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
|