#!/usr/bin/python # # I, the copyright holder of this file, hereby release it into the # public domain. This applies worldwide. In case this is not legally # possible: I grant anyone the right to use this work for any # purpose, without any conditions, unless such conditions are # required by law. # # 2009-10-18 - Initial version # 2009-10-19 - Read user name and password from ~/.purple/accounts.xml # 2009-10-20 - Never give empty string as first argument to # pynotify.Notification # - Catch exceptions for notifications and show warnings # - Added option show_notifications # - Catch KeyboardInterrupt and skip it # # Bugs: Sloppy error handling # Configure user name and password here, or leave empty to read from # ~/.purple/accounts.xml, where the credentials can be found if you # have Pidgin configured to connect to Jabber (Google Talk) with your # Google account. user_name = "" password = "" # Whether to show notifications with the summary of each unread # conversation. show_notifications = True import pygtk pygtk.require("2.0") import gtk from xml.etree import ElementTree import glib import gobject import pynotify import urllib2 import webbrowser class Conversation: pass def get_feed(): auth_handler = urllib2.HTTPBasicAuthHandler() auth_handler.add_password( "New mail feed", "https://mail.google.com", user_name, password) response = urllib2.build_opener(auth_handler).open( "https://mail.google.com/mail/feed/atom").read() ns = "{http://purl.org/atom/ns#}" root = ElementTree.XML(response) full_count = int(root.findtext(ns + "fullcount")) conversations = [] for entry in root.findall(ns + "entry"): conversation = Conversation() conversation.id = entry.findtext(ns + "id") conversation.link = entry.find(ns + "link").get("href") conversation.title = entry.findtext(ns + "title") conversation.summary = entry.findtext(ns + "summary") conversation.author_name = entry.findtext(ns + "author/" + ns + "name") conversation.author_email = entry.findtext(ns + "author/" + ns + "email") conversations.append(conversation) return full_count, conversations def open_mail(icon): webbrowser.open("https://mail.google.com/mail") icon.set_visible(0) def create_action(link): def open(notification, action): webbrowser.open("https" + link[4:] if link.startswith("http://") else link) return open last_conversation_ids = () notifications = {} def on_timer(): global last_conversation_ids try: full_count, conversations = get_feed() except Exception, e: if show_notifications: try: pynotify.Notification("Failed to get email", str(e)) except glib.GError, e2: warnings.warn("Failed to get email: " + str(e)) warnings.warn("Failed to show notification: " + str(e2)) else: warnings.warn("Failed to get email: " + str(e)) return 1 icon.set_visible(full_count) if not show_notifications: return conversation_ids = set() for conversation in conversations: conversation_ids.add(conversation.id) if conversation.id not in last_conversation_ids: notification = pynotify.Notification( conversation.title or " ", conversation.summary) notification.add_action("default", " ", create_action(conversation.link)) notification.set_timeout(3600000) try: notification.show() except glib.GError, e: warnings.warn("Failed to show notification: " + str(e)) notifications[conversation.id] = notification for id in notifications.keys(): if id not in conversation_ids: notifications[id].close() del notifications[id] last_conversation_ids = conversation_ids return 1 # Get user name and password from ~/.purple/accounts.xml. Returns # (user_name, password) on success. Returns None on failure. def get_purple_credentials(): import os path = os.path.expanduser("~/.purple/accounts.xml") if not os.path.exists(path): return root = ElementTree.XML(open(path).read()) for account in root.findall("account"): if account.findtext("protocol") != "prpl-jabber": continue name = account.findtext("name") index = name.find("@gmail.com") if index > 0: return name[:index], account.findtext("password") def main(): global icon if show_notifications: pynotify.init("Gmail") icon = gtk.status_icon_new_from_file("/usr/share/icons/gnome/22x22/actions/mail-mark-unread.png") icon.connect("activate", open_mail) on_timer() gobject.timeout_add_seconds(60, on_timer) gtk.main() if __name__ == "__main__": if not user_name: user_name, password = get_purple_credentials() if user_name: print "User name:", user_name try: main() except KeyboardInterrupt: pass else: print "User name and password not configured"