Plan 9 from Bell Labs’s /usr/web/sources/contrib/maht/limbo/flickr/Flickr.b

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


implement Flickr;

include "sys.m";
	sys: Sys;

include "draw.m";
	draw : Draw;

include "keyring.m";
	keyring: Keyring;
include "/usr/maht/http_client/http_client.m";
	http_client : Http_client;
	Request, Connection, Response : import http_client;

include "/usr/maht/xmhell/xml.m";
	xml: Xml;
	Parser, Item, Attributes, Mark: import xml;

include "/usr/maht/mime/mime.m";
	mime : Mime;
	Document, Disposition : import mime;

include "bufio.m";
	bufio : Bufio;
	Iobuf : import bufio;

include "Flickr.m";

debug(b : array of byte) 
{
	t := array of byte sys->sprint("%s\n", string b);
	sys->write(sys->fildes(2), t, len(t));
}

query_string(a: ref Auth, method: string, parameters : list of ref Parameter) : string
{
	p : ref Parameter;
	query_string := "";
	if(a != nil) {
		if (a.token != "")
			query_string += "auth_token=" + a.token + "&";
		query_string += "api_key=" + a.apikey + "&";
	}
	query_string += "method=flickr." + method;
	for(ps:=parameters; ps != nil; ps =  tl ps) {
		p = hd ps;
		query_string += "&" + http_client->urlencode(p.name) + "=" + http_client->urlencode(p.value) ;
	}
	return query_string;
}

sign_parameters(a: ref Auth, method : string, parameters : list of ref Parameter) : string
{
	keyring = load Keyring Keyring->PATH;
	sys = load Sys Sys->PATH;
	digest := array[16] of byte;
	p : ref Parameter;
	unhashed := a.secret;
	if (a != nil) {
		unhashed += "api_key" + a.apikey;
		if(a.token != "")
			 unhashed += "auth_token" + a.token;
	}
	if(method != "")
		unhashed += "methodflickr." + method;
	for(ps:=parameters; ps != nil; ps =  tl ps) {
		p = hd ps;
		unhashed += p.name + p.value;
	}
	sys->print("unhashed: %s\n", unhashed);
	keyring->md5(array of byte unhashed, len array of byte unhashed, digest, nil);
	digest_text := "";
	for(i:=0; i<16; i++) {
		digest_text += sys->sprint("%02x", int(digest[i]));
	}
	return digest_text;
}

send_request(a: ref Auth, method : string, parameters : list of ref Parameter)  : ref Response
{
	http_client = load Http_client Http_client->PATH;
	sys = load Sys Sys->PATH;
	bufio = load Bufio Bufio->PATH;

	c := http_client->new_connection("tcp!" + IP + "!80");
	b := bufio->fopen(c.c.dfd, Bufio->OWRITE);
	bb := bufio->fopen(sys->fildes(1), Bufio->OWRITE);
	body := array of byte (query_string(a, method, parameters) + "&api_sig=" + sign_parameters(a, method, parameters));
	http_client->POST(b, Host, RESTForm, "1.1", "Content-Type: application/x-www-form-urlencoded" :: nil, body);
	http_client->POST(bb, Host, RESTForm, "1.1", "Content-Type: application/x-www-form-urlencoded" :: nil, body);
	b.flush();
	bb.flush();
	return c.read_response();
}

read_rsp_node(response : ref Response) : string
{
	if(response == nil)
		return "";
	xml = load Xml Xml->PATH;
	xml->init();
	x := xml->init_io(string response.body, nil, "");
	for(n := x.next(); n != nil; n = x.next()) {
		pick e := n {
		Tag =>
			case e.name {
			"rsp" =>
				if(e.attrs.get("stat") == "ok")
					x.down();
				break;
			* =>
				x.down();
				f := x.next();
				pick g := f {
				Text =>
					return g.ch;
				}
			}
		}
	}
	return "";
}

Auth.get_frob(a : self ref Auth) : string
{
	response := send_request(a, "auth.getFrob", nil);
	if(response == nil)
		return "";
	return read_rsp_node(response);
}

Auth.get_token(a: self ref Auth) : string
{
	params := ref Parameter("frob", a.get_frob()) :: nil;
	response := send_request(a, "auth.getToken", params);
	return "";
}

Auth.check_token(a: self ref Auth) : int
{
	response := send_request(a, "auth.checkToken", nil);
#	sys->print("%s", response.to_string());
	return 1;
}

Photo.to_string(p : self ref Photo) : string
{
	return sys->sprint("Photo id=%s\n\towner: %s\n\tsecret: %s\n\tserver: %s\n\tfarm: %s\n\ttitle: %s\n\tispublic: %d\n\tisfriend: %d\n\tisfamily: %d\n", p.id, p.owner, p.secret, p.server, p.farm, p.title, p.ispublic, p.isfriend, p.isfamily);
}

response_to_photopage(response : ref Response) : ref Photopage
{
	if(response == nil) return nil;
	photopage := ref Photopage;
	p : ref Photo;
	xml = load Xml Xml->PATH;
	xml->init();
	x := xml->init_io(string response.body, nil, "");
	for(n := x.next(); n != nil; n = x.next()) {
		pick e := n {
		Tag =>
			case e.name {
			"rsp" =>
				if(e.attrs.get("stat") == "ok")
					x.down();
				break;
			"photos" =>
				photopage.page = int e.attrs.get("page");
				photopage.pages = int e.attrs.get("pages");
				photopage.perpage = int e.attrs.get("perpage");
				photopage.total = int e.attrs.get("total");
				x.down();
			"photo" =>
				p = ref Photo;
				p.id = e.attrs.get("id");
				p.owner = e.attrs.get("owner");
				p.secret = e.attrs.get("secret");
				p.server = e.attrs.get("server");
				p.farm = e.attrs.get("farm");
				p.title = e.attrs.get("title");
				p.ispublic = int e.attrs.get("ispublic");
				p.isfriend = int e.attrs.get("isfriend");
				p.isfamily = int e.attrs.get("isfamily");
				photopage.photos = p :: photopage.photos;
			}
		}
	}
	return photopage;
}


get_favourites(a : ref Auth, per_page, page_no : int) : ref Photopage
{
	params :=  ref Parameter("page", sys->sprint("%d", page_no)) ::ref Parameter("per_page", sys->sprint("%d", per_page)) :: nil;
	return response_to_photopage(send_request(a, "favorites.getList", params));
}

upload_jpeg(a: ref Auth, jpeg : array of byte) : string
{
	mime = load Mime Mime->PATH;
	d := mime->new_document();
	d.add_part(ref Disposition("form-data", ref mime->Keyval("name", "photo") :: ref mime->Keyval("filename", "hail_glenda.jpeg") :: nil), "image/jpeg", jpeg);
	sig := sign_parameters(a, "", nil); 
#	d.add_part(ref Disposition("form-data", ref mime->Keyval("name", "is_public") :: nil), "", array of byte "1");
#	d.add_part(ref Disposition("form-data", ref mime->Keyval("name", "tags") :: nil), "", array of byte "tag1 tag2 tag3");
#	d.add_part(ref Disposition("form-data", ref mime->Keyval("name", "description") :: nil), "", array of byte "This is the description");
#	d.add_part(ref Disposition("form-data", ref mime->Keyval("name", "title") :: nil), "", array of byte "This is the title");
	d.add_part(ref Disposition("form-data", ref mime->Keyval("name", "api_sig") :: nil), "", array of byte sig);
	d.add_part(ref Disposition("form-data", ref mime->Keyval("name", "auth_token") :: nil), "", array of byte a.token);
	d.add_part(ref Disposition("form-data", ref mime->Keyval("name", "api_key") :: nil), "", array of byte a.apikey);

	http_client = load Http_client Http_client->PATH;
	sys = load Sys Sys->PATH;

	c := http_client->new_connection("tcp!" + IP + "!80");
	b := bufio->fopen(c.c.dfd, Bufio->OWRITE);
	http_client->POST(b, Host, UploadForm, "1.1", "Content-type: multipart/form-data; boundary=" +  d.boundary :: "Accept-Encoding: identity" :: nil, d.bytes());
	b.flush();
	return read_rsp_node(c.read_response());
}

Category.to_string(c : self ref Category) : string
{
	return sys->sprint("C:%s\n\tid: %d\n\tp:%d\n\tc: %d", c.name, c.id, c.parent, c.count);
}

Group.to_string(g : self ref Group) : string
{
	
	return sys->sprint("G:%s\n\tnsid: %s\n\tmembers: %d", http_client->urlencode(g.name), g.nsid, g.members);
}

groups_browse(a: ref Auth, category_id : int) : (list of ref Category, list of ref Group)
{
	params := ref Parameter("cat_id", sys->sprint("%d", category_id)) :: nil;
	response := send_request(a, "groups.browse", params);
	if(response == nil)
		return (nil, nil);
	categories : list of ref Category;
	groups : list of ref Group;
	g := ref Group;
	c : ref Category;
	xml = load Xml Xml->PATH;
	xml->init();
	p := xml->init_io(string response.body, nil, "");
	for(i := p.next(); i != nil; i = p.next()) {
		pick e := i {
		Tag =>
			case e.name {
			"rsp" =>
				if(e.attrs.get("stat") == "ok")
					p.down();
				break;
			"category" =>
				p.down();
			"subcat" =>
				c = ref Category;
				c.id = int e.attrs.get("id");
				c.parent = int category_id;
				c.name = e.attrs.get("name");
				c.count = int e.attrs.get("count");
				categories = c :: categories;
			"group" =>
				g = ref Group;
				g.nsid =e.attrs.get("nsid");
				g.name = e.attrs.get("name");
				g.members = int e.attrs.get("members");
				groups = g :: groups;
			}
		}
	}
	return (categories, groups);
}

my_recently_posted_photos(a: ref Auth, per_page, page_no : int) : ref Photopage
{
	params :=  ref Parameter("page", sys->sprint("%d", page_no)) ::ref Parameter("per_page", sys->sprint("%d", per_page)) :: ref Parameter("user_id", "me") :: nil;;
	return response_to_photopage(send_request(a, "photos.search", params));
}

Photopage.to_string(photopage: self ref Photopage) : string
{
	page := sys->sprint("Page %d of %d x%d = %d\n", photopage.page, photopage.pages, photopage.perpage, photopage.total);
	p : ref Photo;
	for(ps := photopage.photos; ps != nil; ps = tl ps) {
		p = hd ps;
		page += "\t" + p.to_string() + "\n";
	}
	return page;
}

#	Put Limbo Flickr

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].