implement Blogger; include "sys.m"; sys : Sys; include "draw.m"; Context: import Draw; include "string.m"; str : String; include "factotum.m"; auth : Factotum; include "arg.m"; arg : Arg; include "xmhell.m"; xml : Xml; Parser, Item, Attributes : import xml; include "sslsession.m"; include "keyring.m"; include "asn1.m"; include "pkcs.m"; include "x509.m"; include "ssl3.m"; ssl3: SSL3; include "httpc.m"; httpc : Httpc; Request, Response, Connection : import httpc; include "Blogger.m"; googleaddr : con "tcp!64.233.183.104!443"; bloggeraddr : con "tcp!72.14.207.191!80"; log_in(email, password : string) : ref User { if(email =="" || password =="") raise "username or password blank"; c := httpc->new_ssl_connection(googleaddr); if(c == nil) raise "Connection (SSL) to " + googleaddr + " failed"; data := "Email=" + httpc->urlencode(email) + "&Passwd=" + httpc->urlencode(password) + "&source=GroundZero-BloggerModule-1&service=blogger"; r := c.send_request(ref Request("www.google.com", "POST", "/accounts/ClientLogin", "1.1", "Inferno: Maht's Blogger Module", "Content-Type: application/x-www-form-urlencoded" :: nil, array of byte data)); (nil, bits) := sys->tokenize(r.body_string(), "\n"); while(bits != nil) { (i,b) := sys->tokenize(hd bits, "="); if(i > 0) if(hd b == "Auth") return ref User(hd tl b, nil); bits = tl bits; } return nil; } mime(mimetype, body : string) : ref Mime { case(mimetype) { "text/plain" or "text" or "" => return ref Mime.text(body); "text/html" => return ref Mime.html(body); "text/xhtml" => return ref Mime.xhtml(body); "image/png" => return ref Mime.png(body); } return nil; } extract_blog(psr : ref Parser) : ref Blog { blog : ref Blog; i := psr.next(); tag, mtype : string; while(i != nil) { pick k := i { Tag => tag = k.name; case(tag) { "id" => blog = ref Blog; psr.down(); "published" => psr.down(); "updated" => psr.down(); "category" => blog.tags = k.attrs.get("term") :: blog.tags; "title" => mtype = k.attrs.get("type"); psr.down(); "summary" => mtype = k.attrs.get("type"); psr.down(); } Text => case(tag) { "id" => (nbits, bits) := sys->tokenize(k.ch, "-"); if(nbits == 3) blog.id = hd tl tl bits; "title" => blog.title = mime(mtype, k.ch); "published" => blog.published = k.ch; "updated" => blog.updated = k.ch; "summary" => blog.summary = mime("", k.ch); } psr.up(); } i = psr.next(); } return blog; } extract_blog_list(r : ref Response) : list of ref Blog { blogs : list of ref Blog; blogs = nil; psr := xml->init_io(r.body_string(), nil, ""); i := psr.next(); while(i != nil) { pick k := i { Tag => case(k.name) { "feed" => psr.down(); "entry" => psr.down(); blogs = extract_blog(psr) :: blogs; psr.up(); } } i = psr.next(); } return blogs; } User.fill_blog_list(u : self ref User) { c := httpc->new_connection(bloggeraddr); if(c == nil) raise "Connection to " + bloggeraddr + " failed"; r := c.send_request(ref Request("www.blogger.com", "GET", "/feeds/default/blogs", "1.1", "Inferno: Maht's Blogger Module", "Authorization: GoogleLogin auth=" + u.authtoken :: nil, nil)); if(r != nil) u.blogs = extract_blog_list(r); } User.blog_by_id(u : self ref User, id : string) : ref Blog { b := u.blogs; while(b != nil) { if((hd b).id == id) return hd b; b = tl b; } return nil; } User.blog_by_name(u : self ref User, name : string) : ref Blog { b := u.blogs; while(b != nil) { pick bb := (hd b).title { text or html or xhtml => if(bb.data == name) return hd b; } b = tl b; } return nil; } Blog.new_post(b : self ref Blog, u : ref User, e : ref Entry, draft : int) : string { c := httpc->new_connection(bloggeraddr); if(c == nil) raise "Connection to " + bloggeraddr + " failed"; hdrs := "Authorization: GoogleLogin auth=" + u.authtoken :: "Content-Type: application/atom+xml" :: nil; if(e.slug != ""); hdrs = "Slug: " + e.slug :: hdrs; r := c.send_request(ref Request("www.blogger.com", "POST", "/feeds/" + b.id + "/posts/default", "1.1", "Inferno: Maht's Blogger Module", hdrs, array of byte e.xml(draft))); # temporary if(r != nil) return r.to_string(); return ""; } Mime.xml(mp : self ref Mime, tag : string) : string { pick m := mp { png => return "<" + tag + " src='" + m.src + "' />"; html=> return "<" + tag + " type='html'>" + m.data + ""; xhtml=> return "<" + tag + " type='xhtml'>" + m.data + ""; text=> return "<" + tag + ">" + m.data + ""; } return ""; } Mime.plain(mp : self ref Mime) : string { pick m := mp { png => return m.src; html or xhtml or text => return m.data; } return ""; } Entry.xml(e : self ref Entry, draft : int) : string { x := ""; if(e.title != nil) x += e.title.xml("title"); if(draft) x += "yes"; if(e.summary != nil) x += e.summary.xml("summary"); if(e.content != nil) x += e.content.xml("content"); if(e.author_name != "" || e.author_email != "") { x += ""; if(e.author_name != "") x += "" + e.author_name + ""; if(e.author_email != "") x += "" + e.author_email + ""; x += ""; } if(e.updated != "") x += "" + e.updated + ""; if(e.id != "") x += "" + e.id + ""; if(e.tags != nil) { tags := e.tags; while(hd tags != nil) { x += ""; tags = tl tags; } } x += ""; return x; } User.list_blogs(u : self ref User) { numblogs : int; b := u.blogs; for(numblogs = 0; b != nil; b = tl b) { sys->print("blog: %s, %s\n", (hd b).id, (hd b).title.plain()); numblogs++; } if(numblogs == 0) sys->print("No blogs\n"); } User.new_post(u : self ref User, subject, blogid : string, draft : int) : string { blog := u.blog_by_id(blogid); if(blog == nil) raise "Blog ID not found"; e := ref Entry; e.title = ref Mime.text(subject); data := array[1024] of byte; stdin := sys->fildes(0); read := sys->read(stdin, data, len data); content := ""; while(read > 0) { content += string data[0:read]; read = sys->read(stdin, data, len data); } e.content = ref Mime.text(content); return blog.new_post(u, e, draft); } init(nil: ref Context, args: list of string) { sys = load Sys Sys->PATH; str = load String String->PATH; xml = load Xml Xml->PATH; xml->init(); arg = load Arg Arg->PATH; arg->init(args); arg->setusage("Blogger: [-l] [-n blogid -s subject -d]"); auth = load Factotum Factotum->PATH; auth->init(); httpc = load Httpc Httpc->PATH; user := pass := action := blogid := subject := ""; draft := 0; while((c := arg->opt()) != 0) case c { 'u' => user = arg->arg(); 'p' => pass = arg->arg(); 'l' => action = "list"; 'n' => action = "new"; blogid = arg->arg(); 's' => subject = arg->arg(); 'd' => draft = 1; } case user { "" => (user, pass) = auth->getuserpasswd("proto=pass dom=www.google.com"); * => if(pass != "") (user, pass) = auth->getuserpasswd("proto=pass dom=www.google.com user=" + user); } { u := log_in(user, pass); u.fill_blog_list(); case action { "list" => u.list_blogs(); "new" => if(subject != "") sys->print("%s", u.new_post(subject, blogid, draft)); else raise "Subject required"; } } exception e { "*" => sys->fprint(sys->fildes(2), "%s\n", e); } }