dzach 2008-6-25: How can one post a message to a google Blogger blog programmatically using TCL?
Given the popularity of Google's Blogger platform, it might be a good idea to provide some basic functionality here. Google's Account Authentication API documentation can be found at:
http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html#ClientLogin
and a guide for the API here:
http://code.google.com/apis/blogger/developers_guide_protocol.html#CreatingPublicEntries
Here is the code I've tried so far (corrected with the help of Pat Thoyts in the Tcler's Chat):
namespace eval ::gpost {
proc login {} {
# packages http and tls are needed
if {[catch {
package require tls
package req http
} err]
} {
return $err
}
variable var
variable login
array set var {
loginurl https://www.google.com/accounts/ClientLogin
posturl http://www.blogger.com/feeds/<your-blog's-id>/posts/default
timer_http 30000
}
array unset login
array set login {
accountType GOOGLE
Email <your_google_account_email>
Passwd <your_google_account_password>
service blogger
source <your_company-service-version>
}
::http::register https 443 ::tls::socket
set query [eval ::http::formatQuery [array get login]]
# by specifying the -query option http::geturl sends a POST instead of a GET request, with a Content-type: application/x-www-form-urlencoded header
# sent the POST request
set token [::http::geturl $var(loginurl) -timeout $var(timer_http) -query $query]
# to see what the reply was, uncomment the next line
#parray $token
upvar $token state
# store login ids for later use
foreach line [split [http::data $token] \n] { array set login [split $line =] }
set login(httpcode) [lindex $state(http) 1]
::http::cleanup $token
return $login(httpcode)
}
proc post args {
# prepare ATOM XML
variable var
variable login
array set data $args
if {![info exists data(-body)] || $data(-body) eq ""} {
return [set login(httpcode) 500]
}
append atom "<entry xmlns='http://www.w3.org/2005/Atom' xmlns:app='http://purl.org/atom/app#'>"
if {[info exists data(-title)] && ($data(-title) ne "")} {
append atom "<title type='text'>$data(-title)</title>"
}
append atom "<content type='xhtml'>"
append atom $data(-body)
append atom "</content>"
if {[info exists data(-pubtime)] && ($data(-pubtime) ne "")} {
append atom "<published>$var(-pubtime)</published>"
}
if {[info exists data(-categories)] && ($data(-categories) ne "")} {
foreach cat $data(-categories) {
append atom "<category scheme='http://www.blogger.com/atom/ns#' term='" $cat "' />"
}
}
if {![info exists data(-draft)] || $data(-draft)} {
append atom "<app:control><app:draft>yes</app:draft></app:control>"
}
if {[info exists data(-author)] && ($data(-author) ne "")} {
append atom "<author><name>$data(author)</name>"
if {[info exists data(-email)] && ($data(-email) ne "")} {
append atom "<email>$data(-email)</email> "
}
append atom "</author>"
}
append atom "</entry>"
# the encoding should be utf-8
set atom [encoding convertto utf-8 $atom]
# now that the post is in an ATOM XML structure, send it to google
set token [::http::geturl $var(posturl) -timeout $var(timer_http) -query $atom -type application/atom+xml -headers [list Authorization "GoogleLogin auth=$login(Auth)"]]
# to see what the server reply was, uncomment the next line
#parray $token
# store http return code to be returned
upvar $token state
set login(httpcode) [lindex $state(http) 1]
# free memory used
::http::cleanup $token
return $login(httpcode)
}
}; # end namespace ::gpostA reply like:
HTTP/1.0 200 OK Server: GFE/1.3 Content-Type: text/plain SID=DQAAAGgA...7Zg8CTN LSID=DQAAAGsA...lk8BBbG Auth=DQAAAGgA...dk3fA5N
should be returned by the server upon login, where Auth=DQAAAGgA...dk3fA5N is the Auth (authorization) key to use in all subsequent requests. The key is stored in array value ::gpost::login(Auth), and a code 200 is returned if the login was successful.
For a minimal post, the post command must include a -body option, so to post an article, type for example:
::gpost::login ::gpost::post -body "This is a test"
A code 201 is returned if the post was successful. Don't forget to put your own values for the posturl (<your-blog's-id>), your Email (<your_google_account_email>), your Passwd (<your_google_account_password>) and a source (<your_company-service-version>) parameter for logging purposes, in the login and var arrays.