Merge lp:~jconti/gm-notify/messaging-menu into lp:gm-notify

Proposed by Dimitri John Ledkov
Status: Merged
Approved by: Mateusz Balbus
Approved revision: 96
Merged at revision: 80
Proposed branch: lp:~jconti/gm-notify/messaging-menu
Merge into: lp:gm-notify
Diff against target: 1304 lines (+762/-216)
10 files modified
MANIFEST (+2/-0)
data/gm-notify.convert (+6/-0)
data/gm-notify.desktop (+2/-2)
data/net.launchpad.gm-notify.gschema.xml (+25/-0)
gm-config.ui (+439/-0)
gm-notify (+150/-106)
gm-notify-config (+84/-75)
gm_notify_keyring.py (+40/-24)
gtalk.py (+11/-5)
setup.py (+3/-4)
To merge this branch: bzr merge lp:~jconti/gm-notify/messaging-menu
Reviewer Review Type Date Requested Status
Mateusz Balbus Approve
Review via email: mp+155163@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Dimitri John Ledkov (xnox) wrote :

This looks very good, I'm considering to upload this into Ubuntu Archive, as it has MessagingMenu support, among many other improvements.

Revision history for this message
Mateusz Balbus (mate-ob) wrote :

Looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'MANIFEST'
2--- MANIFEST 2010-09-18 13:06:25 +0000
3+++ MANIFEST 2013-03-25 04:23:21 +0000
4@@ -4,12 +4,14 @@
5 keyring.py
6 setup.py
7 gm-config.glade
8+gm-config.ui
9 gtalk.py
10 data/checking.gif
11 data/gm-notify
12 data/gm-notify-config.desktop
13 data/gm-notify.desktop
14 data/gm-notify.schemas
15+data/net.launchpad.gm-notify.gschema.xml
16 po/gm-notify.pot
17 po/bg/gm-notify.mo
18 po/bg/gm-notify.po
19
20=== added file 'data/gm-notify.convert'
21--- data/gm-notify.convert 1970-01-01 00:00:00 +0000
22+++ data/gm-notify.convert 2013-03-25 04:23:21 +0000
23@@ -0,0 +1,6 @@
24+[net.launchpad.gm-notify]
25+play-sound = /apps/gm-notify/play_sound
26+ignore-inbox = /apps/gm-notify/ignore_inbox
27+soundfile = /apps/gm-notify/soundfile
28+mailboxes = /apps/gm-notify/mailboxes
29+openclient = /apps/gm-notify/openclient
30
31=== modified file 'data/gm-notify.desktop'
32--- data/gm-notify.desktop 2010-06-22 19:46:39 +0000
33+++ data/gm-notify.desktop 2013-03-25 04:23:21 +0000
34@@ -1,8 +1,8 @@
35 [Desktop Entry]
36 Encoding=UTF-8
37-Name=Google Mail
38+Name=GMail Notifier
39 Comment=An E-Mail Notifier for Google Mail
40-Icon=applications-email-panel
41+Icon=evolution
42 Type=Application
43 Exec=gm-notify
44 StartupNotify=False
45
46=== added file 'data/net.launchpad.gm-notify.gschema.xml'
47--- data/net.launchpad.gm-notify.gschema.xml 1970-01-01 00:00:00 +0000
48+++ data/net.launchpad.gm-notify.gschema.xml 2013-03-25 04:23:21 +0000
49@@ -0,0 +1,25 @@
50+<?xml version="1.0" encoding="UTF-8"?>
51+<schemalist>
52+ <schema path="/net/launchpad/gm-notify/" id="net.launchpad.gm-notify" gettext-domain="gm-notify">
53+ <key type="b" name="play-sound">
54+ <default>false</default>
55+ <summary>Shall we play a sound on new mail?</summary>
56+ </key>
57+ <key type="b" name="ignore-inbox">
58+ <default>false</default>
59+ <summary>If true, there won't be notifications regarding just your inbox.</summary>
60+ </key>
61+ <key type="s" name="soundfile">
62+ <default>''</default>
63+ <summary>Path to the soundfile which should be played when a new mail arrives</summary>
64+ </key>
65+ <key type="as" name="mailboxes">
66+ <default>[]</default>
67+ <summary>List containing mailboxes to check</summary>
68+ </key>
69+ <key type="b" name="openclient">
70+ <default>false</default>
71+ <summary>Shall we open the default mail client or webinterface?</summary>
72+ </key>
73+ </schema>
74+</schemalist>
75
76=== added file 'gm-config.ui'
77--- gm-config.ui 1970-01-01 00:00:00 +0000
78+++ gm-config.ui 2013-03-25 04:23:21 +0000
79@@ -0,0 +1,439 @@
80+<?xml version="1.0" encoding="UTF-8"?>
81+<interface>
82+ <!-- interface-requires gtk+ 3.0 -->
83+ <object class="GtkWindow" id="gmnotify_config_main">
84+ <property name="can_focus">False</property>
85+ <property name="border_width">10</property>
86+ <property name="title" translatable="yes">GMail Notifier</property>
87+ <property name="window_position">center</property>
88+ <property name="icon_name">evolution</property>
89+ <child>
90+ <object class="GtkBox" id="vbox_main">
91+ <property name="visible">True</property>
92+ <property name="can_focus">False</property>
93+ <property name="orientation">vertical</property>
94+ <property name="spacing">10</property>
95+ <child>
96+ <object class="GtkNotebook" id="notebook_main">
97+ <property name="visible">True</property>
98+ <property name="can_focus">True</property>
99+ <child>
100+ <object class="GtkBox" id="vbox1">
101+ <property name="can_focus">False</property>
102+ <property name="orientation">vertical</property>
103+ <child>
104+ <object class="GtkGrid" id="grid1">
105+ <property name="visible">True</property>
106+ <property name="can_focus">False</property>
107+ <property name="row_homogeneous">True</property>
108+ <property name="column_homogeneous">True</property>
109+ <child>
110+ <object class="GtkLabel" id="label_user">
111+ <property name="visible">True</property>
112+ <property name="can_focus">False</property>
113+ <property name="label" translatable="yes">E-Mail:</property>
114+ </object>
115+ <packing>
116+ <property name="left_attach">0</property>
117+ <property name="top_attach">0</property>
118+ <property name="width">1</property>
119+ <property name="height">1</property>
120+ </packing>
121+ </child>
122+ <child>
123+ <object class="GtkLabel" id="label_password">
124+ <property name="visible">True</property>
125+ <property name="can_focus">False</property>
126+ <property name="label" translatable="yes">Password:</property>
127+ </object>
128+ <packing>
129+ <property name="left_attach">0</property>
130+ <property name="top_attach">1</property>
131+ <property name="width">1</property>
132+ <property name="height">1</property>
133+ </packing>
134+ </child>
135+ <child>
136+ <object class="GtkEntry" id="input_user">
137+ <property name="visible">True</property>
138+ <property name="can_focus">True</property>
139+ <property name="invisible_char">●</property>
140+ <property name="invisible_char_set">True</property>
141+ </object>
142+ <packing>
143+ <property name="left_attach">1</property>
144+ <property name="top_attach">0</property>
145+ <property name="width">1</property>
146+ <property name="height">1</property>
147+ </packing>
148+ </child>
149+ <child>
150+ <object class="GtkEntry" id="input_password">
151+ <property name="visible">True</property>
152+ <property name="can_focus">True</property>
153+ <property name="visibility">False</property>
154+ <property name="invisible_char">●</property>
155+ <property name="invisible_char_set">True</property>
156+ <signal name="focus-out-event" handler="on_input_password_focus_out_event" swapped="no"/>
157+ </object>
158+ <packing>
159+ <property name="left_attach">1</property>
160+ <property name="top_attach">1</property>
161+ <property name="width">1</property>
162+ <property name="height">1</property>
163+ </packing>
164+ </child>
165+ <child>
166+ <object class="GtkImage" id="image_credentials">
167+ <property name="visible">True</property>
168+ <property name="can_focus">False</property>
169+ <property name="stock">gtk-stop</property>
170+ </object>
171+ <packing>
172+ <property name="left_attach">0</property>
173+ <property name="top_attach">2</property>
174+ <property name="width">1</property>
175+ <property name="height">1</property>
176+ </packing>
177+ </child>
178+ <child>
179+ <object class="GtkLabel" id="label_credentials">
180+ <property name="visible">True</property>
181+ <property name="can_focus">False</property>
182+ <property name="label" translatable="yes">Please enter credentials</property>
183+ </object>
184+ <packing>
185+ <property name="left_attach">1</property>
186+ <property name="top_attach">2</property>
187+ <property name="width">1</property>
188+ <property name="height">1</property>
189+ </packing>
190+ </child>
191+ </object>
192+ <packing>
193+ <property name="expand">True</property>
194+ <property name="fill">True</property>
195+ <property name="position">0</property>
196+ </packing>
197+ </child>
198+ <child>
199+ <object class="GtkHSeparator" id="seperator_account">
200+ <property name="visible">True</property>
201+ <property name="can_focus">False</property>
202+ </object>
203+ <packing>
204+ <property name="expand">False</property>
205+ <property name="fill">True</property>
206+ <property name="position">2</property>
207+ </packing>
208+ </child>
209+ <child>
210+ <object class="GtkBox" id="vbox2">
211+ <property name="visible">True</property>
212+ <property name="can_focus">False</property>
213+ <property name="border_width">10</property>
214+ <property name="orientation">vertical</property>
215+ <property name="spacing">5</property>
216+ <child>
217+ <object class="GtkLabel" id="label_click">
218+ <property name="visible">True</property>
219+ <property name="can_focus">False</property>
220+ <property name="xalign">0</property>
221+ <property name="label" translatable="yes">Click on applet opens:</property>
222+ </object>
223+ <packing>
224+ <property name="expand">False</property>
225+ <property name="fill">True</property>
226+ <property name="position">0</property>
227+ </packing>
228+ </child>
229+ <child>
230+ <object class="GtkAlignment" id="alignment1">
231+ <property name="visible">True</property>
232+ <property name="can_focus">False</property>
233+ <property name="left_padding">20</property>
234+ <child>
235+ <object class="GtkRadioButton" id="radiobutton_openweb">
236+ <property name="label" translatable="yes">GMail webinterface</property>
237+ <property name="visible">True</property>
238+ <property name="can_focus">True</property>
239+ <property name="receives_default">False</property>
240+ <property name="relief">none</property>
241+ <property name="xalign">0.5</property>
242+ <property name="active">True</property>
243+ <property name="draw_indicator">True</property>
244+ </object>
245+ </child>
246+ </object>
247+ <packing>
248+ <property name="expand">False</property>
249+ <property name="fill">True</property>
250+ <property name="position">1</property>
251+ </packing>
252+ </child>
253+ <child>
254+ <object class="GtkAlignment" id="alignment2">
255+ <property name="visible">True</property>
256+ <property name="can_focus">False</property>
257+ <property name="left_padding">20</property>
258+ <child>
259+ <object class="GtkRadioButton" id="radiobutton_openclient">
260+ <property name="label" translatable="yes">Current default mail client</property>
261+ <property name="visible">True</property>
262+ <property name="can_focus">True</property>
263+ <property name="receives_default">False</property>
264+ <property name="xalign">0.5</property>
265+ <property name="yalign">0.50999999046325684</property>
266+ <property name="active">True</property>
267+ <property name="draw_indicator">True</property>
268+ <property name="group">radiobutton_openweb</property>
269+ </object>
270+ </child>
271+ </object>
272+ <packing>
273+ <property name="expand">False</property>
274+ <property name="fill">True</property>
275+ <property name="position">2</property>
276+ </packing>
277+ </child>
278+ </object>
279+ <packing>
280+ <property name="expand">False</property>
281+ <property name="fill">True</property>
282+ <property name="position">3</property>
283+ </packing>
284+ </child>
285+ </object>
286+ </child>
287+ <child type="tab">
288+ <object class="GtkLabel" id="label_account">
289+ <property name="visible">True</property>
290+ <property name="can_focus">False</property>
291+ <property name="label" translatable="yes">Account</property>
292+ </object>
293+ <packing>
294+ <property name="tab_fill">False</property>
295+ </packing>
296+ </child>
297+ <child>
298+ <object class="GtkBox" id="vbox_enhanced">
299+ <property name="visible">True</property>
300+ <property name="can_focus">False</property>
301+ <property name="border_width">10</property>
302+ <property name="orientation">vertical</property>
303+ <property name="spacing">5</property>
304+ <child>
305+ <object class="GtkCheckButton" id="checkbutton_sound">
306+ <property name="label" translatable="yes">Play sound when new message arrives</property>
307+ <property name="visible">True</property>
308+ <property name="can_focus">True</property>
309+ <property name="receives_default">False</property>
310+ <property name="relief">half</property>
311+ <property name="xalign">0.5</property>
312+ <property name="draw_indicator">True</property>
313+ <signal name="toggled" handler="on_checkbutton_sound_toggled" swapped="no"/>
314+ </object>
315+ <packing>
316+ <property name="expand">False</property>
317+ <property name="fill">True</property>
318+ <property name="position">0</property>
319+ </packing>
320+ </child>
321+ <child>
322+ <object class="GtkFileChooserButton" id="fcbutton_sound">
323+ <property name="visible">True</property>
324+ <property name="can_focus">False</property>
325+ <property name="create_folders">False</property>
326+ </object>
327+ <packing>
328+ <property name="expand">False</property>
329+ <property name="fill">True</property>
330+ <property name="position">1</property>
331+ </packing>
332+ </child>
333+ <child>
334+ <object class="GtkFrame" id="frame_labels">
335+ <property name="visible">True</property>
336+ <property name="can_focus">False</property>
337+ <property name="label_xalign">0</property>
338+ <property name="shadow_type">none</property>
339+ <child>
340+ <object class="GtkAlignment" id="alignment3">
341+ <property name="visible">True</property>
342+ <property name="can_focus">False</property>
343+ <property name="left_padding">12</property>
344+ <child>
345+ <object class="GtkBox" id="vbox3">
346+ <property name="visible">True</property>
347+ <property name="can_focus">False</property>
348+ <property name="orientation">vertical</property>
349+ <child>
350+ <object class="GtkLabel" id="label_labeldesc">
351+ <property name="visible">True</property>
352+ <property name="can_focus">False</property>
353+ <property name="xalign">0</property>
354+ <property name="label" translatable="yes">Please enter the Labels you want to have
355+checked seperated by commas</property>
356+ </object>
357+ <packing>
358+ <property name="expand">False</property>
359+ <property name="fill">True</property>
360+ <property name="padding">5</property>
361+ <property name="position">0</property>
362+ </packing>
363+ </child>
364+ <child>
365+ <object class="GtkEntry" id="entry_labels">
366+ <property name="visible">True</property>
367+ <property name="can_focus">True</property>
368+ <property name="invisible_char">●</property>
369+ </object>
370+ <packing>
371+ <property name="expand">False</property>
372+ <property name="fill">True</property>
373+ <property name="position">1</property>
374+ </packing>
375+ </child>
376+ <child>
377+ <object class="GtkCheckButton" id="checkbutton_inbox">
378+ <property name="label" translatable="yes">Ignore inbox</property>
379+ <property name="visible">True</property>
380+ <property name="can_focus">True</property>
381+ <property name="receives_default">False</property>
382+ <property name="xalign">0.5</property>
383+ <property name="yalign">0.46000000834465027</property>
384+ <property name="draw_indicator">True</property>
385+ </object>
386+ <packing>
387+ <property name="expand">True</property>
388+ <property name="fill">True</property>
389+ <property name="position">2</property>
390+ </packing>
391+ </child>
392+ </object>
393+ </child>
394+ </object>
395+ </child>
396+ <child type="label">
397+ <object class="GtkLabel" id="label_labels">
398+ <property name="visible">True</property>
399+ <property name="can_focus">False</property>
400+ <property name="label" translatable="yes">&lt;b&gt;Labels:&lt;/b&gt;</property>
401+ <property name="use_markup">True</property>
402+ </object>
403+ </child>
404+ </object>
405+ <packing>
406+ <property name="expand">False</property>
407+ <property name="fill">True</property>
408+ <property name="position">2</property>
409+ </packing>
410+ </child>
411+ <child>
412+ <object class="GtkFrame" id="frame_autostart">
413+ <property name="visible">True</property>
414+ <property name="can_focus">False</property>
415+ <property name="label_xalign">0</property>
416+ <property name="shadow_type">none</property>
417+ <child>
418+ <object class="GtkAlignment" id="alignment4">
419+ <property name="visible">True</property>
420+ <property name="can_focus">False</property>
421+ <property name="left_padding">12</property>
422+ <child>
423+ <object class="GtkCheckButton" id="checkbutton_autostart">
424+ <property name="label" translatable="yes">Start automatically on logon</property>
425+ <property name="visible">True</property>
426+ <property name="can_focus">True</property>
427+ <property name="receives_default">False</property>
428+ <property name="xalign">0.5</property>
429+ <property name="draw_indicator">True</property>
430+ </object>
431+ </child>
432+ </object>
433+ </child>
434+ <child type="label">
435+ <object class="GtkLabel" id="label1">
436+ <property name="visible">True</property>
437+ <property name="can_focus">False</property>
438+ <property name="label" translatable="yes">&lt;b&gt;Autostart:&lt;/b&gt;</property>
439+ <property name="use_markup">True</property>
440+ </object>
441+ </child>
442+ </object>
443+ <packing>
444+ <property name="expand">False</property>
445+ <property name="fill">True</property>
446+ <property name="position">3</property>
447+ </packing>
448+ </child>
449+ </object>
450+ <packing>
451+ <property name="position">1</property>
452+ <property name="tab_fill">False</property>
453+ </packing>
454+ </child>
455+ <child type="tab">
456+ <object class="GtkLabel" id="label_enhanced">
457+ <property name="visible">True</property>
458+ <property name="can_focus">False</property>
459+ <property name="label" translatable="yes">Enhanced</property>
460+ </object>
461+ <packing>
462+ <property name="position">1</property>
463+ <property name="tab_fill">False</property>
464+ </packing>
465+ </child>
466+ </object>
467+ <packing>
468+ <property name="expand">True</property>
469+ <property name="fill">True</property>
470+ <property name="position">0</property>
471+ </packing>
472+ </child>
473+ <child>
474+ <object class="GtkBox" id="hbox_mainbuttons">
475+ <property name="visible">True</property>
476+ <property name="can_focus">False</property>
477+ <property name="spacing">10</property>
478+ <child>
479+ <object class="GtkButton" id="button_apply">
480+ <property name="label">gtk-apply</property>
481+ <property name="visible">True</property>
482+ <property name="can_focus">True</property>
483+ <property name="receives_default">True</property>
484+ <property name="use_stock">True</property>
485+ <signal name="clicked" handler="on_button_apply_clicked" swapped="no"/>
486+ </object>
487+ <packing>
488+ <property name="expand">True</property>
489+ <property name="fill">True</property>
490+ <property name="position">0</property>
491+ </packing>
492+ </child>
493+ <child>
494+ <object class="GtkButton" id="button_close">
495+ <property name="label">gtk-close</property>
496+ <property name="visible">True</property>
497+ <property name="can_focus">True</property>
498+ <property name="receives_default">True</property>
499+ <property name="use_stock">True</property>
500+ <signal name="clicked" handler="gtk_main_quit" swapped="no"/>
501+ </object>
502+ <packing>
503+ <property name="expand">True</property>
504+ <property name="fill">True</property>
505+ <property name="position">1</property>
506+ </packing>
507+ </child>
508+ </object>
509+ <packing>
510+ <property name="expand">False</property>
511+ <property name="fill">True</property>
512+ <property name="position">1</property>
513+ </packing>
514+ </child>
515+ </object>
516+ </child>
517+ </object>
518+</interface>
519
520=== modified file 'gm-notify'
521--- gm-notify 2010-09-18 13:06:25 +0000
522+++ gm-notify 2013-03-25 04:23:21 +0000
523@@ -1,4 +1,4 @@
524-#!/usr/bin/env python
525+#!/usr/bin/python
526 # -*- coding: utf-8 -*-
527
528 # gm-notify v0.10.3
529@@ -19,21 +19,18 @@
530 # You should have received a copy of the GNU General Public License
531 # along with this program. If not, see <http://www.gnu.org/licenses/>.
532 #
533+from __future__ import print_function
534+
535 import os
536 import sys
537 import subprocess
538 import gettext
539 import webbrowser
540
541-import pynotify
542-import indicate
543-import gobject
544-import pygst
545-pygst.require("0.10")
546-import gst
547-import gconf
548-from twisted.internet import glib2reactor
549-glib2reactor.install()
550+from gi.repository import Gio, GLib, MessagingMenu, Notify
551+
552+from twisted.internet import gireactor
553+gireactor.install()
554 from twisted.internet import reactor
555 from twisted.words.protocols.jabber import jid
556
557@@ -57,22 +54,69 @@
558 if os.path.exists(path) and os.access(path, os.X_OK): return path
559 raise PathNotFound("%s not found" % name)
560
561-class CheckMail():
562+def play_sound(name):
563+ '''Spawns a canberra-gtk-play process to play the sound'''
564+ if name is None:
565+ return
566+ player_path = "/usr/bin/canberra-gtk-play"
567+ # Not installed?
568+ if not os.path.exists(player_path):
569+ return
570+ command = [player_path]
571+ # File exists, so use the file flag
572+ if os.path.exists(name):
573+ command.extend(["-f", name])
574+ # Assume it is a sound id
575+ else:
576+ command.extend(["-i", name])
577+ try:
578+ result = GLib.spawn_async(command)
579+ except:
580+ return
581+ # Does nothing but the documentation says to do it anyway
582+ if len(result) > 0:
583+ GLib.spawn_close_pid(result[0])
584+
585+class CheckMail(Gio.Application):
586 def __init__(self):
587 '''initiates DBUS-Messaging interface, creates the MailChecker and registers with indicator-applet.
588 In the end it starts the periodic check timer and a gtk main-loop'''
589-
590- # Kill running gm-notify processes (UGLY!)
591- subprocess.call("kill `pgrep -f gm-notify | grep -v %s`" % os.getpid(), stdout=open("/dev/null", "w"), shell=True)
592-
593- # Initiate pynotify and Gnome Keyring
594- if not pynotify.init(_("GMail Notifier")):
595+ super(CheckMail, self).__init__(application_id="net.launchpad.gm-notify",
596+ flags=Gio.ApplicationFlags.FLAGS_NONE)
597+
598+ self._has_activated = False
599+ self._counts = {}
600+ self.connect("activate", self.on_activate)
601+
602+ def on_remote_quit(self, action, args):
603+ '''Stops the application when the "remote-quit" action is activated'''
604+ reactor.stop()
605+
606+ def on_activate(self, app):
607+ '''When first receiving the activate signal, initialize the primary
608+ instance. On subsequent activate signals, we are being activated from a
609+ secondary instance, so treat it as if our name was clicked in the
610+ messaging menu.'''
611+ if self._has_activated:
612+ self.indicator_clicked()
613+ return
614+
615+ self._has_activated = True
616+
617+ # Add an action to quit
618+ quit_action = Gio.SimpleAction.new("remote-quit", None)
619+ quit_action.connect("activate", self.on_remote_quit)
620+ self.add_action(quit_action)
621+
622+ # Initialize the desktop notifications
623+ if not Notify.init(_("GMail Notifier")):
624 sys.exit(-1)
625-
626+
627 keys = keyring.Keyring("GMail", "mail.google.com", "http")
628 if keys.has_credentials():
629 self.creds = keys.get_credentials()
630 else:
631+ print("Failed to get credentials")
632 # Start gm-notify-config if no credentials are found
633 try:
634 subprocess.call(get_executable_path("gm-notify-config"))
635@@ -88,67 +132,86 @@
636 else:
637 self.domain = self.jid.host
638
639- # init gconf to read config values
640- self.client = gconf.client_get_default()
641-
642- # init sound
643- soundfile = self.client.get_string("/apps/gm-notify/soundfile")
644- if self.client.get_bool("/apps/gm-notify/play_sound") and soundfile:
645- self.player = gst.element_factory_make("playbin", "player")
646- self.player.set_property("video-sink", gst.element_factory_make("fakesink", "fakesink"))
647- self.player.set_property("uri", "file://" + soundfile)
648- bus = self.player.get_bus()
649- bus.add_signal_watch()
650- bus.connect("message", self.gst_message)
651- else:
652- self.player = None
653-
654- # Register with Indicator-Applet
655- self.server = indicate.indicate_server_ref_default()
656- self.server.set_type("message.mail")
657- self.server.set_desktop_file("/usr/share/gm-notify/gm-notify.desktop")
658- self.server.connect("server-display", self.serverClick)
659- self.indicators = {}
660-
661- # Read /apps/gm-notify/ignore_inbox value. If true you will only receive
662- # notifications about configured labels
663- self.ignore_inbox = self.client.get_bool("/apps/gm-notify/ignore_inbox")
664+ self.client = Gio.Settings("net.launchpad.gm-notify")
665+
666+ # Set up the sound file
667+ self._soundfile = self.client.get_string("soundfile")
668+ if self._soundfile == '':
669+ self._soundfile = "message-new-instant"
670+ if not self.client.get_boolean("play-sound"):
671+ self._soundfile = None
672+
673+ # Messaging Menu integration
674+ self._m_menu = MessagingMenu.App.new("gm-notify.desktop")
675+ self._m_menu.register()
676+ self._m_menu.connect("activate-source", self.source_clicked)
677+
678+ # Read ignore-inbox value. If true you will only receive notifications
679+ # about configured labels
680+ self.ignore_inbox = self.client.get_boolean("ignore-inbox")
681
682 # Retrieve the mailbox we're gonna check
683- self.mailboxes = self.client.get_list("/apps/gm-notify/mailboxes", gconf.VALUE_STRING)
684+ self.mailboxes = self.client.get_strv("mailboxes")
685 self.mailboxes.insert(0, "inbox")
686- self.addMailboxIndicators()
687 self.checker = MailChecker(self.jid, self.creds[1], self.mailboxes[1:], self.new_mail, self.update_count)
688 self.checker.connect()
689-
690- reactor.run()
691-
692- def gst_message(self, bus, message):
693- if message.type == gst.MESSAGE_EOS:
694- self.player.set_state(gst.STATE_NULL)
695- elif message.type == gst.MESSAGE_ERROR:
696- self.player.set_state(gst.STATE_NULL)
697- print "Error: %s - %s" % message.parse_error()
698-
699- def serverClick(self, server, timestamp=None):
700- '''called when the server is clicked in the indicator-applet and performs a Mail Check'''
701- for indicator in self.indicators:
702- self.indicators[indicator].set_property("draw-attention", "false")
703-
704- if self.player: self.player.set_state(gst.STATE_NULL)
705+
706+ def indicator_clicked(self):
707+ '''called when "Google Mail" is clicked in indicator-messages and
708+ performs a Mail Check'''
709+ for label in self.mailboxes:
710+ self.remove_attention(label)
711+
712 self.checker.queryInbox()
713+
714+ def remove_attention(self, label):
715+ '''Removes attention from the label source if it exists'''
716+ if self._m_menu.has_source(label):
717+ self._m_menu.remove_attention(label)
718+
719+ def has_source(self, label):
720+ '''Returns true if we have this label, or if we don't and it is in our
721+ mailboxes list, create it'''
722+ if label == "inbox" and self.ignore_inbox:
723+ return False
724+ elif label in self.mailboxes:
725+ if not self._m_menu.has_source(label):
726+ if label in MAILBOXES_NAMES:
727+ name = MAILBOXES_NAMES[label]
728+ else:
729+ name = label
730+ if label == "inbox":
731+ self._m_menu.insert_source_with_string(0, label, None, name, _("empty"))
732+ else:
733+ self._m_menu.append_source_with_string(label, None, name, _("empty"))
734+ if label in self._counts:
735+ self._m_menu.set_source_count(label, self._counts[label])
736+ return True
737+ else:
738+ return False
739
740 def update_count(self, count):
741+ '''Updates the count for all the mailboxes'''
742 for mailbox in count.iteritems():
743 if mailbox[0] == "inbox" and self.ignore_inbox:
744 continue
745
746- i = self.indicators[mailbox[0]]
747- if int(i.get_property("count")) > int(mailbox[1]):
748- i.set_property("draw-attention", "false")
749- i.set_property("count", unicode(mailbox[1]))
750- if int(mailbox[1]) or mailbox[0] == "inbox": i.show()
751- else: i.hide()
752+ if self.has_source(mailbox[0]):
753+ # Get the last count
754+ last_count = 0
755+ if mailbox[0] in self._counts:
756+ last_count = self._counts[mailbox[0]]
757+ current_count = int(mailbox[1])
758+
759+ # Remove attention if the count has decreased
760+ if last_count > current_count:
761+ self._m_menu.remove_attention(mailbox[0])
762+ if current_count > 0:
763+ self._m_menu.set_source_count(mailbox[0], current_count)
764+ # Remove the source if 0 messages, to save space
765+ else:
766+ self._m_menu.remove_source(mailbox[0])
767+ self._counts[mailbox[0]] = current_count
768
769 def new_mail(self, mails):
770 '''Takes mailbox name and titles of mails, to display notification and add indicators'''
771@@ -158,11 +221,12 @@
772 got_label = False
773 for label in mail['labels']:
774 if label == u"^i": label = "inbox"
775- if label in self.indicators:
776- if not label == "inbox" or not self.ignore_inbox:
777- got_label = True
778- self.indicators[label].set_property("draw-attention", "true")
779- if not got_label and self.ignore_inbox: continue
780+ if label == "inbox" and self.ignore_inbox:
781+ continue
782+ if self.has_source(label):
783+ got_label = True
784+ self._m_menu.draw_attention(label)
785+ if not got_label: continue
786
787 if "sender_name" in mail: text += mail['sender_name'] + ":\n"
788 elif "sender_address" in mail: text += mail['sender_address'] + ":\n"
789@@ -179,9 +243,9 @@
790
791 if text:
792 self.showNotification(_("Incoming message"), text.strip("\n"))
793- if self.player: self.player.set_state(gst.STATE_PLAYING)
794+ play_sound(self._soundfile)
795
796- def labelClick(self, indicator, timestamp=None):
797+ def source_clicked(self, app, source_id):
798 '''called when a label is clicked in the indicator-applet and opens the corresponding gmail page'''
799 if self.domain:
800 url = "https://mail.google.com/a/"+self.domain+"/"
801@@ -189,49 +253,29 @@
802 url = "https://mail.google.com/mail/"
803
804 try:
805- url += "#%s" % MAILBOXES_URLS[indicator.label]
806+ url += "#%s" % MAILBOXES_URLS[source_id]
807 except KeyError:
808- url += "#label/%s" % indicator.label
809-
810- indicator.set_property("draw-attention", "false")
811+ url += "#label/%s" % source_id
812
813 # Open mail client
814- if self.client.get_bool("/apps/gm-notify/openclient"):
815- command = self.client.get_string("/desktop/gnome/url-handlers/mailto/command").split(" ")[0]
816- if command.find("mutt") != -1: command += " -f =%s" % indicator.label
817- if self.client.get_bool("/desktop/gnome/url-handlers/mailto/needs_terminal"):
818- termCmd = self.client.get_string("/desktop/gnome/applications/terminal/exec")
819- if termCmd:
820- termCmd += " " + self.client.get_string("/desktop/gnome/applications/terminal/exec_arg") + " "
821- else:
822- termCmd = "gnome-terminal -x "
823- command = termCmd + command
824- subprocess.Popen(command, shell=True)
825+ if self.client.get_boolean("openclient"):
826+ try:
827+ info = Gio.AppInfo.get_default_for_type("x-scheme-handler/mailto", False)
828+ info.launch(None, None)
829+ except:
830+ pass
831 else:
832 webbrowser.open(url)
833-
834+
835 def showNotification(self, title, message):
836 '''takes a title and a message to display the email notification. Returns the
837 created notification object'''
838
839- n = pynotify.Notification(title, message, "notification-message-email")
840+ n = Notify.Notification.new(title, message, "notification-message-email")
841 n.show()
842
843 return n
844
845- def addMailboxIndicators(self):
846- for mailbox in reversed(self.mailboxes):
847- new_indicator = indicate.Indicator()
848-
849- try:
850- new_indicator.set_property("name", MAILBOXES_NAMES[mailbox])
851- except KeyError:
852- new_indicator.set_property("name", mailbox)
853- new_indicator.set_property("count", "0")
854- new_indicator.label = mailbox
855- new_indicator.connect("user-display", self.labelClick)
856- self.indicators[mailbox] = new_indicator
857- self.indicators["inbox"].show()
858- if self.ignore_inbox: self.indicators["inbox"].hide()
859-
860 cm = CheckMail()
861+reactor.registerGApplication(cm)
862+reactor.run()
863
864=== modified file 'gm-notify-config'
865--- gm-notify-config 2010-09-18 13:06:25 +0000
866+++ gm-notify-config 2013-03-25 04:23:21 +0000
867@@ -19,19 +19,18 @@
868 # You should have received a copy of the GNU General Public License
869 # along with this program. If not, see <http://www.gnu.org/licenses/>.
870 #
871+from __future__ import print_function
872+
873 import sys
874 import os
875 import gettext
876 import subprocess
877 import shutil
878
879-import pynotify
880-import pygtk
881-pygtk.require("2.0")
882-import gtk, gtk.glade
883-import gconf
884-from twisted.internet import gtk2reactor
885-gtk2reactor.install()
886+from gi.repository import Gio, Gtk
887+
888+from twisted.internet import gtk3reactor
889+gtk3reactor.install()
890 from twisted.internet import reactor
891 from twisted.words.protocols.jabber import jid
892
893@@ -39,8 +38,6 @@
894 from gtalk import MailChecker
895
896 _ = gettext.translation('gm-notify', fallback=True).ugettext
897-if not pynotify.init(_("GMail Notifier")):
898- sys.exit(-1)
899
900 class PathNotFound(Exception): pass
901
902@@ -53,24 +50,39 @@
903 if os.path.exists(path) and os.access(path, os.X_OK): return path
904 raise PathNotFound("%s not found" % name)
905
906-class Window:
907+class Window(Gtk.Application):
908 def __init__(self):
909+ super(Window, self).__init__(application_id="net.launchpad.gm-notify-config",
910+ flags=Gio.ApplicationFlags.FLAGS_NONE)
911+ self.window = None
912+ self.connect("activate", self.on_activate)
913+
914+ def on_activate(self, app):
915+ '''Setup the application'''
916+ if self.window is not None:
917+ return
918+
919 #####
920 # GUI initialization
921 #####
922 self.keys = keyring.Keyring("GMail", "mail.google.com", "http")
923- self.client = gconf.client_get_default()
924+ self.client = Gio.Settings("net.launchpad.gm-notify")
925
926- if os.path.exists("gm-config.glade"):
927- glade_file = "gm-config.glade"
928- elif os.path.exists("/usr/local/share/gm-notify/gm-config.glade"):
929- glade_file = "/usr/local/share/gm-notify/gm-config.glade"
930- elif os.path.exists("/usr/share/gm-notify/gm-config.glade"):
931- glade_file = "/usr/share/gm-notify/gm-config.glade"
932+ if os.path.exists("gm-config.ui"):
933+ builder_file = "gm-config.ui"
934+ elif os.path.exists("/usr/local/share/gm-notify/gm-config.ui"):
935+ builder_file = "/usr/local/share/gm-notify/gm-config.ui"
936+ elif os.path.exists("/usr/share/gm-notify/gm-config.ui"):
937+ builder_file = "/usr/share/gm-notify/gm-config.ui"
938
939- self.wTree = gtk.glade.XML(glade_file, "gmnotify_config_main", "gm-notify")
940- self.window = self.wTree.get_widget("gmnotify_config_main")
941+ self.wTree = Gtk.Builder.new()
942+ self.wTree.add_from_file(builder_file)
943+ self.wTree.set_translation_domain("gm-notify")
944+ self.window = self.wTree.get_object("gmnotify_config_main")
945 self.window.show_all()
946+ self.add_window(self.window)
947+
948+ self.wTree.get_object("notebook_main").set_current_page(0)
949
950 #####
951 # Init with stored values
952@@ -81,8 +93,8 @@
953 self.creds = self.keys.get_credentials()
954 else:
955 self.creds = ("", "")
956- self.wTree.get_widget("input_user").set_text(self.creds[0])
957- self.wTree.get_widget("input_password").set_text(self.creds[1])
958+ self.wTree.get_object("input_user").set_text(self.creds[0])
959+ self.wTree.get_object("input_password").set_text(self.creds[1])
960
961 self.api = MailChecker("", "")
962 self.api.cb_auth_successful = self.credentials_valid
963@@ -91,68 +103,64 @@
964 self.check_credentials(None, None)
965
966 # Sound
967- self.wTree.get_widget("checkbutton_sound").set_active(self.client.get_bool("/apps/gm-notify/play_sound"))
968- if self.client.get_string("/apps/gm-notify/soundfile"):
969- self.wTree.get_widget("fcbutton_sound").set_filename(self.client.get_string("/apps/gm-notify/soundfile"))
970- self.on_checkbutton_sound_toggled(self.wTree.get_widget("checkbutton_sound"))
971+ self.wTree.get_object("checkbutton_sound").set_active(self.client.get_boolean("play-sound"))
972+ if self.client.get_string("soundfile"):
973+ self.wTree.get_object("fcbutton_sound").set_filename(self.client.get_string("soundfile"))
974+ self.on_checkbutton_sound_toggled(self.wTree.get_object("checkbutton_sound"))
975
976 # ClickAction
977- if self.client.get_bool("/apps/gm-notify/openclient"):
978- self.wTree.get_widget("radiobutton_openclient").set_active(True)
979+ if self.client.get_boolean("openclient"):
980+ self.wTree.get_object("radiobutton_openclient").set_active(True)
981 else:
982- self.wTree.get_widget("radiobutton_openweb").set_active(True)
983+ self.wTree.get_object("radiobutton_openweb").set_active(True)
984
985 # Mailboxes
986- mailboxes = self.client.get_list("/apps/gm-notify/mailboxes", gconf.VALUE_STRING)
987- self.wTree.get_widget("checkbutton_inbox").set_active(self.client.get_bool("/apps/gm-notify/ignore_inbox"))
988- self.wTree.get_widget("entry_labels").set_text(", ".join(mailboxes))
989+ mailboxes = self.client.get_strv("mailboxes")
990+ self.wTree.get_object("checkbutton_inbox").set_active(self.client.get_boolean("ignore-inbox"))
991+ self.wTree.get_object("entry_labels").set_text(", ".join(mailboxes))
992
993 # Autorun
994 if os.path.exists("data/gm-notify.desktop"):
995 self.gm_notify_autostart_file = "data/gm-notify.desktop"
996- elif os.path.exists("/usr/local/share/gm-notify/gm-notify.desktop"):
997- self.gm_notify_autostart_file = "/usr/local/share/gm-notify/gm-notify.desktop"
998- elif os.path.exists("/usr/share/gm-notify/gm-notify.desktop"):
999- self.gm_notify_autostart_file = "/usr/share/gm-notify/gm-notify.desktop"
1000+ elif os.path.exists("/usr/local/share/applications/gm-notify.desktop"):
1001+ self.gm_notify_autostart_file = "/usr/local/share/applications/gm-notify.desktop"
1002+ elif os.path.exists("/usr/share/applications/gm-notify.desktop"):
1003+ self.gm_notify_autostart_file = "/usr/share/applications/gm-notify.desktop"
1004 self.autostart_file = os.path.expanduser("~/.config/autostart/gm-notify.desktop")
1005- self.wTree.get_widget("checkbutton_autostart").set_active(os.path.exists(self.autostart_file))
1006+ self.wTree.get_object("checkbutton_autostart").set_active(os.path.exists(self.autostart_file))
1007
1008- signals = { "gtk_main_quit": self.terminate,
1009- "on_button_apply_clicked": self.save,
1010- "on_input_password_focus_out_event": self.check_credentials,
1011- "on_checkbutton_sound_toggled": self.on_checkbutton_sound_toggled,
1012- }
1013- self.wTree.signal_autoconnect(signals)
1014+ # Connect signals
1015+ self.wTree.get_object("button_close").connect("clicked", self.terminate)
1016+ self.wTree.get_object("button_apply").connect("clicked", self.save)
1017+ self.wTree.get_object("input_password").connect("focus-out-event", self.check_credentials)
1018+ self.wTree.get_object("checkbutton_sound").connect("toggled", self.on_checkbutton_sound_toggled)
1019
1020 def save(self, widget, data=None):
1021 '''saves the entered data and closes the app'''
1022-
1023- self.client.add_dir("/apps/gm-notify", gconf.CLIENT_PRELOAD_NONE)
1024-
1025 # Credentials
1026 self.keys.delete_credentials()
1027- self.keys.set_credentials(( self.wTree.get_widget("input_user").get_text(),
1028- self.wTree.get_widget("input_password").get_text()))
1029+ self.keys.set_credentials(self.wTree.get_object("input_user").get_text(),
1030+ self.wTree.get_object("input_password").get_text())
1031
1032 # Mailboxes
1033 mailboxes = []
1034- for label in self.wTree.get_widget("entry_labels").get_text().split(","):
1035+ for label in self.wTree.get_object("entry_labels").get_text().split(","):
1036 mailboxes.append(label.strip())
1037- self.client.set_list("/apps/gm-notify/mailboxes", gconf.VALUE_STRING, mailboxes)
1038- self.client.set_bool("/apps/gm-notify/ignore_inbox", self.wTree.get_widget("checkbutton_inbox").get_active())
1039+ self.client.set_strv("mailboxes", mailboxes)
1040+ self.client.set_boolean("ignore-inbox", self.wTree.get_object("checkbutton_inbox").get_active())
1041
1042 # ClickAction
1043- self.client.set_bool("/apps/gm-notify/openclient", self.wTree.get_widget("radiobutton_openclient").get_active())
1044+ self.client.set_boolean("openclient", self.wTree.get_object("radiobutton_openclient").get_active())
1045
1046 # Soundfile
1047- if self.wTree.get_widget("checkbutton_sound").get_active() and self.wTree.get_widget("fcbutton_sound").get_filename():
1048- self.client.set_bool("/apps/gm-notify/play_sound", True)
1049- self.client.set_string("/apps/gm-notify/soundfile", str(self.wTree.get_widget("fcbutton_sound").get_filename()))
1050+ if self.wTree.get_object("checkbutton_sound").get_active() and self.wTree.get_object("fcbutton_sound").get_filename():
1051+ self.client.set_boolean("play-sound", True)
1052+ self.client.set_string("soundfile", str(self.wTree.get_object("fcbutton_sound").get_filename()))
1053 else:
1054- self.client.set_bool("/apps/gm-notify/play_sound", False)
1055+ self.client.set_boolean("play-sound", False)
1056
1057 # Autorun
1058- if self.wTree.get_widget("checkbutton_autostart").get_active():
1059+ if self.wTree.get_object("checkbutton_autostart").get_active():
1060 if not os.path.exists(self.autostart_file):
1061 try:
1062 os.makedirs(os.path.expanduser("~/.config/autostart"))
1063@@ -163,13 +171,13 @@
1064 shutil.copyfile(self.gm_notify_autostart_file, self.autostart_file)
1065 os.chmod(self.autostart_file, 0700)
1066 except IOError:
1067- print "Warning: cannot write to path", self.autostart_file
1068+ print("Warning: cannot write to path", self.autostart_file)
1069 else:
1070 if os.path.exists(self.autostart_file):
1071 try:
1072 os.unlink(self.autostart_file)
1073 except:
1074- print "Warning: cannot delete", self.autostart_file
1075+ print("Warning: cannot delete", self.autostart_file)
1076
1077 # Start gm-notify itself
1078 subprocess.Popen(get_executable_path("gm-notify"))
1079@@ -178,16 +186,16 @@
1080 reactor.stop()
1081
1082 def on_checkbutton_sound_toggled(self, widget):
1083- self.wTree.get_widget("fcbutton_sound").set_sensitive(self.wTree.get_widget("checkbutton_sound").get_active())
1084+ self.wTree.get_object("fcbutton_sound").set_sensitive(self.wTree.get_object("checkbutton_sound").get_active())
1085
1086 def check_credentials(self, widget, event, data=None):
1087 '''check if the given credentials are valid'''
1088
1089- input_user = self.wTree.get_widget("input_user")
1090- input_password = self.wTree.get_widget("input_password")
1091- image_credentials = self.wTree.get_widget("image_credentials")
1092- label_credentials = self.wTree.get_widget("label_credentials")
1093- button_apply = self.wTree.get_widget("button_apply")
1094+ input_user = self.wTree.get_object("input_user")
1095+ input_password = self.wTree.get_object("input_password")
1096+ image_credentials = self.wTree.get_object("image_credentials")
1097+ label_credentials = self.wTree.get_object("label_credentials")
1098+ button_apply = self.wTree.get_object("button_apply")
1099 button_apply.set_sensitive(False)
1100
1101 # Change status text and disable input fields
1102@@ -203,13 +211,13 @@
1103 return False
1104
1105 def credentials_valid(self):
1106- input_user = self.wTree.get_widget("input_user")
1107- input_password = self.wTree.get_widget("input_password")
1108- image_credentials = self.wTree.get_widget("image_credentials")
1109- label_credentials = self.wTree.get_widget("label_credentials")
1110- button_apply = self.wTree.get_widget("button_apply")
1111+ input_user = self.wTree.get_object("input_user")
1112+ input_password = self.wTree.get_object("input_password")
1113+ image_credentials = self.wTree.get_object("image_credentials")
1114+ label_credentials = self.wTree.get_object("label_credentials")
1115+ button_apply = self.wTree.get_object("button_apply")
1116
1117- image_credentials.set_from_icon_name("gtk-yes", gtk.ICON_SIZE_MENU)
1118+ image_credentials.set_from_icon_name("gtk-yes", Gtk.IconSize.MENU)
1119 label_credentials.set_text(_("Valid credentials"))
1120 button_apply.set_sensitive(True)
1121 input_user.set_sensitive(True)
1122@@ -218,12 +226,12 @@
1123 self.api.die()
1124
1125 def credentials_invalid(self):
1126- input_user = self.wTree.get_widget("input_user")
1127- input_password = self.wTree.get_widget("input_password")
1128- image_credentials = self.wTree.get_widget("image_credentials")
1129- label_credentials = self.wTree.get_widget("label_credentials")
1130+ input_user = self.wTree.get_object("input_user")
1131+ input_password = self.wTree.get_object("input_password")
1132+ image_credentials = self.wTree.get_object("image_credentials")
1133+ label_credentials = self.wTree.get_object("label_credentials")
1134
1135- image_credentials.set_from_icon_name("gtk-stop", gtk.ICON_SIZE_MENU)
1136+ image_credentials.set_from_icon_name("gtk-stop", Gtk.IconSize.MENU)
1137 label_credentials.set_text(_("Invalid credentials"))
1138 input_user.set_sensitive(True)
1139 input_password.set_sensitive(True)
1140@@ -231,4 +239,5 @@
1141 self.api.die()
1142
1143 t = Window()
1144+reactor.registerGApplication(t)
1145 reactor.run()
1146
1147=== modified file 'gm_notify_keyring.py'
1148--- gm_notify_keyring.py 2010-05-05 17:31:35 +0000
1149+++ gm_notify_keyring.py 2013-03-25 04:23:21 +0000
1150@@ -1,43 +1,59 @@
1151+from __future__ import print_function
1152+
1153 __version__ = "$Revision: 14294 $"
1154
1155-import gtk # ensure that the application name is correctly set
1156-import gnomekeyring as gkey
1157-
1158+from gi.repository import GnomeKeyring, Gtk
1159+
1160+def attributes(d):
1161+ '''Converts a dictionary to a GnomeKeyring.Attribute array'''
1162+ attrs = GnomeKeyring.Attribute.list_new()
1163+ for key in d:
1164+ GnomeKeyring.Attribute.list_append_string(attrs, key, str(d[key]))
1165+ return attrs
1166+
1167+def dict_from_attributes(attrs):
1168+ '''Converts item results back into a dictionary'''
1169+ result = {}
1170+ for attr in GnomeKeyring.Attribute.list_to_glist(attrs):
1171+ result[attr.name] = attr.get_string()
1172+ return result
1173+
1174+class KeyringException(Exception):
1175+ pass
1176
1177 class Keyring(object):
1178 def __init__(self, name, server, protocol):
1179 self._name = name
1180 self._server = server
1181 self._protocol = protocol
1182- self._keyring = gkey.get_default_keyring_sync()
1183+ result, self._keyring = GnomeKeyring.get_default_keyring_sync()
1184
1185 def has_credentials(self):
1186- try:
1187- attrs = {"server": self._server, "protocol": self._protocol}
1188- items = gkey.find_items_sync(gkey.ITEM_NETWORK_PASSWORD, attrs)
1189- return len(items) > 0
1190- except (gkey.DeniedError, gkey.NoMatchError):
1191+ attrs = attributes({"server": self._server, "protocol": self._protocol})
1192+ result, items = GnomeKeyring.find_items_sync(GnomeKeyring.ItemType.NETWORK_PASSWORD, attrs)
1193+ if result in (GnomeKeyring.Result.NO_MATCH, GnomeKeyring.Result.DENIED):
1194 return False
1195+ return len(items) > 0
1196
1197 def get_credentials(self):
1198- attrs = {"server": self._server, "protocol": self._protocol}
1199- items = gkey.find_items_sync(gkey.ITEM_NETWORK_PASSWORD, attrs)
1200- return (items[0].attributes["user"], items[0].secret)
1201+ attrs = attributes({"server": self._server, "protocol": self._protocol})
1202+ result, items = GnomeKeyring.find_items_sync(GnomeKeyring.ItemType.NETWORK_PASSWORD, attrs)
1203+ if len(items) == 0:
1204+ raise KeyringException("Credentials not found")
1205+ d = dict_from_attributes(items[0].attributes)
1206+ return (d["user"], items[0].secret)
1207
1208 def delete_credentials(self):
1209- attrs = {"server": self._server, "protocol": self._protocol}
1210- try:
1211- items = gkey.find_items_sync(gkey.ITEM_NETWORK_PASSWORD, attrs)
1212- for item in items:
1213- gkey.item_delete_sync(None, item.item_id)
1214- except (gkey.DeniedError, gkey.NoMatchError):
1215- pass
1216+ attrs = attributes({"server": self._server, "protocol": self._protocol})
1217+ result, items = GnomeKeyring.find_items_sync(GnomeKeyring.ItemType.NETWORK_PASSWORD, attrs)
1218+ for item in items:
1219+ GnomeKeyring.item_delete_sync(self._keyring, item.item_id)
1220
1221- def set_credentials(self, (user, pw)):
1222- attrs = {
1223+ def set_credentials(self, user, pw):
1224+ attrs = attributes({
1225 "user": user,
1226 "server": self._server,
1227 "protocol": self._protocol,
1228- }
1229- gkey.item_create_sync(gkey.get_default_keyring_sync(),
1230- gkey.ITEM_NETWORK_PASSWORD, self._name, attrs, pw, True)
1231+ })
1232+ GnomeKeyring.item_create_sync(self._keyring,
1233+ GnomeKeyring.ItemType.NETWORK_PASSWORD, self._name, attrs, pw, True)
1234
1235=== modified file 'gtalk.py'
1236--- gtalk.py 2010-09-18 13:06:25 +0000
1237+++ gtalk.py 2013-03-25 04:23:21 +0000
1238@@ -19,17 +19,19 @@
1239 # You should have received a copy of the GNU General Public License
1240 # along with this program. If not, see <http://www.gnu.org/licenses/>.
1241 #
1242+from __future__ import print_function
1243+
1244 from threading import Event
1245
1246 from twisted.words.protocols.jabber import xmlstream, client, jid
1247 from twisted.words.xish import domish
1248-from twisted.internet import reactor, task
1249+from twisted.internet import reactor, task, error
1250
1251 _DEBUG = False
1252 COLOR_GREEN = "\033[92m"
1253 COLOR_END = "\033[0m"
1254 def DEBUG(msg):
1255- if _DEBUG: print COLOR_GREEN + str(msg) + COLOR_END
1256+ if _DEBUG: print(COLOR_GREEN + str(msg) + COLOR_END)
1257
1258 class GTalkClientFactory(xmlstream.XmlStreamFactory):
1259 def __init__(self, jid, password):
1260@@ -89,7 +91,11 @@
1261 self.connector.disconnect() # Our reconnecting factory will try the reconnecting
1262
1263 def send_callback_handler(self, data, callback=None, **kargs):
1264- self.timeout_call_id.cancel()
1265+ try:
1266+ self.timeout_call_id.cancel()
1267+ except error.AlreadyCalled:
1268+ DEBUG("already called timeout_call_id.cancel()")
1269+ return
1270 if callback:
1271 callback(data, **kargs)
1272 else:
1273@@ -242,10 +248,10 @@
1274 if iq: self.queryInbox()
1275
1276 def rawDataIn(self, buf):
1277- print u"< %s" % unicode(buf, "utf-8")
1278+ print(u"< %s" % unicode(buf, "utf-8"))
1279
1280 def rawDataOut(self, buf):
1281- print u"> %s" % unicode(buf, "utf-8")
1282+ print(u"> %s" % unicode(buf, "utf-8"))
1283
1284 def connectedCB(self, xmlstream):
1285 self.xmlstream = xmlstream
1286
1287=== modified file 'setup.py'
1288--- setup.py 2010-09-18 13:06:25 +0000
1289+++ setup.py 2013-03-25 04:23:21 +0000
1290@@ -10,11 +10,10 @@
1291 py_modules=['gtalk', 'gm_notify_keyring'],
1292 scripts=['gm-notify', 'gm-notify-config'],
1293 data_files=[('/usr/share/applications', ['data/gm-notify-config.desktop']),
1294- ('/usr/share/indicators/messages/applications', ['data/gm-notify']),
1295- ('/usr/share/gm-notify', ['data/gm-notify.desktop']),
1296+ ('/usr/share/applications', ['data/gm-notify.desktop']),
1297 ('/usr/share/gm-notify', ['data/checking.gif']),
1298- ('/usr/share/gm-notify', ['gm-config.glade']),
1299- ('/etc/gconf/schemas', ['data/gm-notify.schemas']),
1300+ ('/usr/share/gm-notify', ['gm-config.ui']),
1301+ ('/usr/share/glib-2.0/schemas', ['data/net.launchpad.gm-notify.gschema.xml']),
1302 ('/usr/share/locale/da/LC_MESSAGES', ['po/da/gm-notify.mo']),
1303 ('/usr/share/locale/bg/LC_MESSAGES', ['po/bg/gm-notify.mo']),
1304 ('/usr/share/locale/de/LC_MESSAGES', ['po/de/gm-notify.mo']),

Subscribers

People subscribed via source and target branches

to status/vote changes: