Index: blog_poster.py
===================================================================
RCS file: /home/tenco/.cvs_repo/gnomeblog/blog_poster.py,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- blog_poster.py	17 Jul 2006 19:56:10 -0000	1.1.1.1
+++ blog_poster.py	5 Aug 2006 15:18:09 -0000	1.2
@@ -119,8 +119,14 @@
         #the markup to html converter
         if use_gtkspell:
             self._detach_gtkspell()
-
-        html_text = self.blogEntry.getHTML()
+        
+        client = gconf.client_get_default()
+        protocol = client.get_string(gconf_prefix + "/blog_protocol")
+        
+        if protocol == 'BloggerAtomAPI':
+            html_text = self.blogEntry.getXML()
+        else:
+            html_text = self.blogEntry.getHTML()
 
         #turn spelling back on
         if use_gtkspell:
Index: blogger_prefs.py
===================================================================
RCS file: /home/tenco/.cvs_repo/gnomeblog/blogger_prefs.py,v
retrieving revision 1.1.1.1
retrieving revision 1.5
diff -u -r1.1.1.1 -r1.5
--- blogger_prefs.py	17 Jul 2006 19:56:10 -0000	1.1.1.1
+++ blogger_prefs.py	5 Aug 2006 15:18:09 -0000	1.5
@@ -33,6 +33,7 @@
         blogTypeMenu = gconf_widgets.OptionMenu(gconf_prefix + "/blog_type")
         blogTypeMenu.setStringValuePairs([("blogs.gnome.org", "blogs.gnome.org"),
                                           ("Blogger.com", "blogger.com"),
+                                          ("Blogger.com AtomAPI", "bloggeratom"),
                                           ("Advogato", "advogato.org"),
                                           ("LiveJournal", "livejournal.com"),
                                           ("-", ""),
@@ -50,6 +51,7 @@
 
         self.blogProtocolMenu = gconf_widgets.OptionMenu(gconf_prefix + "/blog_protocol")
         self.blogProtocolMenu.setStringValuePairs([("BloggerAPI", "bloggerAPI"),
+                                                   ("Blogger.com AtomAPI", "BloggerAtomAPI"),
                                                    ("Advogato", "advogato"),
                                                    ("LiveJournal", "livejournal"),
                                                    ("MetaWeblog", "MetaWeblog")])
@@ -140,6 +142,11 @@
             url_ending = ""
             protocol = "bloggerAPI"
             url_description = _("XML-RPC URL:")
+        elif blog_type == "bloggeratom":
+            url = "https://www.blogger.com"
+            url_ending = ""
+            protocol = "BloggerAtomAPI"
+            url_description = _("Base Blog URL:")
         elif blog_type == "advogato.org":
             url = "http://www.advogato.org/XMLRPC"
             url_ending = ""
Index: html_converter.py
===================================================================
RCS file: /home/tenco/.cvs_repo/gnomeblog/html_converter.py,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- html_converter.py	17 Jul 2006 19:56:11 -0000	1.1.1.1
+++ html_converter.py	5 Aug 2006 15:18:09 -0000	1.2
@@ -1,4 +1,5 @@
 import gtk
+import xml.dom
 
 def getHTML(buffer):
     global para_tag
@@ -16,8 +17,28 @@
         html = html + new_text + _getTagsHTML(next_iter, open_tags)
 
     return html.decode('utf8')
+    
+def getXML(buffer):
+    global para_tag
+    impl = xml.dom.getDOMImplementation()
+    doc = impl.createDocument(None, None, None)
+    
+    next_iter = buffer.get_start_iter()
+
+    open_tags = [ para_tag ]
+    html = "<p>" + _getTagsHTML(next_iter, open_tags)
+
+    while not next_iter.is_end():
+        iter = next_iter
+        next_iter = _getNextIter(iter)
+
+        new_text = buffer.get_text(iter, next_iter, True)
+        node = doc.createTextNode(new_text.decode('utf-8'))
+        html = html + node.toxml('utf-8') + _getTagsHTML(next_iter, open_tags)
+        
+    doc.unlink()
+    return html.decode('utf8')
 
-  
 def _getNextIter(iter):
     nextTagIter  = iter.copy()
     endLineIter  = iter.copy()
@@ -82,4 +103,3 @@
         html = html + _turnOnTags(tags_to_reopen, open_tags)
 
     return html
-
Index: rich_entry.py
===================================================================
RCS file: /home/tenco/.cvs_repo/gnomeblog/rich_entry.py,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- rich_entry.py	17 Jul 2006 19:56:11 -0000	1.1.1.1
+++ rich_entry.py	5 Aug 2006 15:18:09 -0000	1.2
@@ -102,6 +102,9 @@
         
     def getHTML(self):
         return html_converter.getHTML(self.buffer)
+        
+    def getXML(self):
+        return html_converter.getXML(self.buffer)
 
     def clear(self):
         self.buffer.delete(self.buffer.get_start_iter(),
Index: protocols/BloggerAtomAPI.py
===================================================================
RCS file: protocols/BloggerAtomAPI.py
diff -N protocols/BloggerAtomAPI.py
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ protocols/BloggerAtomAPI.py	5 Aug 2006 16:21:52 -0000	1.7
@@ -0,0 +1,190 @@
+# -*- coding: utf8 -*-
+from os.path import basename
+from time import strftime
+import StringIO
+
+from xml.dom import minidom
+# Neither httplib nor urllib2 support either Proxy Transport for HTTPS or
+# HTTP request types DELETE and PUT, so we use python bindings for libcurl
+import pycurl
+
+import gettext
+_ = gettext.gettext
+
+import gconf
+from gnomeblog import hig_alert
+
+class Blog:
+    def __init__ (self):
+        base_key = "/system/proxy"
+        self.host_key = base_key + "/secure_host"
+        self.port_key = base_key + "/secure_port"
+        self.proxyHost = "" 
+        self.proxyPort = 0
+        self.use_proxy = False
+
+    def _sendHTTPSRequest (self, url, RequestType, username, password,
+                            blogid=None, atom_content=None, postid=None):
+
+        if RequestType not in ['listblogs', 'listrecent', 'getpost', 'createpost', 'editpost', 'deletepost']:
+            raise ValueError, 'RequestType "%s" not supported' % RequestType
+
+        answer = StringIO.StringIO()
+
+        con = pycurl.Curl()
+        con.setopt(con.USERPWD, ':'.join([username, password]))
+        con.setopt(con.WRITEFUNCTION, answer.write)
+        con.setopt(con.HTTPAUTH, 1)
+        # Verifying of SSL-certificates by the user not supported yet.
+        con.setopt(con.SSL_VERIFYPEER, 0)
+        con.setopt(con.SSL_VERIFYHOST, 0)
+
+        # Proxy support. Untested!
+        if self.use_proxy == True:
+            con.setopt(con.PROXY, self.proxyHost)
+            con.setopt(con.PROXYPORT, self.proxyPort)
+            con.setopt(con.HTTPPROXYTUNNEL, 1)
+
+        # Useful for debugging...
+        #con.setopt(con.VERBOSE, 1)
+
+        if RequestType == 'listblogs':
+            con.setopt(con.URL, '/'.join([url, 'atom']))
+
+        if RequestType == 'createpost':
+            if (blogid == None) or (atom_content == None):
+                raise ValueError, 'For RequestType "createpost", "blogid" and "atom_content" must not be set to "None"'
+            con.setopt(con.POST, 1)
+            con.setopt(con.HTTPHEADER, ['Content-type: application/xml'])
+            con.setopt(con.POSTFIELDS, atom_content)
+            con.setopt(con.URL, '/'.join([url, 'atom', blogid]))
+
+        # This types of request have never been tested, so don't assume that they will work.
+        # Neither are they required for the current BloggerAtomAPI. Broad hint: if you want
+        # to integrate them into gnome-blog, go on with it. ;-)
+        if RequestType == 'listrecent':
+            if (blogid == None):
+                raise ValueError, 'For RequestType "listrecent", "blogid" must not be "None"'
+            con.setopt(con.URL, '/'.join([url, 'atom', blogid]))
+            
+        if RequestType == 'getpost':
+            if (blogid == None) or (postid == None):
+                raise ValueError, 'For RequestType "getpost", "blogid" and "postid" must not be set to "None"'
+            con.setopt(con.URL, '/'.join([url, 'atom', blogid, postid]))
+            
+        if RequestType == 'editpost':
+            if (blogid == None) or (postid == None) or (atom_content == None):
+                raise ValueError, 'For RequestType "editpost", "blogid", "postid" and "atom_content" must not be set to "None"'
+            content = StringIO.StringIO(atom_content)
+            con.setopt(con.READFUNCTION, content.getvalue())
+            con.setopt(con.UPLOAD, 1)
+            con.setopt(con.HTTPHEADER, ['Content-type: application/xml', 'Transfer-Encoding: chunked'])
+            con.setopt(con.URL, '/'.join([url, 'atom', blogid, postid]))
+            
+        if RequestType == 'deletepost':
+            if (blogid == None) or (postid == None):
+                raise ValueError, 'For RequestType "deletepost", "blogid" and "postid" must not be set to "None"'
+            con.setopt(con.CUSTOMREQUEST, 'DELETE')
+            con.setopt(con.URL, '/'.join([url, 'atom', blogid, postid]))
+
+        try:
+            con.perform() != 0
+        except:
+            hig_alert.reportError('Connection failed', 'Gnome-Blog failed to connect to the remote server.')
+        
+        con.close()
+        if RequestType == 'editpost':
+            content.close()
+        return answer.getvalue()
+
+    def _getProxySettings (self, client):
+        self.proxyHost = client.get_string(self.host_key) 
+        self.proxyPort = client.get_int(self.port_key)
+        if (self.proxyHost != "") and (self.proxyPort != 0):
+            return True
+        else:
+            return False
+
+    def _insertTextNode (self, document, tagname, text):
+        list = document.getElementsByTagName(tagname)
+        element = list.item(0)
+        
+        if tagname == 'div':
+            entry = '<root>%s</root>' % text
+            div = minidom.parseString(entry)
+            for i in range(div.firstChild.childNodes.length):
+                element.appendChild(div.firstChild.childNodes.item(0))
+        else:
+            textNode = document.createTextNode(text)
+            element.appendChild(textNode)
+        
+    def getBlogList (self, username, password, url, client, gconf_prefix):
+    
+#        url = client.get_string(gconf_prefix + '/xmlrpc_url')
+        
+        if self._getProxySettings(client):
+            self.use_proxy = True
+        
+        response = self._sendHTTPSRequest(url, 'listblogs', username, password)
+
+        try:
+            tree = minidom.parseString(response)
+        except:
+            hig_alert.reportError('Unexpected Response', 'The server responded in an unexpected manner.')
+            return
+        
+        links = tree.documentElement.getElementsByTagName('link')
+        string_value_pairs = []
+
+        for l in links:
+            if l.getAttribute('rel') == 'service.post':
+                string_value_pairs.append((l.getAttribute("title"), basename(l.getAttribute("href"))))
+
+        tree.unlink()
+        return string_value_pairs
+
+    def postEntry (self, username, password, base_url, title, entry, client, gconf_prefix):
+        
+        blog_id  = client.get_string(gconf_prefix + "/blog_id")
+        url = client.get_string(gconf_prefix + '/xmlrpc_url')
+
+        if self._getProxySettings(client):
+            self.use_proxy = True
+
+        doc = minidom.parseString('<entry xmlns="http://purl.org/atom/ns#">'
+            + '<title mode="escaped" type="text/plain"></title>'
+            + '<issued></issued>'
+            + '<generator url="http://www.gnome.org/~seth/gnome-blog/">Gnome-Blog</generator>'
+            + '<content type="application/xhtml+xml">'
+            + '<div xmlns="http://www.w3.org/1999/xhtml"></div>'
+            + '</content>'
+            + '</entry>')
+
+        self._insertTextNode(doc, 'title', title)
+        self._insertTextNode(doc, 'issued', strftime("%Y-%m-%dT%H:%M:%SZ"))
+        self._insertTextNode(doc, 'div', entry)
+
+        if (blog_id == None):
+            blog_id = ""
+
+        if (username == None):
+            username = ""
+
+        if (password == None):
+            password = ""
+
+        precontent = doc.toxml('utf-8')
+        content = precontent.replace('?>', ' standalone="yes"?>', 1)
+        doc.unlink()
+        resp = self._sendHTTPSRequest(url, 'createpost', username, password, blog_id, content)
+        
+        # Check if entry could be posted
+        try:
+            err_check = minidom.parseString(resp)
+        except:
+            hig_alert.reportError('Could not post', 'Document could not be posted.')
+            return False
+            
+        return True
+
+blog = Blog()
Index: protocols/Makefile.am
===================================================================
RCS file: /home/tenco/.cvs_repo/gnomeblog/protocols/Makefile.am,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- protocols/Makefile.am	17 Jul 2006 19:56:11 -0000	1.1.1.1
+++ protocols/Makefile.am	21 Jul 2006 16:20:15 -0000	1.2
@@ -5,6 +5,7 @@
 gnomeblog_PYTHON = 		\
 	bloggerAPI.py		\
 	MetaWeblog.py		\
-	advogato.py		\
+	advogato.py	    	\
 	livejournal.py		\
+    BloggerAtomAPI.py   \
 	$(NULL)
