Showing posts with label google. Show all posts
Showing posts with label google. Show all posts

Sunday, February 24, 2008

Google Makes Me Stupid

Does anyone else find that sometimes their first response to a problem is to search Google? I just had the good ol' 500 Internal Server Error in an Apache request and immediately I searched Google for assistance. Given that the web server in question was my own, the reasonable person would first check the server error.log, but I'm apparently not that guy. In my defence, it didn't take long for me to remember this, but still, Google was my initial reaction.

A quick check of said log file suggested an .htaccess issue, and now all is well. Perhaps we're (I'm?) becoming too dependant on our search engine overlords...

Sunday, November 12, 2006

Gmail and Top Posting

I know many have bitched about this in the past, so I won't go off on a rant now. I am curious though if Google has addressed this anywhere that I haven't seen. As in, have they so much as acknowledged the complaints at all? Even if there were some FAQ entry somewhere that said something lame like "We at Google have decided that top posting is best practise and have no plans to support bottom posters." that would provide a feeling of closure. Instead, each time the New Features indicator appears I jump all over it hoping that today is the day. It never is.

Admittedly, I do feel like a bit of a knob even complaining or mentioning this at all. It's not that big of a deal to delete the space at the top, trim the replied text, and add my reply to the bottom. Also, I understand that Windows users are the majority and that Google probably doesn't wish to confuse them. But at least acknowledge good form and provide a non-default setting so that the geeks of the world who do give a shit feel loved too.

Am I alone here?

Monday, October 30, 2006

Retrieving Your BloggerBeta Blog ID

Some people are wondering how to programatically get the blogID that the Google Data API page keeps referring to. I'm not sure if this is the best way or not, but I've had success using the following method in Python:

def getBlogID(uri):
    import httplib2, re
    con = httplib2.Http()
    response, content = con.request(uri, 'GET')
    match = re.search('blogID=(\d*)', content)
    if match:
        return match.group(1)
    else:
        print "BlogID retrieval failed."

It's quite simple actually, it takes your blog's URL as a parameter (as in http://whatever.blogspot.com), and sends an empty GET request to it. The response returned contains a string that matches the regular expression blogID=(\d*). That is, the string "blogID=" followed by a bunch of numbers. That bunch of numbers is the blogID. The function shown above extracts that number with a regular expression, and returns it.

Friday, October 13, 2006

Success! Posting to Blogger-beta Using Vim

If you see this, then I've finally (at least partially) figured out how to use the Blogger-beta GData API from Python. And to make posting a little bit quicker/easier for me, I've stuck that Python code into a Vim plugin.

To be honest, I'm not entirely sure what I was doing wrong in my previous attempts. I've changed several things, then changed some back. The resulting code really doesn't look much different to me than it did before, but there are a few very subtle changes. I suspect my ignorance when it comes to HTTP and XML protocols played a large part in my frustrations.

Anyways, here is a working version of the Python code that works for posting a blog entry. You will obviously need to fill in your BLOGID, GMAIL_ADDRESS, and GMAIL_PASSWORD appropriately for it to work for you:

#!/usr/bin/env python

import httplib2, re

account = "GMAIL_ADDRESS"
password = "GMAIL_PASSWORD"
blogid = "BLOGID"

def authenticate(h):
    auth_uri = 'https://www.google.com/accounts/ClientLogin'
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    myrequest = "Email=%s&Passwd=%s&service=blogger&service=TestCompany-TestApp-0.0" % (account, password)
    response, content = h.request(auth_uri, 'POST', body=myrequest, headers=headers)
    if response['status'] == '200':
        return re.search('Auth=(\S*)', content).group(1)
    else:
        return None

entry = """<?xml version="1.0" ?>
    <entry xmlns='http://www.w3.org/2005/Atom'>
      <title type='text'>Test Post</title>
      <content type='xhtml'>
        <div xmlns="http://www.w3.org/1999/xhtml">
        If you are reading this, then it worked!
        </div>
      </content>
      <author>
        <name>TestUser</name>
      </author>
    </entry>
    """

h = httplib2.Http()
uri = 'http://www.blogger.com/feeds/%s/posts/full' % blogid

# Get the Auth token from ClientLogin
auth = authenticate(h)
if auth:
    headers = {'Content-Type': 'application/atom+xml', 'Authorization': 'GoogleLogin auth=%s' % auth.strip()}
    response, content = h.request(uri, 'POST', body=entry, headers=headers)

    # blindly follow redirects
    while response['status'] == '302':
        response, content = h.request(response['location'], 'POST', body=entry, headers=headers)

    if response['status'] == '201':
        print "Entry successfully posted."
    else:
        print "Post failed: %s" % response['status']
else:
    print "Authorization failed."

It's pretty rough, I realize, but I think it's good enough to get anyone started if you are interested. I hope someone will find this useful.

Now to see what other functionality I can perform :).

Oh, I almost forgot. If you want the Vim plugin I'm using you can get it here. To install it, drop it in ~/.vimrc/plugins/. To use it, open vim, type your post's subject on the first line, the post body below that, and type :BlogPost when you are done.

Wednesday, October 11, 2006

A Step Closer to Google Authentication?

Thanks to a comment left by Frank Mantek regarding the issue I was having with my Blogger-beta authentication, I've been able to get a step closer (I think?) to success. Frank was correct in his assumption that I was getting a 302 redirect response from the ClientLogin URL, and that my custom headers weren't being resent to the new URL. The response I got was a dictionary which contained of course the status code of 302, and also a location key with a value of http://beta.blogger.com/feeds/BLOGID/posts/full. Being quite new to all of this HTTP stuff, I can only assume that location is where the redirect was pointing to. I then implemented a test on the return status code, if it is 302, I manually resent the post and custom headers to the new location, and got a new error!

The new error is a 400 Bad Request error, and the content says GoogleLogin auth token is malformed. A search online for that error string revealed a guy with the same problem, but no responses. Since that thread was too old to reply to and revive, I had to start a new and similar thread. Hopefully it'll get some action.

I won't post all of the new code as most of it remains unchanged. I simply modified the getPost() function to take the URL to make the request to. The new stuff looks like this, with the test for redirect included:

h = httplib2.Http()
uri = 'http://www.blogger.com/feeds/BLOGID/posts/full'

cert = authenticate()
if cert:
    response, content = postEntry(cert, uri)
    while response['status'] == '302':
        cert = authenticate()
        response, content = postEntry(cert, response['location'])
    print response, content

Hopefully this is in fact a step closer. I'd love to get this working. Thanks for the comment and the help, Frank! :)

Tuesday, October 10, 2006

Send a Gmail Message from Vim

Using Gmail on my laptop through the web interface can be quite time consuming. I use the Linux version of Firefox, and it's not exactly known around the world for its great speed. Anyways, sometimes I just want to shoot off a quick email, and it would take just as long to load the Gmail compose form as it would to type the email content. For these times I wrote a little vim-python script as follows:

" Make sure the Vim was compiled with +python before loading the script...
if !has("python")
        finish
endif

:command! -nargs=? GMSend :call GMailSend("<args>")

function! GMailSend(args)
python << EOF
import vim
to = vim.eval('a:args')
GSend(to)
EOF
endfunction

python << EOF
########### BEGIN USER CONFIG ##########
account = 'MY_GMAIL_ACCOUNT'
password = 'MY_GMAIL_PASSWORD'
########### END USER CONFIG ###########


def GSend(to):
    """
    Send the current buffer as a Gmail message to a given user.
    """
    import libgmail

    subject = vim.current.buffer[0]
    body = '\n'.join(vim.current.buffer[2:])

    ga = libgmail.GmailAccount(account, password)
    try:
        ga.login()
    except libgmail.GmailLoginFailure:
        print "Login failed. (Wrong username/password?)"

    gmsg = libgmail.GmailComposedMessage(to, subject, body)

    if ga.sendMessage(gmsg):
        print "Message sent `%s` successfully." % subject
    else:
        print "Could not send message."

EOF

It's a really simple script, and it uses Python so it will only work if your Vim was compiled with the +python option. Of course, you'll also need to edit the script to put in your own Gmail user name and password (lines 18 and 19).

Installation

Drop the above script (or download it from here) into your ~/.vim/plugin/ directory. Reload Vim or source the file with :so ~/.vim/gmail.vim.

Usage

It's even easier to use. The first line in the buffer is the email's subject, and the rest is the body. Once the email is composed in this fashion, type :GMSend <dest> where <dest> is the email address that you want to send this message to. If all is well, you'll see a message at the bottom of your Vim window indicating that all is well, and that the message was sent successfully.

Hopefully somebody out there will find this useful. The version I am actually using is a little more complex. I've extended the script to download messages by folder or label and stick the id, subject, and author in an active buffer. From there I can select one of the shown messages and the script will display the body in the same buffer. I've kept the rest to myself as I'm not real thrilled with the UI part, and I'm not sure it will work as expected for everyone. If you are interested, leave a comment. I'm pretty confident that the script posted above (the one that just sends mail) will work as expected. Enjoy!

Sunday, October 08, 2006

Using the Google GData API with Python

I did a very quick search online for examples that I could use to see how to interact with Google's GData API for creating and posting Blogger-beta blog entries. The best I could find was this post to Jon Udell's Infoworld weblog which illustrates making an entry to Google Calendar. Now even though it is a different web application, most of this example code is still relevent as apparently they use the same API.

From this, I tried the following code:

#!/usr/bin/env python

import httplib2

h = httplib2.Http()
h.add_credentials('MY_GMAIL_ACCOUNT', 'MY_GMAIL_PASSWORD')
h.follow_all_redirects = True
uri = 'http://www.blogger.com/feeds/BLOGID/posts/full'

post_xml = """
<?xml version="1.0" ?>
<entry xmlns='http://www.w3.org/2005/Atom'>
  <title type='text'>Test Post from Python</title>
  <content type='xhtml'>
    <div xmlns="http://www.w3.org/1999/xhtml">
      <p>If you can see this, then it worked!</p>
    </div>
  </content>
  <author>
    <name>Dennis</name>
  </author>
</entry>
"""

headers = {'Content-Type': 'application/atom+xml'}
response, content = h.request(uri, 'POST', body=post_xml, headers=headers)
print response, content

With this code, the last print line revealed a Error 401 of Missing auth parameter in GoogleLogin. I assumed that there was a problem with the method of authentication in the httplib2 library. Possibly it was out of date as apparently this API is a bit of a moving target still these days. As a result, I had a look at the Google Account Authentication docs to see if I would have better luck doing the authentication manually. After a bit of fiddling, I ended up with this:

#!/usr/bin/env python

import httplib2
import re

def postEntry(auth):

    entry = """
    <?xml version="1.0" ?>
    <entry xmlns='http://www.w3.org/2005/Atom'>
      <title type='text'>Test Post from Python</title>
      <content type='xhtml'>
        <div xmlns="http://www.w3.org/1999/xhtml">
          <p>If you can see this, then it worked!</p>
        </div>
      </content>
      <author>
        <name>Dennis</name>
      </author>
    </entry>
    """

    headers = {'Content-Type': 'application/atom+xml', 'Authorization': 'GoogleLogin Auth=%s' % auth.strip()}
    response, content = h.request(uri, 'POST', body=entry, headers=headers)
    print response, content

def authenticate():
    auth_uri = 'https://www.google.com/accounts/ClientLogin'
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    myrequest = "Email=MY_GMAIL_ACCOUNT&Passwd=MY_GMAIL_PASSWORD&service=blogger&service=Dcraven-TestApp-0.0"
    response, content = h.request(auth_uri, 'POST', body=myrequest, headers=headers)
    if response['status'] == '200':
        return re.search('Auth=(\S*)', content).group(1)
    else:
        return None

h = httplib2.Http()
h.follow_all_redirects = True
uri = 'http://www.blogger.com/feeds/BLOGID/posts/full'

cert = authenticate()
if cert:
    postEntry(cert)

The result of this was exactly the same thing, although the actual authenticate() function worked fine, so the problem doesn't lie there. The response from the POST call in this method was in fact 200, and I did get an Auth code from the server. Even after manually packing this code into the header as specified by the Google documentation, I still got an Error 401: Missing auth parameter in GoogleLogin returned by the postEntry() function.

I think this code should work, but alas, it does not. If anyone has any ideas why, or can spot an error in the code I'd really appreciate you pointing it out in a comment below. In the meantime I think I'll make posts the old fashioned way until I get the ambition to try again.

NOTE: I suppose I should note that in the above code, the words BLOGID, MY_GMAIL_PASSWORD, and MY_GMAIL_ACCOUNT actually contained the appropriate values when I tried to run the program :)

UPDATE: I just wanted to post this update for anyone landing here from a Google search or something. I ended up having success with this as posted here.