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 + "</" + tag + ">";
xhtml=>
return "<" + tag + " type='xhtml'>" + m.data + "</" + tag + ">";
text=>
return "<" + tag + ">" + m.data + "</" + tag + ">";
}
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 := "<entry xmlns='http://www.w3.org/2005/Atom'>";
if(e.title != nil)
x += e.title.xml("title");
if(draft)
x += "<app:control xmlns:app=\"http://purl.org/atom/app#\"><app:draft>yes</app:draft></app:control>";
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 += "<author>";
if(e.author_name != "")
x += "<name>" + e.author_name + "</name>";
if(e.author_email != "")
x += "<email>" + e.author_email + "</email>";
x += "</author>";
}
if(e.updated != "")
x += "<updated>" + e.updated + "</updated>";
if(e.id != "")
x += "<id>" + e.id + "</id>";
if(e.tags != nil) {
tags := e.tags;
while(hd tags != nil) {
x += "";
tags = tl tags;
}
}
x += "</entry>";
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);
}
}
|