Commit 52ff25afc81a282e920641b3069ec3eee99aa3e4

Rebranded from gsentinel to gmail-sentinel (gsentinel is already taken)

Commit diff

Makefile

 
1212make-install-dirs:
1313 mkdir -p $(DESTDIR)$(PREFIX)/bin
1414 mkdir -p $(DESTDIR)$(PREFIX)$(LIBDIR)
15 mkdir -p $(DESTDIR)$(PREFIX)$(LIBDIR)/gsentinel
15 mkdir -p $(DESTDIR)$(PREFIX)$(LIBDIR)/gmail-sentinel
1616 mkdir -p $(DESTDIR)$(PREFIX)/share/
17 mkdir -p $(DESTDIR)$(PREFIX)/share/gsentinel/
18 mkdir -p $(DESTDIR)$(PREFIX)/share/gsentinel/media/
17 mkdir -p $(DESTDIR)$(PREFIX)/share/gmail-sentinel/
18 mkdir -p $(DESTDIR)$(PREFIX)/share/gmail-sentinel/media/
1919 mkdir -p $(DESTDIR)$(PREFIX)/share/locale
2020
2121install: make-install-dirs
22 install -m 644 *.py $(DESTDIR)$(PREFIX)$(LIBDIR)/gsentinel
23 install -m 644 media/* $(DESTDIR)$(PREFIX)/share/gsentinel/media
22 install -m 644 *.py $(DESTDIR)$(PREFIX)$(LIBDIR)/gmail-sentinel
23 install -m 644 media/* $(DESTDIR)$(PREFIX)/share/gmail-sentinel/media
2424
2525 cd $(DESTDIR)$(PREFIX)/bin && \
2626 /bin/echo -e \
2727 "#!/bin/sh\n" \
28 "cd $(PREFIX)/share/gsentinel\n" \
29 "exec python $(PREFIX)$(LIBDIR)/gsentinel/gsentinel.py \"\$$@\"" \
30 > gsentinel && \
31 chmod 755 gsentinel
32 for f in `find po -name gsentinel.mo` ; do \
28 "cd $(PREFIX)/share/gmail-sentinel\n" \
29 "exec python $(PREFIX)$(LIBDIR)/gmail-sentinel/gmail-sentinel.py \"\$$@\"" \
30 > gmail-sentinel && \
31 chmod 755 gmail-sentinel
32 for f in `find po -name gmail-sentinel.mo` ; do \
3333 install -d -m 755 \
3434 `echo $$f | sed "s|^po|$(DESTDIR)$(PREFIX)/share/locale|" | \
3535 xargs dirname` && \
4343 rm -f messages.pot
4444
4545uninstall:
46 rm -rf $(DESTDIR)$(PREFIX)/bin/gsentinel
47 rm -rf $(DESTDIR)$(PREFIX)$(LIBDIR)/gsentinel
48 rm -rf $(DESTDIR)$(PREFIX)/share/gsentinel
49 find $(DESTDIR)$(PREFIX)/share/locale -name gsentinel.mo -exec rm -f {} \;
46 rm -rf $(DESTDIR)$(PREFIX)/bin/gmail-sentinel
47 rm -rf $(DESTDIR)$(PREFIX)$(LIBDIR)/gmail-sentinel
48 rm -rf $(DESTDIR)$(PREFIX)/share/gmail-sentinel
49 find $(DESTDIR)$(PREFIX)/share/locale -name gmail-sentinel.mo -exec rm -f {} \;
toggle raw diff

gmail-sentinel.conf.sample

 
1# MAKE SURE YOU CHANGE AND UNCOMMENT THE BELOW OPTIONS TO SUIT YOUR
2# SYSTEM
3
4
5[gmail]
6# Your GoogleMail username (your email address without @gmail.com)
7username = gmail_username
8
9# Your GoogleMail password
10password = gmail_password
11
12# Check interval defines (in seconds) how often should GoogleMail
13# Sentinel should check for new mail in your inbox
14checkinterval = 60
15
16[media]
17# The path where is located the media (icons).
18path = /path/to/media/
19
20[options]
21# How much time (in seconds) should the popup be displayed
22popuptime = 5
23# Your favorite browser location
24browser = /usr/bin/firefox
toggle raw diff

gmail-sentinel.py

 
1#! /usr/bin/env python
2# -*- coding: iso-8859-1 -*-
3#
4# Copyright (C) 2008 by Rodrigo Lazo
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20"""
21GoogleMail Sentinel.
22
23Yet another GoogleMail Notifier. Checks your GoogleMail's inbox
24periodically for new mail using feeds(atom). This program creates an
25icon in the task bar when running and notifies about new mail through
26popups.
27"""
28
29
30import pygtk
31pygtk.require('2.0')
32import time
33import gtk
34import gobject
35import pynotify
36import locale, gettext
37import sys
38import os
39from os.path import dirname, pardir
40from gettext import gettext as _
41from ConfigParser import ConfigParser
42from gmailatom import GmailAtom
43
44APP_NAME = "Gmail-Sentinel"
45APP_VERSION = "0.1"
46APP_COPYRIGHT = "(C)2008 Rodrigo Lazo.\n" + _("GoogleMail and Gmail are trademarks of Google, Inc.")
47APP_DESCRIPTION = _('GoogleMail Sentinel')
48APP_WEBSITE = 'http://code.google.com/p/gmail-sentinel/'
49
50# Path definition
51SHARE_PATH = os.path.abspath(os.path.join(dirname(__file__), pardir, pardir, 'share'))
52LOCALE_PATH = os.path.join(SHARE_PATH, 'locale')
53
54# L10n initialization
55locale.setlocale(locale.LC_ALL, '')
56gettext.textdomain('gmail-sentinel')
57gettext.bindtextdomain('gmail-sentinel', LOCALE_PATH)
58
59class GmailNotification:
60 """ Notification pop-up. """
61
62 def __init__ (self, data, count, timeout, icon_file):
63 self.data = data
64 body = "<i>%s: </i>%s\n<i>%s: </i>%s\n%s" % (_("From"),
65 self.data['sender'],
66 _("Subject"),
67 self.data['subject'],
68 self.data["snippet"])
69 self.popup = pynotify.Notification(_("You have %d new messages")%count,
70 body)
71 self.popup.set_icon_from_pixbuf(gtk.gdk.pixbuf_new_from_file(icon_file))
72 self.popup.set_timeout(timeout)
73
74 def attach_to_status_icon (self, status_icon):
75 """ Make the popup appear from the WIDGET"""
76 self.popup.attach_to_status_icon(status_icon)
77
78 def show (self):
79 """ Displays the notification"""
80 self.popup.show()
81
82
83class GmailStatusIcon(gtk.StatusIcon):
84 """Status Icon for the system tray."""
85
86 def __init__(self, media_path):
87 gtk.StatusIcon.__init__(self)
88 self.current_icon_path = media_path
89 self.active_icon = os.path.join(self.current_icon_path,
90 'active.png')
91 self.inactive_icon = os.path.join(self.current_icon_path,
92 'inactive.png')
93 self.gmail_icon = os.path.join(self.current_icon_path,
94 'gmail-icon.png')
95 menu = '''
96 <ui>
97 <menubar name="Menubar">
98 <menu action="Menu">
99 <menuitem action="About"/>
100 <menuitem action="Quit"/>
101 </menu>
102 </menubar>
103 </ui>
104 '''
105 actions = [
106 ('Menu', None, _('Menu')),
107 ('About', gtk.STOCK_ABOUT, _('_About...'),
108 None, _('About'), self.on_about),
109 ('Quit', gtk.STOCK_QUIT, _('_Quit'),
110 None,_('Quit'), self.on_quit),
111 ]
112 ag = gtk.ActionGroup('Actions')
113 ag.add_actions(actions)
114 self.manager = gtk.UIManager()
115 self.manager.insert_action_group(ag, 0)
116 self.manager.add_ui_from_string(menu)
117 self.menu = self.manager.get_widget('/Menubar/Menu/About').props.parent
118 self.set_from_file(self.inactive_icon)
119 self.set_visible(True)
120 self.connect('popup-menu', self.on_popup_menu)
121
122 def on_quit(self, *args):
123 """Kills the application. Callback function."""
124 sys.exit()
125
126 def on_popup_menu(self, status, button, timing):
127 """Displays the popup menu."""
128 self.menu.popup(None, None, None, button, timing)
129
130 def on_about(self, data):
131 """Displays the about window"""
132 dialog = gtk.AboutDialog()
133 dialog.set_name(APP_NAME)
134 dialog.set_version(APP_VERSION)
135 dialog.set_copyright(APP_COPYRIGHT)
136 dialog.set_comments(APP_DESCRIPTION)
137 dialog.set_website(APP_WEBSITE)
138 dialog.set_logo(gtk.gdk.pixbuf_new_from_file(self.gmail_icon))
139 dialog.run()
140 dialog.destroy()
141
142 def set_from_file(self, path):
143 """Helper function to handle media path."""
144 if path != self.current_icon_path:
145 self.current_icon_path = path
146 gtk.StatusIcon.set_from_file(self, path)
147
148class Gnotify:
149 """Main class."""
150
151 def __init__ (self):
152 """Initializer. Creates the status icon and opens the
153 connection."""
154 self.config = ConfigParser()
155 self.connection = None
156 self.unread_msg_count = 0
157
158 if not self.load_configuration():
159 print "Configuration file does not exist."
160 sys.exit(1)
161
162 self.status_icon = GmailStatusIcon(self.config.get('media', 'path'))
163 # Make sure the status icon shows up
164 while gtk.events_pending():
165 gtk.main_iteration(True)
166 if self.connect() :
167 self.check_inbox()
168 # The multiplier is to simplify the configuration
169 # file. Converts the miliseconds into seconds
170 interval = int(self.config.get('gmail', 'checkinterval'))*1000
171 self.main_timer = gobject.timeout_add(interval, self.check_inbox)
172
173 def load_configuration (self):
174 """Loads the configuration. If file does not exist returns
175 false, if the configuration file is bad formatted it will die
176 loudly."""
177 filename = os.path.expanduser("~/.gmail-sentinel.conf")
178 if not os.path.exists(filename):
179 return False
180
181 self.config.read([filename])
182 return True
183
184 def connect (self):
185 """Creates a connection. The connection itself do the
186 parsing."""
187 if self.connection is None:
188 try:
189 print "connecting..."
190 self.status_icon.set_tooltip(_("Connecting..."))
191 self.connection = GmailAtom(self.config.get('gmail','username'),
192 self.config.get('gmail','password'))
193 except:
194 print "login failed, will retry"
195 self.status_icon.set_tooltip(_("Connection failed"))
196 return False
197 self.connection.refreshInfo()
198 print "connection successful... continuing"
199 self.status_icon.set_tooltip(_("Connected"))
200 return True
201
202 def check_inbox(self):
203 """Checks for new mail."""
204 # Revisar si esta el pop up y eliminarlo
205 if self.connection is None and self.connect() is False:
206 # Try again latter
207 return True
208 print "----------"
209 print "checking for new mail ("+time.strftime("%Y/%m/%d %H:%M:%S",
210 time.localtime())+")"
211 while gtk.events_pending():
212 gtk.main_iteration( True )
213
214 if not self.has_new_mail():
215 # Check again later
216 self.unread_msg_count > 0 or \
217 self.status_icon.set_from_file(self.status_icon.inactive_icon)
218 return True
219 self.status_icon.set_from_file(self.status_icon.active_icon)
220 count = self.connection.getUnreadMsgCount()
221 last_message = self.get_last_message()
222 print "%s new messages" % count
223 # The multiplier is to simplify the configuration
224 # file. Converts the miliseconds into seconds
225 timeout = int(self.config.get('options', 'popuptime'))*1000
226 popup = GmailNotification(last_message, count, timeout,
227 self.status_icon.active_icon)
228 popup.attach_to_status_icon(self.status_icon)
229 popup.show()
230 return True
231
232 def has_new_mail (self):
233 """Checks if new mail has arrived."""
234 try:
235 # Hackerish?
236 self.connection.refreshInfo()
237 current_msg_count = self.connection.getUnreadMsgCount()
238 new_mail = current_msg_count > 0 and \
239 current_msg_count != self.unread_msg_count
240 self.unread_msg_count = current_msg_count
241 return new_mail
242 except:
243 print "getUnreadMsgCount() failed, will try again soon"
244 self.unread_msg_count = 0
245 return False
246
247 def get_last_message (self):
248 """ Returns the sender, subject and snippet of the last
249 message retrieved."""
250 return {'sender' : self.connection.getMsgAuthorName(0),
251 'subject' : self.connection.getMsgTitle(0),
252 'snippet' : self.connection.getMsgSummary(0)[:40] + "..."}
253
254 def main (self):
255 """ Mailoop"""
256 gtk.main()
257
258if __name__ == "__main__":
259 pynotify.init(APP_NAME)
260 notifier = Gnotify()
261 notifier.main()
toggle raw diff

gsentinel.conf.sample

 
0# MAKE SURE YOU CHANGE AND UNCOMMENT THE BELOW OPTIONS TO SUIT YOUR
1# SYSTEM
2
3
4[gmail]
5# Your GoogleMail username (your email address without @gmail.com)
6username = gmail_username
7
8# Your GoogleMail password
9password = gmail_password
10
11# Check interval defines (in seconds) how often should GoogleMail
12# Sentinel should check for new mail in your inbox
13checkinterval = 60
14
15[media]
16# The path where is located the media (icons).
17path = /path/to/media/
18
19[options]
20# How much time (in seconds) should the popup be displayed
21popuptime = 5
22# Your favorite browser location
23browser = /usr/bin/firefox
toggle raw diff

gsentinel.py

 
0#! /usr/bin/env python
1# -*- coding: iso-8859-1 -*-
2#
3# Copyright (C) 2008 by Rodrigo Lazo
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19"""
20GoogleMail Sentinel.
21
22Yet another GoogleMail Notifier. Checks your GoogleMail's inbox
23periodically for new mail using feeds(atom). This program creates an
24icon in the task bar when running and notifies about new mail through
25popups.
26"""
27
28
29import pygtk
30pygtk.require('2.0')
31import time
32import gtk
33import gobject
34import pynotify
35import locale, gettext
36import sys
37import os
38from os.path import dirname, pardir
39from gettext import gettext as _
40from ConfigParser import ConfigParser
41from gmailatom import GmailAtom
42
43APP_NAME = "GSentinel"
44APP_VERSION = "0.1"
45APP_COPYRIGHT = "(C)2008 Rodrigo Lazo.\n" + _("GoogleMail is a trademark of Google, Inc.")
46APP_DESCRIPTION = _('GoogleMail Sentinel')
47APP_WEBSITE = 'http://rlazo.supersized.org/gnotify.html/'
48
49# Path definition
50SHARE_PATH = os.path.abspath(os.path.join(dirname(__file__), pardir, pardir, 'share'))
51LOCALE_PATH = os.path.join(SHARE_PATH, 'locale')
52
53# L10n initialization
54locale.setlocale(locale.LC_ALL, '')
55gettext.textdomain('gsentinel')
56gettext.bindtextdomain('gsentinel', LOCALE_PATH)
57
58class GmailNotification:
59 """ Notification pop-up. """
60
61 def __init__ (self, data, count, timeout, icon_file):
62 self.data = data
63 body = "<i>%s: </i>%s\n<i>%s: </i>%s\n%s" % (_("From"),
64 self.data['sender'],
65 _("Subject"),
66 self.data['subject'],
67 self.data["snippet"])
68 self.popup = pynotify.Notification(_("You have %d new messages")%count,
69 body)
70 self.popup.set_icon_from_pixbuf(gtk.gdk.pixbuf_new_from_file(icon_file))
71 self.popup.set_timeout(timeout)
72
73 def attach_to_status_icon (self, status_icon):
74 """ Make the popup appear from the WIDGET"""
75 self.popup.attach_to_status_icon(status_icon)
76
77 def show (self):
78 """ Displays the notification"""
79 self.popup.show()
80
81
82class GmailStatusIcon(gtk.StatusIcon):
83 """Status Icon for the system tray."""
84
85 def __init__(self, media_path):
86 gtk.StatusIcon.__init__(self)
87 self.current_icon_path = media_path
88 self.active_icon = os.path.join(self.current_icon_path,
89 'active.png')
90 self.inactive_icon = os.path.join(self.current_icon_path,
91 'inactive.png')
92 self.gmail_icon = os.path.join(self.current_icon_path,
93 'gmail-icon.png')
94 menu = '''
95 <ui>
96 <menubar name="Menubar">
97 <menu action="Menu">
98 <menuitem action="About"/>
99 <menuitem action="Quit"/>
100 </menu>
101 </menubar>
102 </ui>
103 '''
104 actions = [
105 ('Menu', None, _('Menu')),
106 ('About', gtk.STOCK_ABOUT, _('_About...'),
107 None, _('About'), self.on_about),
108 ('Quit', gtk.STOCK_QUIT, _('_Quit'),
109 None,_('Quit'), self.on_quit),
110 ]
111 ag = gtk.ActionGroup('Actions')
112 ag.add_actions(actions)
113 self.manager = gtk.UIManager()
114 self.manager.insert_action_group(ag, 0)
115 self.manager.add_ui_from_string(menu)
116 self.menu = self.manager.get_widget('/Menubar/Menu/About').props.parent
117 self.set_from_file(self.inactive_icon)
118 self.set_visible(True)
119 self.connect('popup-menu', self.on_popup_menu)
120
121 def on_quit(self, *args):
122 """Kills the application. Callback function."""
123 sys.exit()
124
125 def on_popup_menu(self, status, button, timing):
126 """Displays the popup menu."""
127 self.menu.popup(None, None, None, button, timing)
128
129 def on_about(self, data):
130 """Displays the about window"""
131 dialog = gtk.AboutDialog()
132 dialog.set_name(APP_NAME)
133 dialog.set_version(APP_VERSION)
134 dialog.set_copyright(APP_COPYRIGHT)
135 dialog.set_comments(APP_DESCRIPTION)
136 dialog.set_website(APP_WEBSITE)
137 dialog.set_logo(gtk.gdk.pixbuf_new_from_file(self.gmail_icon))
138 dialog.run()
139 dialog.destroy()
140
141 def set_from_file(self, path):
142 """Helper function to handle media path."""
143 if path != self.current_icon_path:
144 self.current_icon_path = path
145 gtk.StatusIcon.set_from_file(self, path)
146
147class Gnotify:
148 """Main class."""
149
150 def __init__ (self):
151 """Initializer. Creates the status icon and opens the
152 connection."""
153 self.config = ConfigParser()
154 self.connection = None
155 self.unread_msg_count = 0
156
157 if not self.load_configuration():
158 print "Configuration file does not exist."
159 sys.exit(1)
160
161 self.status_icon = GmailStatusIcon(self.config.get('media', 'path'))
162 # Make sure the status icon shows up
163 while gtk.events_pending():
164 gtk.main_iteration(True)
165 if self.connect() :
166 self.check_inbox()
167 # The multiplier is to simplify the configuration
168 # file. Converts the miliseconds into seconds
169 interval = int(self.config.get('gmail', 'checkinterval'))*1000
170 self.main_timer = gobject.timeout_add(interval, self.check_inbox)
171
172 def load_configuration (self):
173 """Loads the configuration. If file does not exist returns
174 false, if the configuration file is bad formatted it will die
175 loudly."""
176 filename = os.path.expanduser("~/.gsentinel.conf")
177 if not os.path.exists(filename):
178 return False
179
180 self.config.read([filename])
181 return True
182
183 def connect (self):
184 """Creates a connection. The connection itself do the
185 parsing."""
186 if self.connection is None:
187 try:
188 print "connecting..."
189 self.status_icon.set_tooltip(_("Connecting..."))
190 self.connection = GmailAtom(self.config.get('gmail','username'),
191 self.config.get('gmail','password'))
192 except:
193 print "login failed, will retry"
194 self.status_icon.set_tooltip(_("Connection failed"))
195 return False
196 self.connection.refreshInfo()
197 print "connection successful... continuing"
198 self.status_icon.set_tooltip(_("Connected"))
199 return True
200
201 def check_inbox(self):
202 """Checks for new mail."""
203 # Revisar si esta el pop up y eliminarlo
204 if self.connection is None and self.connect() is False:
205 # Try again latter
206 return True
207 print "----------"
208 print "checking for new mail ("+time.strftime("%Y/%m/%d %H:%M:%S",
209 time.localtime())+")"
210 while gtk.events_pending():
211 gtk.main_iteration( True )
212
213 if not self.has_new_mail():
214 # Check again later
215 self.unread_msg_count > 0 or \
216 self.status_icon.set_from_file(self.status_icon.inactive_icon)
217 return True
218 self.status_icon.set_from_file(self.status_icon.active_icon)
219 count = self.connection.getUnreadMsgCount()
220 last_message = self.get_last_message()
221 print "%s new messages" % count
222 # The multiplier is to simplify the configuration
223 # file. Converts the miliseconds into seconds
224 timeout = int(self.config.get('options', 'popuptime'))*1000
225 popup = GmailNotification(last_message, count, timeout,
226 self.status_icon.active_icon)
227 popup.attach_to_status_icon(self.status_icon)
228 popup.show()
229 return True
230
231 def has_new_mail (self):
232 """Checks if new mail has arrived."""
233 try:
234 # Hackerish?
235 self.connection.refreshInfo()
236 current_msg_count = self.connection.getUnreadMsgCount()
237 new_mail = current_msg_count > 0 and \
238 current_msg_count != self.unread_msg_count
239 self.unread_msg_count = current_msg_count
240 return new_mail
241 except:
242 print "getUnreadMsgCount() failed, will try again soon"
243 self.unread_msg_count = 0
244 return False
245
246 def get_last_message (self):
247 """ Returns the sender, subject and snippet of the last
248 message retrieved."""
249 return {'sender' : self.connection.getMsgAuthorName(0),
250 'subject' : self.connection.getMsgTitle(0),
251 'snippet' : self.connection.getMsgSummary(0)[:40] + "..."}
252
253 def main (self):
254 """ Mailoop"""
255 gtk.main()
256
257if __name__ == "__main__":
258 pynotify.init(APP_NAME)
259 notifier = Gnotify()
260 notifier.main()
toggle raw diff