Plan 9 from Bell Labs’s /usr/web/sources/contrib/maht/inferno/appl/lib/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 "httpc.m";
	httpc : Httpc;
	Request, Connection, Response : import httpc;

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

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

include "sslsession.m";
include "asn1.m";
include "pkcs.m";
include "x509.m";
include "ssl3.m";
	ssl3: SSL3;

include "Flickr.m";

init()
{
	sys = load Sys Sys->PATH;
	keyring = load Keyring Keyring->PATH;
	httpc = load Httpc Httpc->PATH;
	httpc->init();
	xml = load Xml Xml->PATH;
	xml->init();
	mime = load Mime Mime->PATH;
}

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 += "&" + httpc->urlencode(p.name) + "=" + httpc->urlencode(p.value) ;
	}
	return query_string;
}

sign_parameters(a: ref Auth, method : string, parameters : list of ref Parameter) : string
{
	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;
	}
	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
{
	return httpc->new_connection("tcp!" + IP + "!80").send_request(ref Request(Host, "POST", RESTForm, "1.1", "Maht Flickr", "Content-Type: application/x-www-form-urlencoded" :: nil, array of byte (query_string(a, method, parameters) + "&api_sig=" + sign_parameters(a, method, parameters))));
}

read_rsp_node(xtxt: string) : string
{
	if(xtxt == nil)
		return "";
	x := xml->init_io(xtxt, 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
{
	r := send_request(a, "auth.getFrob", nil);
	if(r == nil)
		return "";
	return read_rsp_node(r.body_string());
}

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

Auth.check_token(a: self ref Auth)
{
	r := send_request(a, "auth.checkToken", nil);
	if(r == nil) raise "auth.checkToken failed";
sys->print("%s\n", r.to_string());
}

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(r : ref Response) : ref Photopage
{
	if(r == nil) return nil;
	photopage := ref Photopage;
	p : ref Photo;
	x := xml->init_io(r.body_string(), 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, filename, title, description, tags, public : string) : string
{
	(s, dir) := sys->stat(filename);
	if(s != 0) raise "stat failed for: " + filename;

	disp := ref Disposition;
	data := array[int dir.length] of byte; # bye bye memory
	fd := sys->open(filename, Sys->OREAD);
	read := sys->read(fd, data, len data);
	if(len data != read) raise "short read";

	disp.d_type = "form-data";
	disp.attributes = ref mime->Keyval("name", "photo") :: ref mime->Keyval("filename", dir.name) :: nil;
	
	d := mime->new_document();
	d.add_part(disp, "image/jpeg", data);
	disp = nil;

	params : list of ref Parameter;

	if(title != "") {
		d.add_part(ref Disposition("form-data", ref mime->Keyval("name", "title") :: nil), "", array of byte title);
		params = ref Parameter("title", title) :: params;
	}

	if(description != "") {
		d.add_part(ref Disposition("form-data", ref mime->Keyval("name", "description") :: nil), "", array of byte description);
		params = ref Parameter("description", description) :: params;
	}

	if(tags != "") {
		d.add_part(ref Disposition("form-data", ref mime->Keyval("name", "tags") :: nil), "", array of byte tags);
		params = ref Parameter("tags", tags) :: params;
	}

	if(public != "") {
		d.add_part(ref Disposition("form-data", ref mime->Keyval("name", "is_public") :: nil), "", array of byte public);
		params = ref Parameter("is_public", public) :: params;
	}

	sig := sign_parameters(a, "", params);

	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);


	bytes := d.bytes();

	r := httpc->new_connection("tcp!" + IP + "!80").send_request(ref Request(Host, "POST", UploadForm, "1.1", "Maht Flickr", "Content-type: multipart/form-data; boundary=" +  d.boundary :: "Accept-Encoding: identity" :: nil, bytes));

	x :=  read_rsp_node(r.body_string());

	if (x == "") raise "upload failed";

	return x;
}

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", httpc->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;
	r := send_request(a, "groups.browse", params);
	if(r == nil)
		return (nil, nil);
	categories : list of ref Category;
	groups : list of ref Group;
	g := ref Group;
	c : ref Category;
	p := xml->init_io(r.body_string(), 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].