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