diff -Nru emesene-1.6.1/Config.py emesene-1.6.3~peppermint1/Config.py --- emesene-1.6.1/Config.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/Config.py 2010-07-12 23:13:14.000000000 +0100 @@ -45,8 +45,8 @@ 'overrideDesktop' : '', 'overrideMail' : '', 'startup' : 'default', - 'Id' : id, 'dontShowAvatarInLoginWindow' : 0, + 'Id' : id, } @@ -164,7 +164,8 @@ 'toolInvite' : True, 'toolSendFile' : True, 'toolWebcam' : True, - 'toolClear' : True, + 'toolClear' : True, + 'avatarDate' : '1800-01-01T00:00:00', } class Config(gobject.GObject): diff -Nru emesene-1.6.1/Controller.py emesene-1.6.3~peppermint1/Controller.py --- emesene-1.6.1/Controller.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/Controller.py 2010-08-18 23:28:16.000000000 +0100 @@ -67,6 +67,8 @@ import ContactManager from AvatarHistory import AvatarHistoryViewer +from SingleInstance import SingleInstance + SERVER_HOST = 'messenger.hotmail.com' class Controller(gobject.GObject): @@ -97,12 +99,12 @@ ()), } - def __init__(self, username, minimized, leakdebug, iconified, badroot): + def __init__(self, username, minimized, leakdebug, iconified, badroot, singleinstance): '''Constructor''' gobject.GObject.__init__(self) self.NAME = 'emesene' - self.VERSION = '1.6.1 "mate"' + self.VERSION = '1.6.3 - "Uberlândia"' self.COPYRIGHT = 'Luis Mariano Guerra, dx, C10uD, arielj' self.COMMENT = _('A client for the WLM%s network') % u'\u2122' self.LICENSE_FALLBACK = 'GNU General Public License' @@ -380,9 +382,9 @@ sys.excepthook = self.except_hook_dialog # FIXME: strange issue with avatars - self.changeAvatar(self.config.user['avatarPath']) + self.changeAvatar(self.config.user['avatarPath'],initial=False) self.mainWindow.buildInterface('userlist') - self.changeAvatar(self.config.user['avatarPath']) + self.changeAvatar(self.config.user['avatarPath'],initial=False) layout = self.config.user['conversationLayout'] if not self.conversationLayoutManager.load(layout): @@ -702,15 +704,15 @@ currentAvatarPath = self.config.user['avatarPath'] dialog.show_profile(self, nick, psm, currentAvatarPath, responseProfile) - def on_change_avatar(self, msnp, filename): + def on_change_avatar(self, msnp, filename, initial=False): '''control if the avatar already exists or save the new avatar''' if os.path.exists(filename): - self.changeAvatar(filename) + self.changeAvatar(filename, initial) return else: return - def changeAvatar(self, filename): + def changeAvatar(self, filename, initial=False): if not self.msn: return @@ -719,18 +721,21 @@ try: self.avatar = Avatar.Avatar(self, filename, self.config.getAvatarsCachePath()) + filename = self.avatar.getImagePath() except: # may be GError return if filename == '': - self.msn.setDisplayPicture('') self.mainWindow.setAvatar(self.theme.getImage('userPanel')) self.config.user['avatarPath'] = '' else: - self.msn.setDisplayPicture(self.avatar.getImagePath()) self.mainWindow.setAvatar(self.avatar.getThumb()) self.config.user['avatarPath'] = self.avatar.getImagePath() + # if not initial, update avatar on Msn's servers + if not initial: + self.msn.setDisplayPicture(filename) + self.emit('avatar-changed') def on_self_status_changed(self, msn, status): @@ -926,24 +931,25 @@ leakdebug = False iconified = False badroot = False + singleinstance = False # parse arguments try: import getopt except ImportError: #getopt is disabled in emesene py2exe - return ('', False, False, False) + return ('', False, False, False, False, False) - shortArgs = 'm,i,f' + shortArgs = 'm,i,f,s' longArgs = ['iconified', 'minimized', 'user=', 'fast-login', 'leakdebug', - 'i-know-that-running-emesene-as-root-is-bad'] + 'i-know-that-running-emesene-as-root-is-bad', 'single-instance'] try: args = getopt.getopt(sys.argv[1:], shortArgs, longArgs) except getopt.GetoptError, e: # wrong input, display usage print e print 'Usage:', sys.argv[0], '[-m|--minimized] | [-i | --iconified] [--user=mail@address]' - print 'Advanced options: [-f|--fast-login], --leakdebug, --i-know-that-running-emesene-as-root-is-bad' + print 'Advanced options: [-f|--fast-login], --leakdebug, --i-know-that-running-emesene-as-root-is-bad, [-s|--single-instance]' sys.exit(1) # parse getopt output @@ -959,8 +965,10 @@ leakdebug = True if key == '--i-know-that-running-emesene-as-root-is-bad': badroot = True + if key == '-s' or key == '--single-instance': + singleinstance = True - return (username, minimized, leakdebug, iconified, badroot) + return (username, minimized, leakdebug, iconified, badroot, singleinstance) def debug(msg): '''print a debug message''' @@ -968,11 +976,20 @@ def main(): args = parseArgs() + if (os.name == 'posix') and (os.getuid() == 0) and (args[4] == False): print "I refuse to run as root. " \ "If you know the risks and still want to do it," \ " just add the --i-know-that-running-emesene-as-root-is-bad option." return + + single_instance = SingleInstance() + + if args[5] and single_instance.is_running(): + print "Another instance of emesene is already running. Quitting." + # try to show instance already running + single_instance.show() + sys.exit(0) if (os.name != 'nt'): try: diff -Nru emesene-1.6.1/ConversationUI.py emesene-1.6.3~peppermint1/ConversationUI.py --- emesene-1.6.1/ConversationUI.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/ConversationUI.py 2010-07-12 23:13:14.000000000 +0100 @@ -163,14 +163,14 @@ else: self.hbox.pack_start(self.remoteAvatar, False, False, padding = 1) self.hbox.pack_start(self.mainPaned, True, True) - + self.hbox.set_size_request(-1,40) self.hbox.show() # the vertical panel that divides the textview and the input # (toolbar and input) vpaned = gtk.VPaned() - vpaned.pack1(self.hbox, True, True) - vpaned.pack2(self.input, False) + vpaned.pack1(self.hbox, True, False) + vpaned.pack2(self.input, False, True) # connect the notify signal to catch dragging of the seperator, as # suggested in http://faq.pygtk.org/index.py?req=show&file=faq19.013.htp vpaned.connect('notify', self.onInputResize) @@ -1034,9 +1034,7 @@ self.scrollInput.get_vadjustment().connect('value-changed', self.move_sendbtn) - self.input.connect('copy-clipboard', self._on_copy_clipboard) - self.clipboard = gtk.Clipboard(selection=gtk.gdk.atom_intern("CLIPBOARD")) - self.input.get_buffer().add_selection_clipboard(self.clipboard) + self.input.connect_after('copy-clipboard', self._on_copy_clipboard) if setFocus: self.input.grab_focus() @@ -1228,8 +1226,9 @@ try: start_sel, end_sel = self.inputBuffer.get_selection_bounds() text = self.getInputText(False, True) - self.clipboard.set_text(text, len(text)) - self.clipboard.store() + clipboard = gtk.clipboard_get() + clipboard.set_text(text, -1) + clipboard.store() except ValueError: #if the user just press ctrl+c with nothing selected return diff -Nru emesene-1.6.1/ConversationWindow.py emesene-1.6.3~peppermint1/ConversationWindow.py --- emesene-1.6.1/ConversationWindow.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/ConversationWindow.py 2010-07-12 23:13:14.000000000 +0100 @@ -476,6 +476,9 @@ try: if self.controller.config.user['blinkTrayIcon']: self.controller.trayIcon.tray.set_blinking(True) + except: + pass + try: if self.controller.config.user['statusbarHighLight']: self.set_urgency_hint(True) except: diff -Nru emesene-1.6.1/debian/changelog emesene-1.6.3~peppermint1/debian/changelog --- emesene-1.6.1/debian/changelog 2010-04-14 00:45:31.000000000 +0100 +++ emesene-1.6.3~peppermint1/debian/changelog 2010-08-18 23:30:53.000000000 +0100 @@ -1,11 +1,41 @@ -emesene (1.6.1-0ubuntu1) lucid; urgency=low +emesene (1.6.3~peppermint1) lucid; urgency=low - * New upstream release (LP: #562646). - * Fix missing-debian-source-format lintian warning. - * Refresh 20_dont_build_own_libmimic.patch patch. - * Bump Standards-Version to 3.8.4. + * Imported from Debian Sid for Peppermint OS - -- Devid Antonio Filoni Wed, 14 Apr 2010 01:33:51 +0200 + -- Kendall Weaver Wed, 18 Aug 2010 18:30:48 -0400 + +emesene (1.6.3-1) unstable; urgency=low + + * debian/control: add myself to Uploaders field. + * New upstream release. + * Add 21_svn2451_fix_avatar patch to fix avatars storage. + * Bump Standards-Version to 3.9.0. + + -- Devid Antonio Filoni Sun, 18 Jul 2010 04:13:52 +0200 + +emesene (1.6.2-1) unstable; urgency=low + + * Brown paper bag release. Update to 1.6.2 as intended in the + previous upload. + + -- Emilio Pozuelo Monfort Sat, 29 May 2010 04:29:58 +0200 + +emesene (1.6.1-2) unstable; urgency=low + + * debian/control: + - Recommend python-gst0.10, needed for webcam support. Closes: #565116. + - Stop recommending python-sexy, it's been removed from the archive and + emesene doesn't use it anymore. + - Standards-Version is 3.8.4, no changes needed. + * debian/control, + debian/rules, + debian/source/format: + - Switch to source format 3.0 (quilt). + * New upstream release. Closes: #578936. + - debian/patches/20_dont_build_own_libmimic.patch: + + Updated. + + -- Emilio Pozuelo Monfort Fri, 28 May 2010 16:48:03 +0200 emesene (1.6-1) unstable; urgency=low diff -Nru emesene-1.6.1/debian/control emesene-1.6.3~peppermint1/debian/control --- emesene-1.6.1/debian/control 2010-04-14 00:39:54.000000000 +0100 +++ emesene-1.6.3~peppermint1/debian/control 2010-07-18 03:44:08.000000000 +0100 @@ -1,14 +1,13 @@ Source: emesene Section: net Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Emilio Pozuelo Monfort -Uploaders: Python Applications Packaging Team +Maintainer: Emilio Pozuelo Monfort +Uploaders: Python Applications Packaging Team , + Devid Antonio Filoni Build-Depends: debhelper (>= 7.0.50~), - quilt (>= 0.46-7), python Build-Depends-Indep: python-support -Standards-Version: 3.8.4 +Standards-Version: 3.9.0 Homepage: http://www.emesene.org/ Vcs-Svn: svn://svn.debian.org/python-apps/packages/emesene/trunk/ Vcs-Browser: http://svn.debian.org/viewsvn/python-apps/packages/emesene/trunk/ @@ -21,9 +20,9 @@ python-cairo, python-gobject Recommends: python-dbus, + python-gst0.10, python-notify, - python-libmimic, - python-sexy + python-libmimic Suggests: python-gtkspell Description: platform independent MSN Messenger client emesene is a nice and simple MSN Messenger client. It tries to be similar diff -Nru emesene-1.6.1/debian/patches/20_dont_build_own_libmimic.patch emesene-1.6.3~peppermint1/debian/patches/20_dont_build_own_libmimic.patch --- emesene-1.6.1/debian/patches/20_dont_build_own_libmimic.patch 2010-04-14 00:46:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/debian/patches/20_dont_build_own_libmimic.patch 2010-05-28 15:48:12.000000000 +0100 @@ -5,7 +5,7 @@ --- a/setup.py +++ b/setup.py -@@ -6,17 +6,6 @@ +@@ -6,18 +6,6 @@ import sys if os.name == 'posix': @@ -20,10 +20,11 @@ - 'and your system is safe. It\'s a win-win, don\'t you think?\n'\ - 'Thanks for trying emesene.' - quit() - +- # From apport's setup.py mo_files = [] -@@ -50,7 +39,6 @@ + for filepath in glob("po/*/LC_MESSAGES/*.mo"): +@@ -50,7 +38,6 @@ ('share/icons/hicolor/scalable/apps', ['misc/emesene.svg']), ('share/man/man1', ['misc/emesene.1']), ('share/applications', ['misc/emesene.desktop'])] + mo_files, diff -Nru emesene-1.6.1/debian/patches/21_svn2451_fix_avatar.patch emesene-1.6.3~peppermint1/debian/patches/21_svn2451_fix_avatar.patch --- emesene-1.6.1/debian/patches/21_svn2451_fix_avatar.patch 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/debian/patches/21_svn2451_fix_avatar.patch 2010-07-18 03:45:11.000000000 +0100 @@ -0,0 +1,49 @@ +Description: Revert and change some avatar roaming code. + This seems to fix a bug in roaming profile: avatars were not stored. + http://emesene.svn.sourceforge.net/viewvc/emesene?view=revision&revision=2451 +Index: emesene-1.6.3/Controller.py +=================================================================== +--- emesene-1.6.3.orig/Controller.py 2010-07-18 04:23:03.166283000 +0200 ++++ emesene-1.6.3/Controller.py 2010-07-18 04:23:39.890283000 +0200 +@@ -382,9 +382,9 @@ + sys.excepthook = self.except_hook_dialog + + # FIXME: strange issue with avatars +- self.changeAvatar(self.config.user['avatarPath'],initial=True) ++ self.changeAvatar(self.config.user['avatarPath'],initial=False) + self.mainWindow.buildInterface('userlist') +- self.changeAvatar(self.config.user['avatarPath'],initial=True) ++ self.changeAvatar(self.config.user['avatarPath'],initial=False) + + layout = self.config.user['conversationLayout'] + if not self.conversationLayoutManager.load(layout): +Index: emesene-1.6.3/emesenelib/ProfileManager.py +=================================================================== +--- emesene-1.6.3.orig/emesenelib/ProfileManager.py 2010-07-18 04:24:00.574283000 +0200 ++++ emesene-1.6.3/emesenelib/ProfileManager.py 2010-07-18 04:25:54.710283000 +0200 +@@ -187,7 +187,7 @@ + delta = date2 - date1 + else: + delta = date1 - date2 +- newAvatar = (delta.seconds > 10 or delta.seconds < -10) ++ newAvatar = (delta.seconds > 25 or delta.seconds < -25) + except: + newAvatar = True + +@@ -270,7 +270,7 @@ + #print "DP:", len(data), stat, reas + fd, fn = tempfile.mkstemp(prefix='emsnpic') + os.write(fd, data) +- initial = True ++ initial = False + self.emit('self-dp-changed', fn, initial) + + return False +@@ -340,7 +340,6 @@ + seconds = str(date.second) + + self.config.user['avatarDate'] = "".join((year,"-",month,"-",day,"T",hour,":",minutes,":",seconds)) +- + try: + document_rid = response.body.split('')[0].split('')[1] + soap.requests.create_relationships(self.proxy, self.affinityCache, self.rid, \ diff -Nru emesene-1.6.1/debian/patches/series emesene-1.6.3~peppermint1/debian/patches/series --- emesene-1.6.1/debian/patches/series 2010-04-14 00:11:55.000000000 +0100 +++ emesene-1.6.3~peppermint1/debian/patches/series 2010-07-18 03:44:08.000000000 +0100 @@ -1 +1,2 @@ 20_dont_build_own_libmimic.patch +21_svn2451_fix_avatar.patch diff -Nru emesene-1.6.1/debian/rules emesene-1.6.3~peppermint1/debian/rules --- emesene-1.6.1/debian/rules 2010-04-14 00:11:55.000000000 +0100 +++ emesene-1.6.3~peppermint1/debian/rules 2010-05-24 19:59:02.000000000 +0100 @@ -1,7 +1,7 @@ #!/usr/bin/make -f %: - dh --with quilt $@ + dh $@ override_dh_auto_install: dh_auto_install -- --install-lib=usr/share/emesene \ diff -Nru emesene-1.6.1/dialog.py emesene-1.6.3~peppermint1/dialog.py --- emesene-1.6.1/dialog.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/dialog.py 2010-07-12 23:13:14.000000000 +0100 @@ -1525,9 +1525,11 @@ self.vbox.pack_start(hbox0, False) hbox0.show_all() - self.shortcut.connect('changed', self._on_changed) - self.smilie_list = smilie_list + pygtk_v = gtk.pygtk_version + if (pygtk_v[0] == 2 and pygtk_v[1] > 15) or (pygtk_v[0] > 2): + self._on_changed(None) + self.shortcut.connect('changed', self._on_changed) def _on_accept(self, button): '''method called when the user clicks the button''' @@ -1579,7 +1581,7 @@ SHORTCUT = self.shortcut.get_text() - if SHORTCUT in self.smilie_list: + if SHORTCUT in self.smilie_list or SHORTCUT == "": self.shortcut.set_property('secondary-icon-stock', gtk.STOCK_DIALOG_ERROR) else: self.shortcut.set_property('secondary-icon-stock', None) diff -Nru emesene-1.6.1/emesenelib/core.py emesene-1.6.3~peppermint1/emesenelib/core.py --- emesene-1.6.1/emesenelib/core.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/emesenelib/core.py 2010-07-12 23:13:14.000000000 +0100 @@ -115,8 +115,10 @@ (gobject.TYPE_STRING,gobject.TYPE_STRING)), 'self-current-media-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_PYOBJECT)), + # the filename of the new avatar and a boolean indication if it's changed + # after retrieving it from Msn's server (True) or set by the user (False) 'self-dp-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, - (gobject.TYPE_STRING,)), + (gobject.TYPE_STRING,gobject.TYPE_BOOLEAN)), 'new-conversation' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,gobject.TYPE_PYOBJECT)), @@ -271,7 +273,6 @@ self._allowedRedirects = 5 self._onLogin = False self.canUseP4 = canUseP4 - # login() calls _redirect(), which calls loginInputHandler on socket input, # which calls loginProcess @@ -294,7 +295,7 @@ if self.proxy is None: self.socket = Socket.Socket(host, port) else: - self.socket = Socket.PSocket(host, port, self.proxy) + self.socket = Socket.HTTPSocket(host, port, self.proxy) self.socket.connect('input', self._loginInputHandler) self.socket.connect('hangup', self._loginHangupHandler) @@ -486,8 +487,17 @@ # change the nickname self.changeNick(self.nick, initial=True) + gobject.timeout_add(10000, self.enable_notifications) soap.requests.get_profile(self.proxy, self.cid, self.onGetProfile) + # a delay in case the UUX command doesn't enable notifications + # see "processCommand()" method + def enable_notifications(self): + if not self.canNotify: + self.emit('enable-notifications') + self.canNotify = True + return False + def passportReAuth(self, hash=None): if hash == None: hash = self.hash @@ -763,9 +773,8 @@ # have something to do with this, but this seems safer self.accountConfirmed = False self.emit('account-unconfirmed') - elif command == "PRP" and self.profile_retrieved and not self.canNotify: - self.emit('enable-notifications') - self.canNotify = True + elif command == "UUX" and params == "0" and self.profile_retrieved: + self.enable_notifications() def parseUBX(self, command, tid, params, payload): '''this function parses the UBX payload, and sets the personal diff -Nru emesene-1.6.1/emesenelib/ProfileManager.py emesene-1.6.3~peppermint1/emesenelib/ProfileManager.py --- emesene-1.6.1/emesenelib/ProfileManager.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/emesenelib/ProfileManager.py 2010-08-18 23:28:16.000000000 +0100 @@ -20,6 +20,11 @@ import urllib import base64 import os +import httplib +import socket +import tempfile +import datetime +import time import ContactData import soap.manager @@ -84,6 +89,7 @@ gobject.GObject.__init__(self) self.config = config self.profile_retrieved = False + self.rid = "" def onGetMembershipList(self, response): '''method called when we receive the membership list''' @@ -123,6 +129,9 @@ soap.requests.create_profile(self.proxy, self.reRequestProfile) return + expression_profile = response.body.split('')[0].split('')[1] + self.rid = expression_profile.split('')[0].split('')[1] + try: nick = response.body.split('')[0].split('')[1] nick = common.unescape(nick) @@ -133,43 +142,93 @@ pm = response.body.split('')[0].split('')[1] pm = common.unescape(pm) except: - pm = '' - + pm = '' + + try: + dpurl = response.body.split('')[0].split('')[1] + except: + try: + dpurl = response.body.split('')[0].split('')[1] + except: + dpurl = "" + + photo = response.body.split('')[0].split('')[1] try: - dpurl = response.body.split('')[0].split('')[1] - photo = response.body.split('')[0].split('')[1] self.dpid = photo.split('')[0].split('')[1] - name = photo.split('')[0].split('Name>')[1] except: - dpurl = '' self.dpid = '' - if dpurl != '' and name != self.config.glob['Id']: + try: + modified = (photo.split('')[0].split('')[1])[0:19] + except: + modified = '' + + newAvatar = True + # compare last avatar date and server avatar date, we can't know + # the exact time saved on the server, it's something between the + # time that we sent the request and the time the response arrived + # that's why I compare with seconds of difference (10 is arbitrary) + if modified != '': + serverDate = modified + savedDate = self.config.user['avatarDate'] + + try: + date1 = datetime.datetime(int(serverDate[0:4]), \ + int(serverDate[5:7]), int(serverDate[8:10]), \ + int(serverDate[11:13]), int(serverDate[14:16]), \ + int(serverDate[17:19]),0,None) + date2 = datetime.datetime(int(savedDate[0:4]), \ + int(savedDate[5:7]), int(savedDate[8:10]), \ + int(savedDate[11:13]), int(savedDate[14:16]), \ + int(savedDate[17:19]),0,None) + + delta = 0 + if date2 > date1: + delta = date2 - date1 + else: + delta = date1 - date2 + newAvatar = (delta.seconds > 25 or delta.seconds < -25) + except: + newAvatar = True + + if dpurl != '' and newAvatar: + self.config.user['avatarDate'] = modified gobject.idle_add(self.getPicture, dpurl) self.changeNick(nick, initial=True) self.changePersonalMessage(pm) - self.affinityCache = response.body.split('')[0].split('')[1] - expression_profile = response.body.split('')[0].split('')[1] - self.rid = expression_profile.split('')[0].split('')[1] + + #it seems these are not on the response anymore + try: + self.affinityCache = response.body.split('')[0].split('')[1] + except: + self.affinityCache = '' + try: + name = photo.split('')[0].split('')[1] + except: + name = '' + self.profile_retrieved = True def updateDisplayPicture(self): - if self.affinityCache != '': - if self.dpid != '': - soap.requests.delete_relationship1(self.proxy, self.affinityCache, \ - self.dpid, self.cid, self.onDeleteRelationship1) - else: - soap.requests.update_dp(self.proxy, self.affinityCache, \ - self.cid, self.config.glob['Id'], 'png', \ - base64.b64encode(self.msnobj.data), self.onCreateRelationships) + #if self.affinityCache != '': + if self.dpid != '': + soap.requests.delete_relationship1(self.proxy, self.affinityCache, \ + self.dpid, self.cid, self.onDeleteRelationship1) + else: + soap.requests.update_dp(self.proxy, self.affinityCache, \ + self.cid, self.config.glob['Id'], 'png', \ + base64.b64encode(self.msnobj.data), self.onCreateRelationships) def getPicture(self, url): - import httplib - import socket - hdrs = {"User-Agent": "MSN Explorer/9.0 (MSN 8.0; TmstmpExt)",} - + + if not url.startswith("http://"): + url = "http://byfiles.storage.msn.com/"+url + index = url.find("msn.com") + #remove "http://" and everything after msn.com + server = url[7:index+7] + if self.proxy and self.proxy.host != '': proxy_connect = 'CONNECT %s:%s HTTP/1.0\r\n'%(self.proxy.host, self.proxy.port) user_agent = 'User-Agent: python\r\n' @@ -187,16 +246,15 @@ proxy.sendall(proxy_pieces) response = proxy.recv(8192) status=response.split()[1] - if status!=str(200): + if status!=str(200): raise ValueError,'Error status=%s' % str(status) return False - - conn = httplib.HTTPConnection('byfiles.storage.msn.com', 80) + conn = httplib.HTTPConnection(server, 80) conn.sock = proxy else: - conn = httplib.HTTPConnection('byfiles.storage.msn.com', 80) + conn = httplib.HTTPConnection(server, 80) try: - conn.request("GET", 'http://byfiles.storage.msn.com'+url, headers=hdrs) + conn.request("GET", url, headers=hdrs) response = conn.getresponse() except: return @@ -205,19 +263,16 @@ if stat != 200: # YouFail + print "failed to download avatar" + print "reason: ", reas return False data = response.read() #print "DP:", len(data), stat, reas - if os.name == "nt": - tempfolder = os.environ['TEMP'] + os.sep + "emsnpic" - tempfolder = unicode(tempfolder) - else: - tempfolder = '/tmp/emsnpic' - f = open(tempfolder, 'wb') - f.write(data) - f.close() - self.emit('self-dp-changed', tempfolder) - + fd, fn = tempfile.mkstemp(prefix='emsnpic') + os.write(fd, data) + initial = False + self.emit('self-dp-changed', fn, initial) + return False def onSetDP(self, response): @@ -248,8 +303,43 @@ self.onCreateRelationships) def onCreateRelationships(self,response): - #print 'onCreate:'+str(response) + #print 'onCreate:'#+str(response) + #print response.body if response.status[0] == 200: + + # save avatar update time stamp + aux1 = time.gmtime() + date = datetime.datetime(aux1[0], aux1[1], aux1[2], aux1[3], \ + aux1[4], aux1[5]) + + # it looks like msn server's are gmt -7 + delta = datetime.timedelta(hours=-7) + date = date + delta + + # make one-digit numbers start with "0" + year = str(date.year) + if date.month < 10: + month = "".join(("0",str(date.month))) + else: + month = str(date.month) + if date.day < 10: + day = "".join(("0",str(date.day))) + else: + day = str(date.day) + if date.hour < 10: + hour = "".join(("0",str(date.hour))) + else: + hour = str(date.hour) + if date.minute < 10: + minutes = "".join(("0",str(date.minute))) + else: + minutes = str(date.minute) + if date.second < 10: + seconds = "".join(("0",str(date.second))) + else: + seconds = str(date.second) + + self.config.user['avatarDate'] = "".join((year,"-",month,"-",day,"T",hour,":",minutes,":",seconds)) try: document_rid = response.body.split('')[0].split('')[1] soap.requests.create_relationships(self.proxy, self.affinityCache, self.rid, \ @@ -681,10 +771,11 @@ self.socket.sendCommand("PRP", "MFN " + urllib.quote(nick)) - if not initial and self.affinityCache != '': - soap.requests.update_profile(self.proxy, self.affinityCache, \ - self.rid, common.escape(nick), \ - common.escape(self.personalMessage), self.onNickChanged, oldNick) + if not initial: + if self.rid != "":# self.affinityCache != '': + soap.requests.update_profile(self.proxy, self.affinityCache, \ + self.rid, common.escape(nick), \ + common.escape(self.personalMessage), self.onNickChanged, oldNick) def changeAlias(self, user, alias): alias = alias.decode('utf-8', 'replace').encode('utf-8') @@ -741,10 +832,10 @@ oldPm = self.personalMessage self.personalMessage = pm self.updateUUX() - if self.affinityCache != '': - soap.requests.update_profile(self.proxy, self.affinityCache, \ - self.rid, common.escape(self.nick), \ - common.escape(self.personalMessage), self.onPmChanged, oldPm) + #if self.affinityCache != '': + soap.requests.update_profile(self.proxy, self.affinityCache, \ + self.rid, common.escape(self.nick), \ + common.escape(self.personalMessage), self.onPmChanged, oldPm) self.emit('self-personal-message-changed', self.user, pm) else: common.debug("duplicate pm") diff -Nru emesene-1.6.1/htmltextview.py emesene-1.6.3~peppermint1/htmltextview.py --- emesene-1.6.1/htmltextview.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/htmltextview.py 2010-07-12 23:13:14.000000000 +0100 @@ -667,9 +667,7 @@ self._changed_cursor = False self.linkColor = "#0000FF" - self.connect('copy-clipboard', self._on_copy_clipboard) - self.clipboard = gtk.Clipboard(selection=gtk.gdk.atom_intern("CLIPBOARD")) - self.get_buffer().add_selection_clipboard(self.clipboard) + self.connect_after('copy-clipboard', self._on_copy_clipboard) self.emotes = {} self.connect("motion-notify-event", self.__motion_notify_event) @@ -885,8 +883,9 @@ iterStart = iterEnd - self.clipboard.set_text(text) - self.clipboard.store() + clipboard = gtk.clipboard_get() + clipboard.set_text(text) + clipboard.store() def clear(self): self.get_buffer().set_text('') diff -Nru emesene-1.6.1/MainMenu.py emesene-1.6.3~peppermint1/MainMenu.py --- emesene-1.6.1/MainMenu.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/MainMenu.py 2010-07-12 23:13:14.000000000 +0100 @@ -401,7 +401,11 @@ filter.add_pattern('*') chooser.set_current_name(_('myContacts')) chooser.add_filter(filter) - chooser.set_current_folder(os.environ['HOME']) + if os.name != "nt": + folder = os.environ['HOME'] + else: + folder = os.environ['HOMEPATH'] + chooser.set_current_folder(folder) response = chooser.run() if response == gtk.RESPONSE_OK: all_contacts = self.controller.contacts.get_all_contacts() @@ -616,8 +620,8 @@ self.checkbox.connect('toggled', self.on_auto_reply_toggled) response = replyDialog.run() - replyDialog.destroy() response_cb(response, self.entry.get_text()) + replyDialog.destroy() def on_auto_reply_toggled(self, check): self.entry.set_sensitive(check.get_active()) @@ -629,5 +633,5 @@ self.controller.preference_open = True def on_get_live_activate(self, *args): - link = 'https://accountservices.passport.net/reg.srf?sl=1' + link = 'https://signup.live.com/signup.aspx' desktop.open(link) diff -Nru emesene-1.6.1/.pc/20_dont_build_own_libmimic.patch/setup.py emesene-1.6.3~peppermint1/.pc/20_dont_build_own_libmimic.patch/setup.py --- emesene-1.6.1/.pc/20_dont_build_own_libmimic.patch/setup.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/.pc/20_dont_build_own_libmimic.patch/setup.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,209 @@ +#!/usr/bin/python + +from distutils.core import setup, Extension +from glob import glob +import os +import sys + +if os.name == 'posix': + for arg in sys.argv: + if arg == 'install': + print 'Hello.\nYou are trying to do a system-wide install of emesene '\ + 'using this script, which is a very bad thing to do.\n'\ + 'Seriously, you do NOT want to do this, since it can break '\ + 'other python apps, and emesene too!\n'\ + 'Follow my advice: just run the \"emesene\" script that is '\ + 'in this very same directory and you\'re done. emesene is running '\ + 'and your system is safe. It\'s a win-win, don\'t you think?\n'\ + 'Thanks for trying emesene.' + quit() + + # From apport's setup.py + mo_files = [] + for filepath in glob("po/*/LC_MESSAGES/*.mo"): + lang = filepath[len("po/"):] + targetpath = os.path.dirname(os.path.join("share/locale",lang)) + mo_files.append((targetpath, [filepath])) + + libmimic_module = Extension('libmimic', + sources = ['libmimic/' + file for file in ['bitstring.c', + 'colorspace.c', 'deblock.c', 'decode.c', 'encode.c', + 'fdct_quant.c', 'idct_dequant.c', 'mimic.c', 'vlc_common.c', + 'vlc_decode.c', 'vlc_encode.c', 'py_libmimic.c']]) + + setup(name = 'emesene', + version = '1.6', + description = 'MSN messenger client', + author = 'Luis Mariano Guerra, dx, C10uD', + author_email = 'luismarianoguerra@gmail.com', + url = 'http://www.emesene.org/', + license = 'GNU GPL 2', + requires = ['gtk'], + platforms = ['any'], + packages = ['', 'abstract', 'emesenelib', 'emesenelib.p2p', + 'emesenelib.soap', 'plugins_base', + 'plugins_base.currentSong', 'plugins_base.encryptMessage'], + scripts = ['emesene'], + package_data = {'': ['conversation_themes/*/*', 'smilies/*/*', + 'sound_themes/*/*', 'themes/*/*', 'hotmlog.htm']}, + data_files = [('share/pixmaps', ['misc/emesene.png']), + ('share/icons/hicolor/scalable/apps', ['misc/emesene.svg']), + ('share/man/man1', ['misc/emesene.1']), + ('share/applications', ['misc/emesene.desktop'])] + mo_files, + ext_modules = [libmimic_module] + ) +elif os.name == 'nt': + import pygst + pygst.require("0.10") + import gst + + enabled = True + + if not enabled: + print "py2exe setup.py" + print "(disabled, see source)" + raise SystemExit + + import gobject + import locale + import py2exe + + try: + revision = "$Revision $".split()[1] + except: + revision = 0 + version_id = "1.6" + + outdata_base = { + "script": "Controller.py", + "icon_resources": [(1, "../emesene.ico")] + } + + outdata_win = outdata_base.copy() + outdata_win['dest_base'] = "emesene" + + outdata_con = outdata_base.copy() + outdata_con['dest_base'] = "emesene_debug" + + opts = { + 'py2exe': { + 'packages': ['encodings', 'gtk', 'email', 'abstract', 'emesenelib', 'emesenelib.p2p', + 'emesenelib.soap', 'plugins_base', + 'plugins_base.currentSong', 'plugins_base.encryptMessage'], + 'includes': ['locale', 'gst','pygst', 'libxml2', 'poplib','imaplib','sqlite3', 'cairo', 'pangocairo', 'pango', 'atk', 'gobject', + 'os', 'code', 'winsound', 'win32api', 'win32gui', + 'email.iterators', 'email.generator'], + 'excludes': ["ltihooks", "gdk", "pywin", "pywin.debugger", "pywin.debugger.dbgcon", + "pywin.dialogs", "pywin.dialogs.list", + "Tkconstants","Tkinter","tcl", + "doctest","macpath","pdb", + "cookielib","ftplib","pickle", + "calendar","win32wnet","unicodedata", + "getopt","optparse"], + 'dll_excludes': ["libglade-2.0-0.dll", "w9xpopen.exe"], + 'optimize': '2', + 'dist_dir': '../dist', + } + } + + #included plugins list + plugins = [ + "__init__.py", + "Commands.py", + "CurrentSong.py", + "CustomStatus.py", + "EmoticonPlugin.py", + "EncryptedMessage.py", + "Eval.py", + "Facebook.py", + "gmailNotify.py", + "InlineNotify.py", + "LastSaid.py", + "LogConversation.py", + "Logger.py", + "mailChecker.py", + "Notification.py", + "Plugin.py", + "Plus.py", + "PlusColorPanel.py", + "Screenshots.py", + "StatusHistory.py", + "TinyUrl.py", + "WindowTremblingNudge.py" + ,] + + plugins = [ "../emesene/plugins_base/" + p for p in plugins ] + + os.chdir("../emesene") + + files = [] + #individual files + files.append( (".", ("../emesene/hotmlog.htm", "../emesene/COPYING", \ + "../dlls/libxml2-2.dll", "../dlls/msvcr90.dll", "../dlls/Microsoft.VC90.CRT.manifest",\ + "../dlls/jpeg62.dll", "../emesene/GPL", "../emesene/PSF", "../emesene/LGPL")) ) + files.append( ("smilies/default", glob("../emesene/smilies/default/*.*")) ) + + files.append( ("plugins_base", plugins) ) + + files.append( ("plugins_base/currentSong", \ + ["../emesene/plugins_base/currentSong/__init__.py", \ + "../emesene/plugins_base/currentSong/Amarok.py", \ + "../emesene/plugins_base/currentSong/Amarok2.py", \ + "../emesene/plugins_base/currentSong/Audacious.py", \ + "../emesene/plugins_base/currentSong/Banshee.py", \ + "../emesene/plugins_base/currentSong/CurrentSong.py", \ + "../emesene/plugins_base/currentSong/Exaile.py", \ + "../emesene/plugins_base/currentSong/Listen.py", \ + "../emesene/plugins_base/currentSong/Mpd.py", \ + "../emesene/plugins_base/currentSong/QuodLibet.py", \ + "../emesene/plugins_base/currentSong/Rhythmbox.py", \ + "../emesene/plugins_base/currentSong/Vagalume.py", \ + "../emesene/plugins_base/currentSong/Vlc.py", \ + "../emesene/plugins_base/currentSong/Winamp.py", \ + "../emesene/plugins_base/currentSong/Xfmedia.py", \ + "../emesene/plugins_base/currentSong/Xmms.py"]) ) + + files.append( ("plugins_base/encryptMessage", \ + ["../emesene/plugins_base/encryptMessage/__init__.py", \ + "../emesene/plugins_base/encryptMessage/__rijndael.py", \ + "../emesene/plugins_base/encryptMessage/GPG.py", \ + "../emesene/plugins_base/encryptMessage/MainEncryptedMessage.py", \ + "../emesene/plugins_base/encryptMessage/Rijndael.py"]) ) + + #gtk file structure + + #directories with variable contents + for i in glob("../emesene/po/*"): + files.append( (i.split("/emesene/")[1] + '/LC_MESSAGES', glob(i+"/LC_MESSAGES/*")) ) + + for i in glob("../emesene/conversation_themes/*"): + files.append( (i.split("/emesene/")[1], glob(i+"/theme")) ) + + for i in glob("../emesene/themes/*"): + files.append( (i.split("/emesene/")[1], glob(i+"/*.*")) ) + + for i in glob("../emesene/sound_themes/*"): + files.append( (i.split("/emesene/")[1], glob(i+"/*.*")) ) + + libmimic_module = Extension('libmimic', + sources = ['libmimic/' + file for file in ['bitstring.c', \ + 'colorspace.c', 'deblock.c', 'decode.c', 'encode.c', \ + 'fdct_quant.c', 'idct_dequant.c', 'mimic.c', 'vlc_common.c', \ + 'vlc_decode.c', 'vlc_encode.c', 'py_libmimic.c']]) + + setup( + name="emesene", + version=version_id, + description = 'MSN messenger client', + author = 'Luis Mariano Guerra, dx, C10uD', + author_email = 'luismarianoguerra@gmail.com', + url = 'http://www.emesene.org/', + license = 'GNU GPL 2', + requires = ['gtk'], + windows=[outdata_win], + console=[outdata_con], + options=opts, + data_files=files, + ext_modules = [libmimic_module]) + + print "Done! Files are here: ../dist/" diff -Nru emesene-1.6.1/.pc/21_svn2451_fix_avatar.patch/Controller.py emesene-1.6.3~peppermint1/.pc/21_svn2451_fix_avatar.patch/Controller.py --- emesene-1.6.1/.pc/21_svn2451_fix_avatar.patch/Controller.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/.pc/21_svn2451_fix_avatar.patch/Controller.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,1030 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This file is part of emesene. +# +# Emesene is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# emesene is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with emesene; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import os +# needed for osx # +import pygtk +pygtk.require('2.0') +################## +import gtk +import sys +import time +import thread +import gobject +import gettext +import weakref +import traceback + +import paths + +if os.path.exists("default.mo"): + gettext.GNUTranslations(open("default.mo")).install() +elif os.path.exists(paths.LANG_PATH): + gettext.install('emesene', paths.LANG_PATH) +else: + gettext.install('emesene') + +import Theme +import Avatar +import Config +import desktop +import TrayIcon +import MainWindow +import StatusMenu +import SlashCommands +import Sound +import PluginManager +import ConversationManager +import ConversationLayoutManager +from Parser import UnifiedParser +from CustomEmoticons import CustomEmoticons + +import emesenelib.common +from emesenelib import core +from emesenelib import Socket +from emesenelib import Hotmail + +import stock +import dialog +import abstract.stock as stock +import GroupManager +import ContactManager +from AvatarHistory import AvatarHistoryViewer + +from SingleInstance import SingleInstance + +SERVER_HOST = 'messenger.hotmail.com' + +class Controller(gobject.GObject): + '''The Controller class concentrate all the logic of the program + leaving the other classes to only implement the GUI. + All the classes with GUI should receive a Controller instance to + be able to do things.''' + + # suprise, most of these signals should be refactored + __gsignals__ = { + #'font-changed', font, bold, italic, pangoDesc.get_size() / pango.SCALE + 'font-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + (gobject.TYPE_STRING, gobject.TYPE_BOOLEAN, gobject.TYPE_BOOLEAN, + gobject.TYPE_INT)), + #'color-changed', '#%02X%02X%02X' % (red, green, blue) + 'color-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + (gobject.TYPE_STRING,)), + 'input-format-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT,)), + 'avatar-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + ()), + 'preferences-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + ()), + 'usermenu-item-add' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT,)), + + 'message-read' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + ()), + } + + def __init__(self, username, minimized, leakdebug, iconified, badroot, singleinstance): + '''Constructor''' + gobject.GObject.__init__(self) + + self.NAME = 'emesene' + self.VERSION = '1.6.3 - "Uberlândia"' + self.COPYRIGHT = 'Luis Mariano Guerra, dx, C10uD, arielj' + self.COMMENT = _('A client for the WLM%s network') % u'\u2122' + self.LICENSE_FALLBACK = 'GNU General Public License' + self.WEBSITE = 'http://www.emesene.org' + self.BUGTRACKER = 'http://forum.emesene.org/index.php/board,19.0.html' + self.AUTHORS = [ + 'Luis Mariano \'wariano\' Guerra (emesene and emesenelib)', \ + 'dequis \'dx\' (emesene and emesenelib)', \ + 'Horacio Duran (emesene and emesenelib)', \ + 'Alberto Talavera (emesene)', \ + 'Linan Wang (MsnOIM)', \ + 'Roberto Salas & Jakub Steiner (tango theme)', \ + 'Vinicius Depizzol (default theme)', \ + 'Yguaratã C. Cavalcanti (emesene)', \ + 'Roger \'roger\' Duran (emesene)', \ + 'Alen \'alencool\' (emesene and cairo wizzard :P)', \ + 'Mattia \'MaTz\' Pini (emesene)', \ + '\'mg\' (emesene)', \ + 'Jan \'jandem\' de Mooij (emesene and emesenelib)', \ + 'j0hn \'juan\' (emesene)', \ + 'Luis \'JoinTheHell\' Nell (emesene)', \ + 'nopersona (in the margins theme)', \ + 'Stéphane \'kjir\' Bisinger (webcam)', \ + 'Kevin Campbell (pyisf)', \ + 'Riccardo \'C10uD\' (emesene)', \ + 'Giuseppe Bagnato (proxy)', \ + 'Orfeo \'Otacon\' (emesene)', \ + 'Davide \'Boyska\' (plugins)', \ + '\'x1sc0\' (emesene)', \ + 'Nicolas \'nicolaide\' Espina Tacchetti (emesene)', \ + 'Emilio \'pochu\' Pozuelo Monfort (debian)', \ + 'Bartłomiej Jerzy \'bjfs\' Stobiecki (ppa)', \ + 'Pablo \'pablo\' Mazzini (emesene and emesenelib)', \ + 'scyx (emesene)', \ + 'arielj (emesene)', \ + 'Victor C. (gnome-colors theme)', \ + 'GrinningArmor (emesene)', \ + 'x-warrior (emesene)', \ + 'Tom \'ukblackknight\' (emesene)', \ + 'Stefano \'Cando\' Candori (emesene)', \ + 'All the fantastic emesene community (all)', \ + ] + + # this statuses are not available in wlm anymore + self.bad_statuses = [ 'BRB', 'PHN', 'LUN', 'FLN' ] + + self.status_ordered = [ + [ 'NLN', 'AWY', 'BSY', 'BRB', 'PHN', 'LUN', 'HDN', 'IDL', 'FLN' ], + + [ 'online', 'away', 'busy', 'away', 'busy', + 'away', 'invisible', 'idle', 'offline' ], + + [ _('Online'), _('Away'), _('Busy'), _('Away'), + _('Busy'), _('Away'), _('Invisible'), + _('Idle'), _('Offline') ], + + [ _('_Online'), _('_Away'), _('_Busy'), _('_Away'), + _('_Busy'), _('_Away'), _('_Invisible'), + _('I_dle'), _('O_ffline') ] + ] + + self.connected = False + self.userEmail = None + self.userStatus = None + self.reconnectTimerId = None + + self.config = Config.Config() + self.config.connect('change::debug', self.updateDebug) + self.config.connect('change::binary', self.updateDebug) + desktop.override = self.config.glob['overrideDesktop'] + + self.theme = Theme.Theme(self.config, 'default', 'default') + self.mainWindow = MainWindow.MainWindow(self) + self.mainWindow.set_wmclass('emesene', 'emesene') + self.gtk_screen = self.mainWindow.get_screen() + + use_rgba_colormap = (gtk.gtk_version >= (2, 10, 0) and + self.config.glob['rgbaColormap']) + + if use_rgba_colormap: + colormap = self.gtk_screen.get_rgba_colormap() + if colormap: + gtk.widget_set_default_colormap(colormap) + + self.mainWindow.realize() + # ####################################### # + # we use this crap in our awesome bars :D # + # this is assigned as soon as our colors # + # are ready in # + # mainwindow.userlist.tooltips # + self.tooltipColor = None + self.niceBarWarningColor=gtk.gdk.Color(57600,23040,19712) + # ####################################### # + self.widget_style = self.mainWindow.get_style() + self.unifiedParser = UnifiedParser(self.theme) + + self.conversationLayoutManager = \ + ConversationLayoutManager.ConversationLayoutManager(self) + self.conversationManager = \ + ConversationManager.ConversationManager(self) + + self.contacts = ContactManager.ContactManager(dialog, None, None) + self.groups = GroupManager.GroupManager(dialog, None) + + # "with" would be interesting here + if use_rgba_colormap: + gtk.widget_push_colormap(self.gtk_screen.get_rgb_colormap()) + if not TrayIcon.disabled: + self.trayIcon = TrayIcon.TrayIcon(self) + if use_rgba_colormap: + gtk.widget_pop_colormap() + + if TrayIcon.disabled or not (minimized or self.config.glob['startup'] == 'minimize'): + if iconified or self.config.glob['startup'] == 'iconify' and not self.config.glob['disableTrayIcon']: + self.mainWindow.iconify() + else: + self.mainWindow.show() + if minimized or self.config.glob['startup'] == 'minimize': + self.mainWindow.show() + self.mainWindow.iconify() + + self.pluginManager = None + + gtk.gdk.set_program_class('emesene') + gtk.window_set_default_icon_list(\ + self.theme.getImage('icon16'), self.theme.getImage('icon32'), + self.theme.getImage('icon48'), self.theme.getImage('icon96')) + + self.msn = None + self.lastILN = 0 + self.pendingAvatars = {} + + self.trayDisconnect = None + self.traySeparator = None + self.trayStatusMenu = None + + self.avatar = None + self.cancel = False + self.reconnecting = False + self.preference_open = False + self.addBuddy = None + + self.leakdebug = leakdebug + + if username in self.mainWindow.login.users.getUsers(): + user = username + self.mainWindow.login.getPreferences(user) + pwd = self.mainWindow.login.getPass() + status = self.mainWindow.login.getStatus() + elif self.config.glob['autoLogin']: + user = self.mainWindow.login.getUser() + pwd = self.mainWindow.login.getPass() + status = self.mainWindow.login.getStatus() + else: + user = '' + pwd = '' + + if user != '' and pwd != '': + self.login(user, pwd, status) + + def login(self, user, password, status): + '''do the login''' + + self.reconnecting = (self.mainWindow.currentInterface == 'reconnect') + self.cancel = False + self.userEmail = user + self.userStatus = status + self.mainWindow.buildInterface('loading') + self.config.setCurrentUser(user) + + if not self.config.glob['debug']: + print "If you are reading this, you may want to enable debug" + print "It's the first option in the advanced page in preferences" + + server = SERVER_HOST + proxy = None + + if self.config.glob['useProxy']: + proxy = Socket.Proxy(self.config.glob['proxyHost'], \ + self.config.glob['proxyPort'], \ + self.config.glob['proxyUsername'], \ + self.config.glob['proxyPassword']) + else: + if self.config.glob['httpMethod']: + proxy = Socket.Proxy() + + + # messenger.hotmail.com + self.msn = core.Msnp(server, 1863, user, password,\ + self.config.getUserConfigPath(), proxy, \ + self.config.user['receiveP4context'], self.config) # ugly, but i'm lazy + + self.msn.setDebug(self.config.glob['debug'], + self.config.glob['binary']) + + self.msn.connect('login-error', self.on_login_error, password) + self.msn.connect('login-successful', self.on_login_successful) + gobject.timeout_add(2000, self.trayicon_effect) + + self.contacts = ContactManager.ContactManager( + dialog, self.msn, self.userEmail) + self.groups = GroupManager.GroupManager( + dialog, self.msn) + + self.msn.login() + + def trayicon_effect(self): + '''Create an animation effect in the trayicon''' + if not TrayIcon.disabled and (self.msn and not self.msn.connected): + if self.trayIcon.status == 'login': + self.trayIcon.update('disconnected') + else: + self.trayIcon.update('login') + else: + return False + + def on_login_error(self, msn, message, password): + '''Callback to login-error signal''' + if not self.msn: + return False + if not self.reconnecting: + if self.config.glob['autoLogin']: + self.autoReconnect(self.userEmail, password, self.userStatus) + else: + text = _('Error during login, please retry') + \ + '\n(' + message + ')' + self.goToLoginWindow() + self.mainWindow.showNiceBar(text,self.niceBarWarningColor, gtk.STOCK_DIALOG_WARNING) + else: + self.autoReconnect(self.userEmail, password, self.userStatus) + + def cancelLogin(self): + try: + self.msn.logout() + except Exception, e: + print "Exception at logout", e + self.goToLoginWindow() + if self.reconnectTimerId is not None: + gobject.source_remove(self.reconnectTimerId) + self.reconnectTimerId = None + + def goToLoginWindow(self): + self.config.setCurrentUser('') + self.mainWindow.buildInterface('login') + self.msn = None + self.pluginManager = None + + def on_login_successful(self, msn): + if self.reconnectTimerId is not None: + gobject.source_remove(self.reconnectTimerId) + self.reconnectTimerId = None + self.connected = True + self.pendingAvatars = {} + self.idleTimeout = 0 + + if not (self.theme.setTheme(self.config.user['theme'], + self.config.user['smallIcons']) and + self.theme.smilies.setTheme(self.config.user['smilieTheme'])): + self.config.user['theme'] = 'default' + self.config.user['smilieTheme'] = 'default' + dialog.error(_("Error loading theme, falling back to default")) + else: + self.mainWindow.rebuild() + if self.trayStatusMenu: + self.trayStatusMenu.set_submenu(StatusMenu.StatusMenu(self)) + self.trayIcon.menu.show_all() + self.trayIcon.update(self.msn.status) + + self.msn.changeStatus(self.userStatus) + + self.msn.connect('disconnected', self.disconnected) + self.msn.connect('connection-closed', self.on_connection_closed) + self.msn.connect('error', self.on_msnp_error) + self.msn.connect('exception', self.on_msnp_exception) + sys.excepthook = self.except_hook_dialog + + # FIXME: strange issue with avatars + self.changeAvatar(self.config.user['avatarPath'],initial=True) + self.mainWindow.buildInterface('userlist') + self.changeAvatar(self.config.user['avatarPath'],initial=True) + + layout = self.config.user['conversationLayout'] + if not self.conversationLayoutManager.load(layout): + self.conversationLayoutManager.setDefault() + + # menu items only available when connected + if not self.trayStatusMenu and not TrayIcon.disabled: + statusMenuItem = gtk.MenuItem(_('_Status')) + statusMenu = StatusMenu.StatusMenu(self) + statusMenuItem.set_submenu(statusMenu) + separator = gtk.SeparatorMenuItem() + secondSeparator = gtk.SeparatorMenuItem() + plugins = self.mainWindow.menu.newImageMenuItem('P_lugins',gtk.STOCK_EXECUTE) + plugins.connect('activate', self.mainWindow.menu.on_plugin_activate) + preferences = gtk.ImageMenuItem(gtk.STOCK_PREFERENCES) + preferences.connect('activate', self.mainWindow.menu.on_preferences_activate) + about = gtk.ImageMenuItem(gtk.STOCK_ABOUT) + about.connect('activate', self.mainWindow.menu.on_about_activate) + disconnect = gtk.ImageMenuItem(gtk.STOCK_DISCONNECT) + disconnect.connect('activate', self.on_tray_disconnect) + + self.trayDisconnect = disconnect + self.traySeparator = separator + self.trayPlugins = plugins + self.trayPreferences = preferences + self.trayAbout = about + self.trayStatusMenu = statusMenuItem + self.traySecondSeparator = secondSeparator + + #Slash Command Handler + self.Slash = SlashCommands.SlashCommands(self) + + # add here + if self.config.user['enableSounds'] == True: + self.sound = Sound.SoundHandler(self, self.msn, action='start') + else: + self.sound = Sound.SoundHandler(self, self.msn, action=None) + + if not TrayIcon.disabled: + # REMEMBER to remove them when disconnect + self.trayIcon.menu.prepend(self.trayDisconnect) + self.trayIcon.menu.prepend(self.traySecondSeparator) + self.trayIcon.menu.prepend(self.trayAbout) + self.trayIcon.menu.prepend(self.trayPreferences) + self.trayIcon.menu.prepend(self.trayPlugins) + self.trayIcon.menu.prepend(self.traySeparator) + self.trayIcon.menu.prepend(self.trayStatusMenu) + self.trayIcon.menu.show_all() + self.trayIcon.update(self.msn.status) + + self.pluginManager = PluginManager.PluginManager(self) + gobject.idle_add(self.pluginManager.startActivePlugins) + + self.msn.connect('initial-status-change', self.onInitialStatusChange) + self.msn.connect('display-picture-changed', + self.on_display_picture_changed) + self.msn.connect('new-conversation', self.newConversation) + self.msn.connect('user-attr-changed', self.on_user_attr_changed) + self.msn.connect('self-status-changed', self.on_self_status_changed) + self.msn.connect('self-dp-changed', self.on_change_avatar) + self.msn.connect('group-attr-changed', self.on_group_attr_changed) + self.msn.connect('add-notification', self.addNotification) + self.msn.connect('user-list-change', self.refreshUserList) + self.msn.connect('user-disconnected', self.userDisconnected) + self.msn.connect('connection-problem', self.connectionProblem) + + self.msn.connect('offline-message-waiting', self.offlineMessageWaiting) + self.msn.connect('offline-message-received', + self.offlineMessageReceived) + + self.msn.connect('send-message-error', self.messageError) + self.msn.connect('msnobj-changed', self.msnobjChanged) + + self.hotmail = Hotmail.Hotmail(self.msn, self.config) + self.customEmoticons = CustomEmoticons(self.config, self) + + self.conversationManager.handleLogin(self.userEmail) + + gobject.idle_add(self.checkPending) + self.cancel = False + self.reconnecting = False + + def disconnected(self, msnp): + '''called when a error occurs and we cant keep connected.''' + self.logout(False, True) + + def on_connection_closed(self, msnp): + '''called when a connection error happens''' + self.logout(False, True) + + def on_msnp_error(self, msnp, error, description): + '''called when there is an error during some msnp operation''' + dialog.error(description) + + def on_msnp_exception(self, msnp, exception): + '''called when there is an error in msn.process''' + lines = traceback.format_exception(*exception) + + message = _('%(1)sException%(2)s' \ + 'You are using %(name)s %(version)s so you\'re free to complain here:\n%(bugtracker)s\n' \ + 'Check already existing tickets for duplicates first, please.'\ + % {'1': '', '2': '\n', \ + 'name': self.NAME, 'version': self.VERSION, 'bugtracker': self.BUGTRACKER}) + + for line in lines: + message += '\n' + emesenelib.common.escape(line) + + dialog.exception(message) + + def except_hook_dialog(self, *exception): + '''replaces sys.excepthook displaying a dialog + this is only for unhandled exceptions''' + + traceback.print_exception(*exception) + if exception[0] != KeyboardInterrupt: + gobject.idle_add(self.on_msnp_exception, None, exception) + + def on_user_attr_changed(self, userlist, contact): + self.mainWindow.userList.updateContact(contact) + + def on_display_picture_changed(self, msnp, switchboard, msnobj, email): + contact = self.getContact(email) + if contact: + self.mainWindow.userList.updateContact(contact) + else: + debug('contact not found on contact list!') + + def on_group_attr_changed(self, msnp, oldGroup, newGroup): + self.mainWindow.userList.updateGroup(oldGroup, newGroup) + # canhastestsirkthxbai + # self.refreshUserList() + + def removeGroup(self, group): + #asks the user before removing the group + def remove_cb(response, group): + if response == stock.YES: + if not isinstance(group, basestring): + group = group.name + self.groups.remove(group) + + message = _('Are you sure you want to remove this group?') + dialog.yes_no(message,remove_cb, group) + + def autoReconnect(self, user, password, status): + self.mainWindow.buildInterface('reconnect') + self.mainWindow.login.setFieldValues(user, password, status) + + self.reconnectAfter = 30 + if self.reconnectTimerId is None: + self.reconnectTimerId = gobject.timeout_add(1000, \ + self.updateReconnectTimer) + + self.updateReconnectTimer() + + def updateReconnectTimer(self): + ''' updates reconnect label and launches login if counter is 0 ''' + self.reconnectAfter -= 1 + + if self.mainWindow.login is not None: #fixes n fucking messages after n failed reconnects + self.mainWindow.login.setReconnectCounter(self.reconnectAfter) + + if self.reconnectAfter <= 0: + gobject.source_remove(self.reconnectTimerId) + self.reconnectTimerId = None + self.mainWindow.login.login() + return False + else: + return True + + def cancelReconnect(self): + gobject.source_remove(self.reconnectTimerId) + self.reconnectTimerId = None + self.reconnectAfter = None + self.mainWindow.buildInterface('login') + + def logout(self, closeConversations = True, autoReconnect = False): + '''do the logout''' + + if closeConversations: + self.conversationManager.closeAll() + else: + self.conversationManager.disableAll() + + if self.pluginManager: + self.pluginManager.destroy() + self.pluginManager = None + + # cleanup modules that require msn + self.hotmail = None + self.customEmoticons = None + if self.Slash: + self.Slash.unregister_slash() + self.Slash = None + + self.mainWindow.buildInterface('login') + + if autoReconnect and self.msn: + status = emesenelib.common.reverse_status[self.msn.status] + self.autoReconnect(self.msn.user, self.msn.password, status) + + self.connected = False + self.contacts = ContactManager.ContactManager(dialog, None, None) + self.groups = GroupManager.GroupManager(dialog, None) + self.groups = None + self.lastILN = 0 + + if not TrayIcon.disabled: + try: + self.trayIcon.menu.remove(self.trayDisconnect) + self.trayIcon.menu.remove(self.traySeparator) + self.trayIcon.menu.remove(self.traySecondSeparator) + self.trayIcon.menu.remove(self.trayStatusMenu) + self.trayIcon.menu.remove(self.trayPlugins) + self.trayIcon.menu.remove(self.trayPreferences) + self.trayIcon.menu.remove(self.trayAbout) + self.trayIcon.menu.remove(self.sound.checkBox) + self.trayIcon.update('disconnected') + except: + pass + + if self.msn: + self.msn.logout() + weakmsn = weakref.ref(self.msn) + self.msn = None + else: + return + + if weakmsn(): + print "warning: there are still some references to emesenelib" + print "references to msn:", sys.getrefcount(weakmsn()) -1 + else: + print "yay msn got gc'd" + + if self.leakdebug: + print "cheat sheet: r(o) == gc.get_referrers(o)" + print " to create a msn reference: weakmsn()" + print + import code, readline, gc + r = gc.get_referrers + code.InteractiveConsole(locals()).interact(\ + "Entering controller.msn leak debug console") + + hotmail_file = os.path.join(paths.CONFIG_DIR, \ + self.config.getCurrentUser(), "cache", "login.htm") + + if os.path.isfile(hotmail_file): + try: + os.remove(hotmail_file) + except: + pass + + def quit(self, status): + '''close the window, and do all the things needed...''' + + # makes it more responsive to the user by effectively hiding the + # the window before disconnecting and quitting + #self.mainWindow.connect('unmap-event', self.on_main_hidden, status) + self.mainWindow.hide() + if not TrayIcon.disabled: + self.trayIcon.remove() + + try: + self.mainWindow.saveToQuit() + except: + pass + + if self.connected: + self.logout() + #self.msn.logout() + self.config.writeUserConfig() + + self.config.writeGlobalConfig() + sys.exit(status) + + def checkPending(self): + '''Check for users pending to be added''' + + if self.msn is None: + return False + + if self.addBuddy is None: + self.addBuddy = dialog.AddBuddy(self) + + users = self.msn.checkPending() + if len(users) > 0: + for mail in users: + nick = self.msn.getUserDisplayName(mail) + self.addBuddy.append(nick, mail) + return False + + def set_picture_dialog(self): + ''' Shows a dialog to change personal avatar ''' + def _on_picture_selected(response, path): + '''method called on avatar selected''' + if response == stock.ACCEPT: + self.changeAvatar(path) + elif response == stock.CLEAR: + self.changeAvatar('') + + avatar_cache = self.config.getAvatarsCachePath() + path_current = self.config.user['avatarPath'] + dialog.set_picture(self, path_current, avatar_cache, _on_picture_selected) + + def change_profile_dialog(self): + '''shows a dialog to change nick, personal message and avatar''' + + def responseProfile(response, nick, psm, avatarPath): + '''response if user accepts or denys the profile dialog''' + if response == stock.ACCEPT: + self.contacts.set_nick(nick) + self.contacts.set_message(psm) + if avatarPath != self.config.user['avatarPath']: + self.changeAvatar(avatarPath) + + nick=self.msn.nick.replace('\n', ' ') + psm=self.msn.personalMessage.replace('\n', ' ') + currentAvatarPath = self.config.user['avatarPath'] + dialog.show_profile(self, nick, psm, currentAvatarPath, responseProfile) + + def on_change_avatar(self, msnp, filename, initial=False): + '''control if the avatar already exists or save the new avatar''' + if os.path.exists(filename): + self.changeAvatar(filename, initial) + return + else: + return + + def changeAvatar(self, filename, initial=False): + if not self.msn: + return + + if not filename or not os.path.exists(filename): + filename = '' + try: + self.avatar = Avatar.Avatar(self, filename, + self.config.getAvatarsCachePath()) + filename = self.avatar.getImagePath() + except: # may be GError + return + + if filename == '': + self.mainWindow.setAvatar(self.theme.getImage('userPanel')) + self.config.user['avatarPath'] = '' + else: + self.mainWindow.setAvatar(self.avatar.getThumb()) + self.config.user['avatarPath'] = self.avatar.getImagePath() + + # if not initial, update avatar on Msn's servers + if not initial: + self.msn.setDisplayPicture(filename) + + self.emit('avatar-changed') + + def on_self_status_changed(self, msn, status): + '''called when our status changes''' + if not TrayIcon.disabled: + self.trayIcon.update(self.msn.status) + + def addUserDialog(self, toGroup=None): + '''show a dialog requesting the email of the ser to be added''' + def add_contact_cb(response, account='', group='', alias=''): + '''callback for the add_contact dialog''' + if response == stock.ACCEPT: + account = account.strip() + if len(account.split('@')) == 2: + if group != '' and not group in self.groups.groups.keys(): + self.groups.add(group) + self.contacts.add(account, group, *(self.delayedAlias, account, alias)) + else: + dialog.warning(_("Invalid account")) + + dialog.add_contact(self.groups.groups.keys(), None, add_contact_cb, self.theme.getImage('login')) + + def delayedAlias(self, account, alias): + self.contacts.set_alias(account, alias) + return False + + def addNotification(self, msnp, command, tid, params, email, nick): + '''this method is called when a user adds you''' + + if self.addBuddy is None: + self.addBuddy = dialog.AddBuddy(self) + + self.addBuddy.append(nick, email) + + def refreshUserList(self, *args): + '''call to refreshUserList on MainWindow that calls refresh on userList + userList get the values of showOffline etc from config, so if you want + to change something, change it on config. + if it's loading contacts (ILN), don't do anything''' + if self.lastILN == 0 or (time.time() - self.lastILN) > 1: + self.mainWindow.refreshUserList() + self.lastILN = 0 + + # signal handlers + def connectionProblem(self, msnp): + '''called when a PNG is not answered''' + self.logout(False, True) + + def onInitialStatusChange(self, msnp, command, tid, params): + '''callback for ILN messages. saves the timestamp to speed up login''' + self.lastILN = time.time() + + def onStatusChange(self, msnp, command, tid, params): + '''callback for the status change event''' + self.refreshUserList() + + def on_tray_disconnect(self, *args): + self.logout() + + def msnobjChanged(self, msnp, msnobj, wasOffline): + '''callback called when the user change his msnobj''' + #if msnobj and not wasOffline: + if msnobj: + creator = msnobj.getCreator() + contact = self.getContact(creator) + if (not creator or not contact) or \ + self.theme.hasUserDisplayPicture(contact): + return + + self.pendingAvatars[msnobj.getCreator()] = msnobj + + if not self.idleTimeout: + self.idleTimeout = gobject.timeout_add(5000, \ + self.idleadd, priority=gobject.PRIORITY_LOW) + + def idle(self): + '''called when the gobject mainloop is idle + gobjects thinks that it means "all the time" so we add a + five-second non-blocking delay''' + + stop = True + + if len(self.pendingAvatars.keys()) > 0 and self.msn: + + # pop a pending avatar + creator = self.pendingAvatars.keys().pop(0) + msnobj = self.pendingAvatars[creator] + contact = self.getContact(creator) + + requested = False + + # get a switchboard connection + if contact and not self.theme.hasUserDisplayPicture(contact): + # TODO: not a switchboard method + sb = self.msn.getSwitchboard(creator) + sb.getDisplayPicture(creator) + requested = True + elif contact: + self.msn.emit("display-picture-changed", None, msnobj, creator) + + # delete from pending + del self.pendingAvatars[creator] + + # if there are no more avatars left, stop + stop = len(self.pendingAvatars.keys()) == 0 + if not stop and not requested: + return self.idle() + + if not stop: + # wait 20 seconds without blocking + self.idleTimeout = gobject.timeout_add(20000, \ + self.idleadd, priority=gobject.PRIORITY_LOW) + return False + + def idleadd(self, *args): + '''called 5 seconds after last idle call''' + self.idleTimeout = 0 + gobject.idle_add(self.idle, priority=gobject.PRIORITY_LOW) + return False + + def newConversation(self, msnp, mail, switchboard=None, weStarted=False): + '''This method is called when the user want to initiate a new + conversation with someone, or when a switchboard has been created + and we want to give a window to it. + (callback for 'new conversation' signal emmited by msnp) + weStarted is a boolean that indicate if we started the conversation or + a friend''' + + return self.conversationManager.newConversation(self.msn, mail, \ + switchboard, weStarted) + + def seeAvatarHistory(self, email): + '''opens a dialog with all user's avatars''' + + avatar_cache = self.config.getCachePath() + AvatarHistoryViewer(self,avatar_cache, email).show() + + def seeProfile(self, email): + '''opens the profile url in a browser''' + desktop.open('http://members.msn.com/' + email) + + def offlineMessageWaiting(self, msnp, msnOIM): + '''process the OIM messages''' + msnOIM.retrieve() + + def offlineMessageReceived(self, msnp, oim): + '''process the OIM message''' + user, date, message = oim + window, conv = self.newConversation(msnp, user['addr'], None, False) + self.conversationManager.newest_message_conv = conv + conv.receiveOIM(user['name'], message, date) + + def messageError(self, msnp, to, message, error): + window, conv = self.newConversation(self.msn, to, None, True) + conv.receiveError(msnp, to, message, error) + + def userDisconnected(self, msnp, tid, params): + '''method called when the server disconnect us''' + if tid == 'OTH': + message = _('Logged in from another location.') + else: + message = _('The server has disconnected you.') + + self.logout(False, False) + self.mainWindow.showNiceBar(message,self.tooltipColor) + + def getMenuData(self): + return self.mainWindow.userList.getMenuData() + + # TODO: getters + def getUnreadMails(self): + if self.msn: + return self.msn.inboxUnreadMessages + else: + return 0 + + def getContact(self, mail): + '''return a contact object''' + if not self.msn: + return None + + return self.msn.contactManager.getContact(mail) + + def updateDebug(self, *args): + if self.msn: + self.msn.setDebug(self.config.glob['debug'], \ + self.config.glob['binary']) + +def parseArgs(): + '''parses sys.argv with getopt, returns tuple with Controller args''' + username = '' + minimized = False + leakdebug = False + iconified = False + badroot = False + singleinstance = False + + # parse arguments + try: + import getopt + except ImportError: + #getopt is disabled in emesene py2exe + return ('', False, False, False, False, False) + + shortArgs = 'm,i,f,s' + longArgs = ['iconified', 'minimized', 'user=', 'fast-login', 'leakdebug', + 'i-know-that-running-emesene-as-root-is-bad', 'single-instance'] + try: + args = getopt.getopt(sys.argv[1:], shortArgs, longArgs) + except getopt.GetoptError, e: + # wrong input, display usage + print e + print 'Usage:', sys.argv[0], '[-m|--minimized] | [-i | --iconified] [--user=mail@address]' + print 'Advanced options: [-f|--fast-login], --leakdebug, --i-know-that-running-emesene-as-root-is-bad, [-s|--single-instance]' + sys.exit(1) + + # parse getopt output + for key, value in args[0]: + if key == '--user': + username = value + if key == '-m' or key == '--minimized': + minimized = True + else: + if key == '-i' or key == '--iconified': + iconified = True + if key == '--leakdebug': + leakdebug = True + if key == '--i-know-that-running-emesene-as-root-is-bad': + badroot = True + if key == '-s' or key == '--single-instance': + singleinstance = True + + return (username, minimized, leakdebug, iconified, badroot, singleinstance) + +def debug(msg): + '''print a debug message''' + print 'Controller: ' + msg + +def main(): + args = parseArgs() + + if (os.name == 'posix') and (os.getuid() == 0) and (args[4] == False): + print "I refuse to run as root. " \ + "If you know the risks and still want to do it," \ + " just add the --i-know-that-running-emesene-as-root-is-bad option." + return + + single_instance = SingleInstance() + + if args[5] and single_instance.is_running(): + print "Another instance of emesene is already running. Quitting." + # try to show instance already running + single_instance.show() + sys.exit(0) + + if (os.name != 'nt'): + try: + path = os.path.dirname(__file__) or sys.path[0] + except NameError: + path = sys.path[0] + else: + path = os.path.dirname(sys.path[0]) + + gtk.settings_get_default().set_property("gtk-error-bell", False) + originalPath = os.getcwd() + os.chdir(path) + sys.path.append(path) + # start controller + if (os.name == 'nt') and (hasattr(sys, "frozen")): + controller = Controller('', *args) + else: + controller = Controller(*args) + gobject.threads_init() + # this stuff is to interrupt blocking stuff safely. + for i in range(5): + try: + gtk.gdk.threads_init() + gtk.gdk.threads_enter() + gtk.main() + gtk.gdk.threads_leave() + + except KeyboardInterrupt: + print 'Interrupt (%s more times to close)' % str(5 - i) + else: + break + controller.quit(0) + os.chdir(originalPath) + + + +if __name__ == '__main__': + main() diff -Nru emesene-1.6.1/.pc/21_svn2451_fix_avatar.patch/emesenelib/ProfileManager.py emesene-1.6.3~peppermint1/.pc/21_svn2451_fix_avatar.patch/emesenelib/ProfileManager.py --- emesene-1.6.1/.pc/21_svn2451_fix_avatar.patch/emesenelib/ProfileManager.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/.pc/21_svn2451_fix_avatar.patch/emesenelib/ProfileManager.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,991 @@ +# -*- coding: utf-8 -*- + +# This file is part of emesene. +# +# Emesene is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# emesene is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with emesene; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import gobject +import urllib +import base64 +import os +import httplib +import socket +import tempfile +import datetime +import time + +import ContactData +import soap.manager +import soap.requests +import soap.templates + +import XmlParser + +import common + +# most contact list management stuff is a mess because +# this wasn't written with msnp13 abstraction in mind +# "msnp13 abstraction" is basically separating +# notification and contact list servers + +class ProfileManager(gobject.GObject): + '''this class has all the methods to + modify the contacts, groups, nick and stuff + through SOAP, its made to make Msnp + more modular, also this class can be + changed for other implementation later''' + + __gsignals__ = { + 'user-attr-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT,)), + # olgGroup, newGroup + 'group-attr-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT)), + # email, id, nick, pm, status, alias, blocked + 'contact-added' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT, + gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT, + gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT, + gobject.TYPE_PYOBJECT,)), + # email + 'contact-removed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT,)), + # this signal is emited when WE change an attribute on the user + # the only two attributes that WE can change are alias, and block + # email, attr_name (block, alias), value + 'contact-attr-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT, + gobject.TYPE_PYOBJECT,)), + # name, id + 'group-added' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT)), + # name + 'group-removed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT,)), + # old_name, new_name + 'group-renamed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT)), + # contact, group + 'contact-added-to-group' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT)), + # contact, group + 'contact-removed-from-group' : (gobject.SIGNAL_RUN_LAST, + gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,gobject.TYPE_PYOBJECT)), + } + + def __init__(self, config): + gobject.GObject.__init__(self) + self.config = config + self.profile_retrieved = False + self.rid = "" + + def onGetMembershipList(self, response): + '''method called when we receive the membership list''' + + if response.status[0] == 200: + self.setMembershipListXml(response.body) + self.newCacheFile(self.user + '_ml.xml', response.body) + #self.emit('user-list-change') + + return True + else: + return False + + def onGetAddressBook(self, response): + + if response.status[0] == 200: + self.newCacheFile(self.user + '_ab.xml', response.body) + + self.setAddressBookXml(response.body) + self.cid = getCIDFromDynamicItems(response.body) + self.emit('login-successful') + + return True + else: + return False + + def onGetProfile(self, response): + #print response.body + if response.status[0] != 200 or \ + response.body.find('') == -1: + if self.triedCreatingProfile: + # we already tried, but failed.. :( + self.affinityCache = '' + self.rid = '' + else: + #user doesn't have a roaming profile, try create one. + soap.requests.create_profile(self.proxy, self.reRequestProfile) + return + + expression_profile = response.body.split('')[0].split('')[1] + self.rid = expression_profile.split('')[0].split('')[1] + + try: + nick = response.body.split('')[0].split('')[1] + nick = common.unescape(nick) + except: + nick = '' + + try: + pm = response.body.split('')[0].split('')[1] + pm = common.unescape(pm) + except: + pm = '' + + try: + dpurl = response.body.split('')[0].split('')[1] + except: + try: + dpurl = response.body.split('')[0].split('')[1] + except: + dpurl = "" + + photo = response.body.split('')[0].split('')[1] + try: + self.dpid = photo.split('')[0].split('')[1] + except: + self.dpid = '' + + try: + modified = (photo.split('')[0].split('')[1])[0:19] + except: + modified = '' + + newAvatar = True + # compare last avatar date and server avatar date, we can't know + # the exact time saved on the server, it's something between the + # time that we sent the request and the time the response arrived + # that's why I compare with seconds of difference (10 is arbitrary) + if modified != '': + serverDate = modified + savedDate = self.config.user['avatarDate'] + + try: + date1 = datetime.datetime(int(serverDate[0:4]), \ + int(serverDate[5:7]), int(serverDate[8:10]), \ + int(serverDate[11:13]), int(serverDate[14:16]), \ + int(serverDate[17:19]),0,None) + date2 = datetime.datetime(int(savedDate[0:4]), \ + int(savedDate[5:7]), int(savedDate[8:10]), \ + int(savedDate[11:13]), int(savedDate[14:16]), \ + int(savedDate[17:19]),0,None) + + delta = 0 + if date2 > date1: + delta = date2 - date1 + else: + delta = date1 - date2 + newAvatar = (delta.seconds > 10 or delta.seconds < -10) + except: + newAvatar = True + + if dpurl != '' and newAvatar: + self.config.user['avatarDate'] = modified + gobject.idle_add(self.getPicture, dpurl) + + self.changeNick(nick, initial=True) + self.changePersonalMessage(pm) + + #it seems these are not on the response anymore + try: + self.affinityCache = response.body.split('')[0].split('')[1] + except: + self.affinityCache = '' + try: + name = photo.split('')[0].split('')[1] + except: + name = '' + + self.profile_retrieved = True + + def updateDisplayPicture(self): + #if self.affinityCache != '': + if self.dpid != '': + soap.requests.delete_relationship1(self.proxy, self.affinityCache, \ + self.dpid, self.cid, self.onDeleteRelationship1) + else: + soap.requests.update_dp(self.proxy, self.affinityCache, \ + self.cid, self.config.glob['Id'], 'png', \ + base64.b64encode(self.msnobj.data), self.onCreateRelationships) + + def getPicture(self, url): + hdrs = {"User-Agent": "MSN Explorer/9.0 (MSN 8.0; TmstmpExt)",} + + if not url.startswith("http://"): + url = "http://byfiles.storage.msn.com/"+url + index = url.find("msn.com") + #remove "http://" and everything after msn.com + server = url[7:index+7] + + if self.proxy and self.proxy.host != '': + proxy_connect = 'CONNECT %s:%s HTTP/1.0\r\n'%(self.proxy.host, self.proxy.port) + user_agent = 'User-Agent: python\r\n' + if self.proxy.user: + common.debug('>>> using proxy auth user: '+self.proxy.user) + # setup basic authentication + user_pass = base64.encodestring(self.proxy.user+':'+self.proxy.password).replace('\n','') + proxy_authorization = 'Proxy-authorization: Basic '+user_pass+'\r\n' + proxy_pieces = proxy_connect+proxy_authorization+user_agent+'\r\n' + else: + proxy_pieces = proxy_connect+user_agent+'\r\n' + # now connect, very simple recv and error checking + proxy = socket.socket(socket.AF_INET,socket.SOCK_STREAM) + proxy.connect((self.proxy.host,int(self.proxy.port))) + proxy.sendall(proxy_pieces) + response = proxy.recv(8192) + status=response.split()[1] + if status!=str(200): + raise ValueError,'Error status=%s' % str(status) + return False + conn = httplib.HTTPConnection(server, 80) + conn.sock = proxy + else: + conn = httplib.HTTPConnection(server, 80) + try: + conn.request("GET", url, headers=hdrs) + response = conn.getresponse() + except: + return + stat = response.status + reas = response.reason + + if stat != 200: + # YouFail + print "failed to download avatar" + print "reason: ", reas + return False + data = response.read() + #print "DP:", len(data), stat, reas + fd, fn = tempfile.mkstemp(prefix='emsnpic') + os.write(fd, data) + initial = True + self.emit('self-dp-changed', fn, initial) + + return False + + def onSetDP(self, response): + #print 'onSetDP:'+str(response) + if response.status[0] == 500 and not self.firstSetDpFail: + self.firstSetDpFail = True + # delete relationship + soap.requests.delete_relationship1(self.proxy, self.affinityCache, \ + self.dpid, self.cid, self.onDeleteRelationship1) + + def onDeleteRelationship1(self, response): + #print 'onDelete1:'+str(response) + #print response.body + if response.status[0] != 200: + soap.requests.update_dp(self.proxy, self.affinityCache, self.cid, \ + self.config.glob['Id'], 'png', base64.b64encode(self.msnobj.data), + self.onSetDP) + else: + soap.requests.delete_relationship2(self.proxy, self.affinityCache, \ + self.dpid, self.rid, self.onDeleteRelationship2) + + def onDeleteRelationship2(self, response): + #print 'onDelete2:'+str(response) + #print response.body + if response.status[0] == 200: + soap.requests.update_dp(self.proxy, self.affinityCache, self.cid, \ + self.config.glob['Id'], 'png', base64.b64encode(self.msnobj.data), \ + self.onCreateRelationships) + + def onCreateRelationships(self,response): + #print 'onCreate:'#+str(response) + #print response.body + if response.status[0] == 200: + + # save avatar update time stamp + aux1 = time.gmtime() + date = datetime.datetime(aux1[0], aux1[1], aux1[2], aux1[3], \ + aux1[4], aux1[5]) + + # it looks like msn server's are gmt -7 + delta = datetime.timedelta(hours=-7) + date = date + delta + + # make one-digit numbers start with "0" + year = str(date.year) + if date.month < 10: + month = "".join(("0",str(date.month))) + else: + month = str(date.month) + if date.day < 10: + day = "".join(("0",str(date.day))) + else: + day = str(date.day) + if date.hour < 10: + hour = "".join(("0",str(date.hour))) + else: + hour = str(date.hour) + if date.minute < 10: + minutes = "".join(("0",str(date.minute))) + else: + minutes = str(date.minute) + if date.second < 10: + seconds = "".join(("0",str(date.second))) + else: + seconds = str(date.second) + + self.config.user['avatarDate'] = "".join((year,"-",month,"-",day,"T",hour,":",minutes,":",seconds)) + + try: + document_rid = response.body.split('')[0].split('')[1] + soap.requests.create_relationships(self.proxy, self.affinityCache, self.rid, \ + document_rid, self.onFindDocument) + except: + pass + + def onFindDocument(self, response): + #print 'onFind'+str(response) + if response.status[0] == 200: + soap.requests.find_document(self.proxy, self.affinityCache,self.cid,\ + self.onEnd) + + def onEnd(self,response): + #print 'onEnd:'+str(response) + #print response.body + try: + self.dpid = response.body.split('')[0].split('')[1] + except: + #let the dpid as it was before + pass + + def reRequestProfile(self, response): + ''' requests the profile again, after creating it (?) ''' + self.triedCreatingProfile = True + if response.status[0] == 200: + soap.requests.get_profile(self.proxy, self.cid, self.onGetProfile) + + def addUser(self, email, group, *callback_and_args): + '''add an user to the friend list''' + + if self.contactManager.contact_exists(email): + # We already have that contact + return + + self.sendDL('ADL', email, '1') + self.sendDL('ADL', email, '2') + + # need to add it in prevention of ILN. Don't update user list + self.contactManager.addNewContact(email) + soap.requests.add_contact(self.proxy, email, self.onUserAdded, email, \ + group, callback_and_args) + + def onUserAdded(self, response, email, group, *callback_and_args_triple): + '''this method is called when the addUser soapRequest get a response''' + + common.debug('add user: ' + email + ' ' + str(response.status)) + + if response.status[0] == 200: + # Now that we have the contact id, we show it + self.contactManager.setContactIdXml(email, response.body) + guid = response.body.split('')[1].split('')[0] + self.emit('contact-added', email, guid, None, None, 'FLN', None, + False) + + if group == '': + self.emit('user-list-change') + else: + # once we now the id we can add it to a group + self.addUserToGroup(email, group) + if len(callback_and_args_triple[0]) == 3: # alias hack foo(bar, lol) + func, acco, alias = callback_and_args_triple[0] + if alias != '': + func(acco, alias) + else: + self.contactManager.removeContact(email) + self.emit('user-list-change') + self.emit('error', 'user-add-error', + _('User could not be added: %s') % \ + common.parseSoapFault(response)) + + def removeUserFromGroup(self, user, group): + '''remove user from a group''' + + contactID = self.contactManager.getContactId(user) + sourceGid = self.contactManager.getGroupId(group) + + if sourceGid == '' or sourceGid == 'nogroup': + return + + self.contactManager.removeUserFromGroup(user, sourceGid) + self.emit('user-list-change') + + soap.requests.remove_from_group(self.proxy, contactID, sourceGid, + self.onUserRemovedFromGroup, sourceGid, group, user) + + def onUserRemovedFromGroup(self, response, groupId, group, user): + common.debug('remove user from group: ' + str(response.status)) + + if response.status[0] == 200: + self.emit('contact-removed-from-group', user, group) + else: + self.contactManager.addUserToGroup(user, groupId) + self.emit('user-list-change') + self.emit('error', 'user-remove-error', common.parseSoapFault(response)) + + def addUserToGroup(self, user, group): + '''add a user to a group''' + + gid = self.contactManager.getGroupId(group) + contactID = self.contactManager.getContactId(user) + if gid == None: + common.debug('Group not found') + return + if gid in self.contactManager.getContact(user).groups: + common.debug('User already in group') + return + if gid == 'nogroup': + common.debug('Cannot move to no group') + return + + self.contactManager.addUserToGroup(user, gid) + self.emit('user-list-change') + + soap.requests.add_to_group(self.proxy, gid, contactID, self.onUserAddedToGroup, + user, group, gid) + + def onUserAddedToGroup(self, response, user, group, groupId): + common.debug('add user to group: ' + str(response.status)) + + if response.status[0] == 200: + self.emit('contact-added-to-group', user, group) + else: + self.contactManager.removeUserFromGroup(user, groupId) + self.emit('user-list-change') + self.emit('error', 'user-add-to-group-error', \ + _('User could not be added to group: %s') % \ + common.parseSoapFault(response)) + + def moveUserToGroup(self, user, srcGroup, destGroup, stage=0): + '''move a user from a group erasing it from de source group''' + + if stage == 0: + contactID = self.contactManager.getContactId(user) + sourceGid = self.contactManager.getGroupId(srcGroup) + destGid = self.contactManager.getGroupId(destGroup) + + # moving to/from No group = adding to destGroup / removing from srcGroup + if sourceGid == 'nogroup': + self.addUserToGroup(user, destGroup) + return + if destGid == 'nogroup': + self.removeUserFromGroup(user, srcGroup) + return + + # check whether or not it's an allowed movement + if srcGroup == destGroup: + common.debug('src and dest groups are the same') + return + elif self.contactManager.getGroup(destGid).getUser(user) != None: + common.debug('dest group already contain the user') + return + + # make the visual changes + self.contactManager.removeUserFromGroup(user, sourceGid) + self.contactManager.addUserToGroup(user, destGid) + self.emit('user-list-change') + + # remove the user from the srcGroup + soap.requests.remove_from_group(self.proxy, contactID, sourceGid, + self.onMoveUserToGroup, user, srcGroup, destGroup, 0) + + elif stage == 1: + gid = self.contactManager.getGroupId(destGroup) + contactID = self.contactManager.getContactId(user) + + # add the user to the destGroup + soap.requests.add_to_group(self.proxy, gid, contactID, self.onMoveUserToGroup, + user, srcGroup, destGroup, 1) + + def onMoveUserToGroup(self, response, user, srcGroup, destGroup, stage): + + common.debug('move user (stage ' + str(stage) + '): ' \ + + str(response.status)) + + status = response.status + + if response.status[0] == 200: + if stage == 0: # continue the moving procedure + self.moveUserToGroup(user, srcGroup, destGroup, 1) + else: + # restore the old visual + sourceGid = self.contactManager.getGroupId(srcGroup) + destGid = self.contactManager.getGroupId(destGroup) + + self.contactManager.removeUserFromGroup(user, destGid) + self.contactManager.addUserToGroup(user, sourceGid) + self.emit('user-list-change') + self.emit('error', 'user-move-to-group-error', _('User could not be moved to group: %s') % common.parseSoapFault(response)) + + def removeUser(self, email): + '''remove an user from the friendr list''' + self.sendDL('RML', email, '1') + + contact = self.contactManager.getContact(email) + contactID = self.contactManager.getContactId(email) + soap.requests.remove_contact(self.proxy, contactID, self.onUserRemoved, + email, contact) + + # make the contact not visible + self.contactManager.removeContact(email) + + def removeUserFromPending(self, email): + '''remove an user from the pending list and deny his request''' + self.sendDL('RML', email, '6') + + soap.requests.delete_role(self.proxy, 'Pending', email, \ + self.cb_on_pending_removed, email) + + def cb_on_pending_removed(self, response, email): + '''called when we have the response''' + common.debug('remove pending: ' + email + ' ' + str(response.status)) + + if response.status[0] != 200: + self.removeUser(email) + self.sendDL('RML', email, '6') + soap.requests.delete_role(self.proxy, 'Pending', email, \ + None, None) + + def onUserRemoved(self, response, email, contact): + '''this method is called when the removeUser soapRequest get a response + renes means if we have to renew the di,ml,ab data''' + + common.debug('remove user: ' + email + ' ' + str(response.status)) + + if response.status[0] == 200: + self.emit('contact-removed', email) + else: + self.sendDL('ADL', email, '1') + self.contactManager.addContact(contact) + + self.emit('error', 'user-remove-error', + _('User could not be removed: %s') % + common.parseSoapFault(response)) + self.emit('user-list-change') + + def blockUser(self, email, stage=0): + '''block an user''' + + if stage == 0: + self.sendDL('RML', email, '2') + self.sendDL('ADL', email, '4') + + self.contactManager.blockContact(email) + contact = self.contactManager.getContact(email) + self.emit('user-attr-changed', contact) + + soap.requests.delete_role(self.proxy, 'Allow', email, + self.onUserBlocked, email, 0) + + elif stage == 1: + soap.requests.add_role(self.proxy, 'Block', email, + self.onUserBlocked, email, 1) + + def onUserBlocked(self, response, email, stage): + '''this method is called when the blockUser soapRequest get a response''' + + common.debug('block user (stage ' + str(stage) + '): ' \ + + str(response.status)) + + if response.status[0] == 200: + if stage == 0: # continue the blocking process + self.blockUser(email, 1) + + self.emit('contact-attr-changed', email, 'block', True) + else: + self.unblockUser(email, 0) + self.contactManager.unblockContact(email) + contact = self.contactManager.getContact(email) + self.emit('user-attr-changed', contact) + + def unblockUser(self, email, stage=0): + '''unblock an user''' + + if stage == 0: + self.sendDL('RML', email, '4') + self.sendDL('ADL', email, '2') + + self.contactManager.unblockContact(email) + contact = self.contactManager.getContact(email) + self.emit('user-attr-changed', contact) + + soap.requests.delete_role(self.proxy, 'Block', email, + self.onUserUnblocked, email, 0) + + elif stage == 1: + soap.requests.add_role(self.proxy, 'Allow', email, + self.onUserUnblocked, email, 1) + + def onUserUnblocked(self, response, email, stage): + '''this method is called when the unblockUser soapRequest get a response''' + + common.debug('unblock user (stage ' + str(stage) + '): ' \ + + str(response.status)) + + if response.status[0] == 200: + if stage == 0: + self.unblockUser(email, 1) + + self.emit('contact-attr-changed', email, 'block', False) + else: + self.contactManager.blockContact(email) + contact = self.contactManager.getContact(email) + self.emit('user-attr-changed', contact) + + def addGroup(self, group): + '''add a group to the group list''' + + if self.contactManager.getGroupId(group) != None: + common.debug('Unable to add: Group "' + group \ + + '" already exists') + return + + name = group.replace(' ', '%20') + + soap.manager.do_request(self.proxy,\ + 'http://www.msn.com/webservices/AddressBook/ABGroupAdd', + 'contacts.msn.com', 443, '/abservice/abservice.asmx', + soap.templates.addGroup % (group,), + self.onGroupAdded, (group,)) + + def onGroupAdded(self, response, group): + '''this method is called when the addGroup soap request get a response''' + + common.debug('add group ' + str(response.status)) + + if response.status[0] == 200: + try: + gid = response.body.split('')[1].split('')[0] + self.contactManager.addGroup(group, gid) + self.emit('group-added', group, gid) + self.emit('user-list-change') + except IndexError, e: + common.debug('cannot add group to userlist') + common.debug(str(e)) + else: + self.emit('error', 'group-add-error', _('Group could not be added: %s') % common.parseSoapFault(response)) + + def removeGroup(self, group): + '''remove a group from the group list''' + + gid = self.contactManager.getGroupId(group) + if gid: + groupObj = self.contactManager.getGroup(gid) + self.contactManager.removeGroup(gid) + self.emit('user-list-change') + + soap.manager.do_request(self.proxy,\ + 'http://www.msn.com/webservices/AddressBook/ABGroupDelete', \ + 'contacts.msn.com', 443, '/abservice/abservice.asmx', \ + soap.templates.deleteGroup % (gid,), \ + self.onGroupRemoved, (gid, groupObj)) + + else: + common.debug('Unable to remove: Group "' + group \ + + '" does not exist') + + def onGroupRemoved(self, response, gid, group): + '''this method is called when the removeGroup soap request get a response''' + + common.debug('remove group ' + str(response.status)) + + if response.status[0] == 200: + self.emit('group-removed', group) + else: + # TODO: change it to setGroup when it manages contacts + self.contactManager.setGroup(gid, group) + self.emit('user-list-change') + self.emit('error', 'group-remove-error', _('Group could not be removed: %s') % common.parseSoapFault(response)) + + def renameGroup(self, oldGroup, newGroup): + '''rename a group from the group list''' + + if oldGroup == newGroup: + common.debug('oldgroup and new group are the same') + return + if self.contactManager.getGroupId(newGroup) != None: + common.debug('That group name is already in use') + return + + gid = self.contactManager.getGroupId(oldGroup) + if gid == None: + common.debug('The specified group does not exist') + return + else: + self.contactManager.renameGroup(gid, newGroup) + group = self.contactManager.getGroup(gid) + objOldGroup = ContactData.Group(oldGroup) + self.emit('group-attr-changed', objOldGroup, group) + soap.manager.do_request(self.proxy,\ + 'http://www.msn.com/webservices/AddressBook/ABGroupUpdate', \ + 'contacts.msn.com', 443, '/abservice/abservice.asmx', \ + soap.templates.renameGroup % (gid, common.escape(newGroup)), \ + self.onGroupRenamed, (oldGroup, newGroup)) + + def onGroupRenamed(self, response, oldGroup, newGroup): + '''this method is called when the renameGroup soap request get a response''' + + common.debug('rename group ' + str(response.status)) + + if response.status[0] == 200: + self.emit('group-renamed', oldGroup, newGroup) + else: + gid = self.contactManager.getGroupId(newGroup) + self.contactManager.renameGroup(gid, oldGroup) + group = self.contactManager.getGroup(gid) + # its old because we revert the changes + objOldGroup = ContactData.Group(newGroup) + self.emit('group-attr-changed', objOldGroup, group) + self.emit('error', 'group-rename-error', _('Group could not be renamed: %s') % common.parseSoapFault(response)) + + def changeNick(self, nick, initial=False): + nick = nick.decode('utf-8', 'replace').encode('utf-8') + if nick == '': + nick = self.user + + if not initial and self.nick == nick: + common.debug('trying to set the same nick') + return + + if len(nick) > 129: + # to avoid problems with utf-8 + return + + oldNick = self.nick + self.nick = nick + #self.contactManager.setContactNick(self.user, self.nick) + self.emit('self-nick-changed', oldNick, self.nick) + + self.socket.sendCommand("PRP", "MFN " + urllib.quote(nick)) + + if not initial: + if self.rid != "":# self.affinityCache != '': + soap.requests.update_profile(self.proxy, self.affinityCache, \ + self.rid, common.escape(nick), \ + common.escape(self.personalMessage), self.onNickChanged, oldNick) + + def changeAlias(self, user, alias): + alias = alias.decode('utf-8', 'replace').encode('utf-8') + + oldAlias = self.contactManager.getContactAlias(user) + + self.contactManager.setContactAlias(user, alias) + self.emit('user-attr-changed', self.contactManager.getContact(user)) + + soap.requests.change_alias(self.proxy, self.contactManager.getContactId(user), + alias, self.onAliasChanged, user, oldAlias) + + def onNickChanged(self, response, oldNick): + return # shhht! user exceeded the limit can be bad + if response.status[0] != 200: + #self.contactManager.setContactNick(self.user, oldNick) + self.emit('self-nick-changed', self.nick, oldNick) + self.emit('error', 'nick-change-error', + common.parseSoapFault(response)) + + def onPmChanged(self, response, oldPm): + return # shhht! user exceeded the limit can be bad + if response.status[0] != 200: + self.emit('self-personal-message-changed', self.personalMessage, oldPm) + self.emit('error', 'pm-change-error', + common.parseSoapFault(response)) + + def onAliasChanged(self, response, user, oldAlias): + if response.status[0] != 200: + self.emit('contact-attr-changed', user, 'alias', oldNick) + self.contactManager.setContactAlias(user, oldNick) + contact = self.contactManager.getContact(user) + self.emit('user-attr-changed', contact) + self.emit('error', 'nick-change-error', + common.parseSoapFault(response)) + + def updateUUX(self): + '''update personal message and current media''' + pm = self.personalMessage + cm = self.currentMedia + pm = pm.decode('utf-8', 'replace').encode('utf-8') + cm = cm.decode('utf-8', 'replace').encode('utf-8') + + self.socket.sendPayloadCommand('UUX', '', \ + '' + common.escape(pm) + '' + \ + '' + common.escape(cm) + '' + \ + '') + + def changePersonalMessage(self, pm): + '''change the personal message''' + if self.personalMessage != pm: + if len(pm) > 129: + return + oldPm = self.personalMessage + self.personalMessage = pm + self.updateUUX() + #if self.affinityCache != '': + soap.requests.update_profile(self.proxy, self.affinityCache, \ + self.rid, common.escape(self.nick), \ + common.escape(self.personalMessage), self.onPmChanged, oldPm) + self.emit('self-personal-message-changed', self.user, pm) + else: + common.debug("duplicate pm") + + def changeCurrentMedia(self, cm, dict=None): + '''change the current media''' + if self.currentMedia != cm: + self.currentMedia = cm + self.updateUUX() + self.emit('self-current-media-changed', self.user, cm, dict) + else: + common.debug("duplicate cm") + + def getUserDisplayName(self, mail): + '''return the user display name or just the mail if it cant be found''' + mail = mail.lower() + if mail == self.user: + return self.nick + else: + alias = self.contactManager.getContactAlias(mail) + + if alias: + return alias + else: + return self.contactManager.getContactNick(mail) + + def setAddressBookXml(self, xml): + '''modify the structure with a new DynamicItems xml''' + + contacts = {} + + for (mail, contact) in self.contactManager.contacts.iteritems(): + contacts[mail] = contact + + self.contactManager.groups = {} + self.contactManager.noGroup.users = {} + self.contactManager.contacts = {} + + #doc = minidom.parseString(xml) + + dinamicItems = XmlParser.DynamicParser(xml) + # Retrieve groups + for i in dinamicItems.groups: + groupId = i['groupId'] + name = i['name'] + + if groupId not in self.contactManager.groups: + self.contactManager.setGroup(groupId , + ContactData.Group(name, groupId)) + self.emit('group-added', name, groupId) + + # Retrieve contacts + for i in dinamicItems.contacts: + if 'isMessengerUser' in i and 'passportName' in i and \ + i['isMessengerUser'] == 'true': + # valid + email = i['passportName'].lower() + contact = ContactData.Contact(email) + else: + continue + + try: + contactId = i['contactId'] + cid = i['CID'] + contact.id = contactId + contact.cid = cid + + groups = [] + + for guid in i['groupIds']: + groups.append(guid) + + contact.groups = groups + + for j in i['Annotations']: + try: + if j['Name'] == 'AB.NickName': + alias = j['Value'] + contact.alias = urllib.unquote(alias) + except: + pass + + displayName = i['displayName'] + contact.nick = urllib.unquote(displayName) + + isMobileIMEnabled = i['isMobileIMEnabled'] + contact.mobile = isMobileIMEnabled == 'true' + + hasSpace = i['hasSpace'] + contact.space = hasSpace == 'true' + except KeyError: + continue + + if email in contacts: + contact.status = contacts[email].status + contact.nick = contacts[email].nick + contact.personalMessage = contacts[email].personalMessage + contact.msnobj = contacts[email].msnobj + contact.clientid = contacts[email].clientid + + # finally adds the contact + self.contactManager.addContact(contact) + self.emit('contact-added', contact.email, contact.id, contact.nick, + contact.personalMessage, contact.status, contact.alias, + contact.blocked) + + for group_id in contact.groups: + self.emit('contact-added-to-group', contact.email, + self.contactManager.getGroup(group_id).name) + + self.contactManager.updateMemberships() + + def setMembershipListXml(self, xml): + '''modify the structure with a new MembershipList xml + if it is the first xml that you send, send first the dynamic items''' + + self.contactManager.lists['Allow'] = [] + self.contactManager.lists['Block'] = [] + self.contactManager.lists['Reverse'] = [] + self.contactManager.lists['Pending'] = [] + + #ml = minidom.parseString(xml) + ml = XmlParser.MembershipParser(xml) + + for i in ml.memberships: + memberRole = i['MemberRole'] + + for j in i['Members']: + try: + email = j['PassportName'].lower() + if email not in self.contactManager.lists[memberRole]: + self.contactManager.lists[memberRole].append(email) + else: + pass + + if memberRole == 'Pending' and 'DisplayName' in j: + self.contactManager.pendingNicks[email] = \ + j['DisplayName'] + + except Exception, e: + pass + +gobject.type_register(ProfileManager) + +def getCIDFromDynamicItems(xml): + try: + cid = xml.split('Me')\ + [1].split('')[0].split('')[1] + return cid + except IndexError: + return '' + diff -Nru emesene-1.6.1/.pc/applied-patches emesene-1.6.3~peppermint1/.pc/applied-patches --- emesene-1.6.1/.pc/applied-patches 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/.pc/applied-patches 2010-08-18 23:28:16.000000000 +0100 @@ -0,0 +1,2 @@ +20_dont_build_own_libmimic.patch +21_svn2451_fix_avatar.patch diff -Nru emesene-1.6.1/.pc/.version emesene-1.6.3~peppermint1/.pc/.version --- emesene-1.6.1/.pc/.version 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/.pc/.version 2010-08-18 23:28:16.000000000 +0100 @@ -0,0 +1 @@ +2 diff -Nru emesene-1.6.1/plugins_base/currentSong/AIMP2.py emesene-1.6.3~peppermint1/plugins_base/currentSong/AIMP2.py --- emesene-1.6.1/plugins_base/currentSong/AIMP2.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/AIMP2.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +# This file is part of emesene. +# +# Emesene is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# emesene is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with emesene; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +import Winamp + +class AIMP2( Winamp.Winamp ): + + def __init__( self ): + Winamp.Winamp.__init__( self ) + self.template = "AIMP2\\0Music\\01\\0{0}\\0%s\\0\\0" \ No newline at end of file diff -Nru emesene-1.6.1/plugins_base/currentSong/aTunes.py emesene-1.6.3~peppermint1/plugins_base/currentSong/aTunes.py --- emesene-1.6.1/plugins_base/currentSong/aTunes.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/aTunes.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- + +# This file is part of emesene. +# +# Emesene is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# emesene is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with emesene; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +import os +import ctypes +user = ctypes.windll.user32 + +import CurrentSong +from emesenelib import * + +class aTunes( CurrentSong.CurrentSong ): + + def __init__( self ): + CurrentSong.CurrentSong.__init__( self ) + self.atunes = None + self.isRunning() + self.currentSong = '' + self.template = "aTunes\\0Music\\01\\0{0}\\0%s\\0\\0" + + def isPlaying( self ): + if self.atunes: + st = ctypes.create_unicode_buffer(100) + user.GetWindowTextW(self.atunes, st, 100) + print st.value + return not st.value.startswith('aTunes') + else: + return False + + def isRunning( self ): + try: + sunClassName = ctypes.c_wchar_p('SunAwtFrame') + self.atunes = user.FindWindowW(sunClassName, None) + return self.atunes != 0 + except: + return False + + def getCurrentSong( self ): + return self.currentSong + + def check( self ): + if not self.isRunning(): + self.currentSong = "" + return True + if self.isPlaying(): + st = ctypes.create_unicode_buffer(100) + user.GetWindowTextW(self.atunes, st, 100) + string = st.value.rsplit(' (',1)[0] + print string + newCurrentSong = self.template % string + else: + newCurrentSong = '' + + if self.currentSong != newCurrentSong: + self.currentSong = newCurrentSong + return True + + return False + + def getStatus( self ): + ''' + check if everything is OK to start the plugin + return a tuple whith a boolean and a message + if OK -> ( True , 'some message' ) + else -> ( False , 'error message' ) + ''' + + if os.name != 'nt': + return ( False, 'This plugin only works on windows systems' ) + + return ( True, 'Ok' ) diff -Nru emesene-1.6.1/plugins_base/currentSong/Audacious.py emesene-1.6.3~peppermint1/plugins_base/currentSong/Audacious.py --- emesene-1.6.1/plugins_base/currentSong/Audacious.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/Audacious.py 2010-07-12 23:13:14.000000000 +0100 @@ -58,7 +58,10 @@ def isRunning( self ): if self.iface: return True - if len(commands.getoutput("audtool2 version")) > 0: + version = commands.getoutput("audtool2 version") + if version == "sh: audtool2: not found": + return False + if len(version) > 0: return True return False diff -Nru emesene-1.6.1/plugins_base/currentSong/Clementine.py emesene-1.6.3~peppermint1/plugins_base/currentSong/Clementine.py --- emesene-1.6.1/plugins_base/currentSong/Clementine.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/Clementine.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +# This file is part of emesene. +# +# Emesene is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# emesene is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with emesene; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +# CurrentSong plugin extension for Clementine +# Gustavo M. Brunoro +# +# Based on CurrentSong plugin extension for Amarok2 by +# Adolfo J. Fitoria E. + + +VERSION = '0.3' +IFACE_NAME = 'org.mpris.clementine' +IFACE_PATH = '/TrackList' + +import os +import CurrentSong + +error = False + +class Clementine( CurrentSong.DbusBase ): + '''Clementine CurrentSong Plugin.''' + + def __init__(self): + CurrentSong.DbusBase.__init__( self, IFACE_NAME, self.setInterface ) + try: + self.iface + except: + self.iface = None + self.playingNow = '' + + def setInterface( self ): + self.iface = self.bus.get_object(IFACE_NAME, IFACE_PATH) + + def isPlaying( self ): + if self.iface: + isPlayingiface = self.bus.get_object(IFACE_NAME, '/Player') + if isPlayingiface: + status = isPlayingiface.GetStatus() + if status[0] == 0: + return True + else: + return False + return False + + def check(self): + if self.isPlaying(): + current_track = self.iface.GetCurrentTrack() + current_song = self.iface.GetMetadata(current_track) + if self.artist != current_song['artist'] or \ + self.title != current_song['title']: + self.artist = current_song['artist'] + self.title = current_song['title'] + self.album = current_song['album'] + return True + else: + return False + diff -Nru emesene-1.6.1/plugins_base/currentSong/Consonance.py emesene-1.6.3~peppermint1/plugins_base/currentSong/Consonance.py --- emesene-1.6.1/plugins_base/currentSong/Consonance.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/Consonance.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +# This file is part of emesene. +# +# Emesene is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# emesene is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with emesene; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# Consonance subplugin for CurrentSong plugin +# by sgesweb (sgesweb@gmail.com) + +VERSION = '1.0' + +import os +import commands + +import CurrentSong + +class Consonance( CurrentSong.CurrentSong ): + customConfig = { + 'unknownArtistString': '[N/A]', + 'unknownTitleString': '[N/A]', + 'unknownAlbumString': '[N/A]' + } + + def __init__( self ): + CurrentSong.CurrentSong.__init__( self ) + + def check(self): + if self.isPlaying(): + self.title = commands.getoutput("consonance -c 2>/dev/null | grep '^title' | sed s/'^title: *'//") + self.artist = commands.getoutput("consonance -c 2>/dev/null | grep '^artist' | sed s/'^artist: *'//") + self.album = commands.getoutput("consonance -c 2>/dev/null | grep '^album' | sed s/'^album: *'//") + if self.artist == '': + self.artist = self.customConfig['unknownArtistString'] + if self.album == '': + self.album = self.customConfig['unknownAlbumString'] + if self.title == '': + self.title = self.customConfig['unknownTitleString'] + return True + return False + + def isPlaying(self): + if not self.isRunning(): + return False + state = commands.getoutput("consonance -c 2>/dev/null | grep '^state' | sed s/'^.* '//") + if state == "Paused" or state == "Stopped": + return False + return True + + def isRunning(self): + if len(commands.getoutput("ps -C consonance --no-heading")) > 0: + return True + return False + + def getStatus( self ): + if os.name != 'posix': + return ( False, _( 'This plugin only works in posix systems' ) ) + return ( True, "OK" ) + + def getCoverPath(self): + return None diff -Nru emesene-1.6.1/plugins_base/currentSong/CurrentSong.py emesene-1.6.3~peppermint1/plugins_base/currentSong/CurrentSong.py --- emesene-1.6.1/plugins_base/currentSong/CurrentSong.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/CurrentSong.py 2010-07-12 23:13:14.000000000 +0100 @@ -41,7 +41,7 @@ self.status = _('unknown') def log(self, type, message): - print "%s: %s" % (type, message) + #print "%s: %s" % (type, message) self._log.append((type, message)) def getSongDict(self): diff -Nru emesene-1.6.1/plugins_base/currentSong/Exaile.py emesene-1.6.3~peppermint1/plugins_base/currentSong/Exaile.py --- emesene-1.6.1/plugins_base/currentSong/Exaile.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/Exaile.py 2010-07-12 23:13:14.000000000 +0100 @@ -34,14 +34,10 @@ def setInterface( self ): proxy_obj = self.bus.get_object( IFACE_NAME, IFACE_PATH ) self.iface = self.module.Interface( proxy_obj, IFACE_NAME ) - + def isPlaying(self): - if self.isRunning(): - trackInfo = str(self.iface.Query()) - if string.split(trackInfo, ", ")[0] == "status: playing": - return True - return False - + return self.iface.IsPlaying() + def check( self ): if not self.isRunning(): return False diff -Nru emesene-1.6.1/plugins_base/currentSong/Foobar2000.py emesene-1.6.3~peppermint1/plugins_base/currentSong/Foobar2000.py --- emesene-1.6.1/plugins_base/currentSong/Foobar2000.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/Foobar2000.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- + +# This file is part of emesene. +# +# Emesene is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# emesene is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with emesene; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +import os +from ctypes import * +from ctypes.wintypes import * +user = windll.user32 + +import CurrentSong +from emesenelib import * + + +_window = None + +WNDENUMPROC=WINFUNCTYPE(BOOL, HWND, LPARAM) + +@WNDENUMPROC +def EnumWindowsCallbackFunc(hwnd,lParam): + global _window + st = create_unicode_buffer(100) + user.GetClassNameW(hwnd,st,100) + user.GetWindowTextW(hwnd,st,100) + if st.value.find("foobar2000") != -1: + _window = hwnd + return True #Allow windows to keep enumerating + +class Foobar2000( CurrentSong.CurrentSong ): + + def __init__( self ): + CurrentSong.CurrentSong.__init__( self ) + self.isRunning() + self.foobarwindow = None + self.currentSong = '' + self.template = "Foobar2000\\0Music\\01\\0{0}\\0%s\\0\\0" + + def isPlaying( self ): + st = create_unicode_buffer(100) + user.GetWindowTextW(self.foobarwindow,st,100) + return not st.value.startswith("foobar2000") + + def isRunning( self ): + global _window + user.EnumWindows(EnumWindowsCallbackFunc,0) + if _window is not None: + self.foobarwindow = _window + return True + else: + return False + + def getCurrentSong( self ): + return self.currentSong + + def check( self ): + if not self.isRunning(): + self.currentSong = "" + return True + if self.isPlaying(): + st = create_unicode_buffer(100) + user.GetWindowTextW(self.foobarwindow, st, 100) + index = st.value.rfind("foobar2000") + # stadard ui adds " [foobar2000 v1.0.3]" at the end + # columns ui adds " - foobar2000" at the end, that's the -3 for + string = st.value[:index-3] + newCurrentSong = self.template % string + else: + newCurrentSong = '' + + if self.currentSong != newCurrentSong: + self.currentSong = newCurrentSong + return True + + return False + + def getStatus( self ): + ''' + check if everything is OK to start the plugin + return a tuple whith a boolean and a message + if OK -> ( True , 'some message' ) + else -> ( False , 'error message' ) + ''' + + if os.name != 'nt': + return ( False, 'This plugin only works on windows systems' ) + + return ( True, 'Ok' ) diff -Nru emesene-1.6.1/plugins_base/currentSong/GOMPlayer.py emesene-1.6.3~peppermint1/plugins_base/currentSong/GOMPlayer.py --- emesene-1.6.1/plugins_base/currentSong/GOMPlayer.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/GOMPlayer.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- + +# This file is part of emesene. +# +# Emesene is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# emesene is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with emesene; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +import os +import ctypes +user = ctypes.windll.user32 + +import CurrentSong +from emesenelib import * + +class GOMPlayer( CurrentSong.CurrentSong ): + + def __init__( self ): + CurrentSong.CurrentSong.__init__( self ) + self.gom = None + self.isRunning() + self.currentSong = '' + self.template = "GOMPlayer\\0Music\\01\\0{0}\\0%s\\0\\0" + + def isPlaying( self ): + if self.gom: + st = ctypes.create_unicode_buffer(100) + user.GetWindowTextW(self.gom, st, 100) + return st.value != 'GOM Player' + else: + return False + + def isRunning( self ): + try: + gomClassName = ctypes.c_wchar_p('GomPlayer1.x') + self.gom = user.FindWindowW(gomClassName, None) + return self.gom != 0 + except: + return False + + def getCurrentSong( self ): + return self.currentSong + + def check( self ): + if not self.isRunning(): + self.currentSong = "" + return True + if self.isPlaying(): + st = ctypes.create_unicode_buffer(100) + user.GetWindowTextW(self.gom, st, 100) + string = st.value.split(" - GOM Player")[0] + newCurrentSong = self.template % string + else: + newCurrentSong = '' + + if self.currentSong != newCurrentSong: + self.currentSong = newCurrentSong + return True + + return False + + def getStatus( self ): + ''' + check if everything is OK to start the plugin + return a tuple whith a boolean and a message + if OK -> ( True , 'some message' ) + else -> ( False , 'error message' ) + ''' + + if os.name != 'nt': + return ( False, 'This plugin only works on windows systems' ) + + return ( True, 'Ok' ) diff -Nru emesene-1.6.1/plugins_base/currentSong/__init__.py emesene-1.6.3~peppermint1/plugins_base/currentSong/__init__.py --- emesene-1.6.1/plugins_base/currentSong/__init__.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/__init__.py 2010-07-12 23:13:14.000000000 +0100 @@ -22,11 +22,14 @@ from Amarok2 import Amarok2 from Audacious import Audacious from Banshee import Banshee + from Clementine import Clementine + from Consonance import Consonance from Exaile import Exaile from Gmusicbrowser import Gmusicbrowser from Guayadeque import Guayadeque from LastFm import LastFm from Listen import Listen + from Mesk import Mesk from QuodLibet import QuodLibet from Rhythmbox import Rhythmbox from Vagalume import Vagalume @@ -37,7 +40,17 @@ from Xmms import Xmms from Xmms2 import Xmms2 else: + from AIMP2 import AIMP2 + from aTunes import aTunes + from Foobar2000 import Foobar2000 + from GOMPlayer import GOMPlayer + from MediaMonkey import MediaMonkey + from MediaPlayerClassic import MediaPlayerClassic + from OneByOne import OneByOne + from RealPlayer import RealPlayer + from SMPlayer import SMPlayer from Winamp import Winamp + from XMPlay import XMPlay # can stay out, since it uses sockets from Mpd import Mpd diff -Nru emesene-1.6.1/plugins_base/currentSong/MediaMonkey.py emesene-1.6.3~peppermint1/plugins_base/currentSong/MediaMonkey.py --- emesene-1.6.1/plugins_base/currentSong/MediaMonkey.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/MediaMonkey.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- + +# This file is part of emesene. +# +# Emesene is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# emesene is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with emesene; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +import os +import ctypes +user = ctypes.windll.user32 + +import CurrentSong +from emesenelib import * + +class MediaMonkey( CurrentSong.CurrentSong ): + + def __init__( self ): + CurrentSong.CurrentSong.__init__( self ) + self.mmonkey = None + self.isRunning() + self.currentSong = '' + self.template = "MediaMonkey\\0Music\\01\\0{0}\\0%s\\0\\0" + + def isPlaying( self ): + if self.mmonkey and user.SendMessageW(self.mmonkey, 0x400, 0, 104) != 1: + return False + + return True + + def isRunning( self ): + try: + mmonkeyClassName = ctypes.c_wchar_p('Winamp v1.x') + self.mmonkey = user.FindWindowW(mmonkeyClassName, None) + return self.mmonkey != 0 + except: + return False + + def getCurrentSong( self ): + return self.currentSong + + def check( self ): + if not self.isRunning(): + self.currentSong = "" + return True + if self.isPlaying(): + st = ctypes.create_unicode_buffer(100) + user.GetWindowTextW(self.mmonkey, st, 100) + string = st.value.split(". ",1)[1] + newCurrentSong = self.template % string + else: + newCurrentSong = '' + + if self.currentSong != newCurrentSong: + self.currentSong = newCurrentSong + return True + + return False + + def getStatus( self ): + ''' + check if everything is OK to start the plugin + return a tuple whith a boolean and a message + if OK -> ( True , 'some message' ) + else -> ( False , 'error message' ) + ''' + + if os.name != 'nt': + return ( False, 'This plugin only works on windows systems' ) + + return ( True, 'Ok' ) diff -Nru emesene-1.6.1/plugins_base/currentSong/MediaPlayerClassic.py emesene-1.6.3~peppermint1/plugins_base/currentSong/MediaPlayerClassic.py --- emesene-1.6.1/plugins_base/currentSong/MediaPlayerClassic.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/MediaPlayerClassic.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- + +# This file is part of emesene. +# +# Emesene is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# emesene is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with emesene; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +import os +import ctypes +user = ctypes.windll.user32 + +import CurrentSong +from emesenelib import * + +class MediaPlayerClassic( CurrentSong.CurrentSong ): + + def __init__( self ): + CurrentSong.CurrentSong.__init__( self ) + self.mplayerwindow = None + self.isRunning() + self.currentSong = '' + self.template = "MPlayerClassic\\0Music\\01\\0{0}\\0%s\\0\\0" + + def isPlaying( self ): + if self.mplayerwindow is not None: + st = ctypes.create_unicode_buffer(100) + user.GetWindowTextW(self.mplayerwindow, st, 100) + return st.value != "Media Player Classic" + else: + return False + + def isRunning( self ): + winampClassName = ctypes.c_wchar_p('MediaPlayerClassicW') + self.mplayerwindow = user.FindWindowW(winampClassName, None) + return self.mplayerwindow != 0 + + def getCurrentSong( self ): + return self.currentSong + + def check( self ): + if not self.isRunning(): + self.currentSong = "" + return True + if self.isPlaying(): + st = ctypes.create_unicode_buffer(100) + user.GetWindowTextW(self.mplayerwindow, st, 100) + string = st.value.split(" - Media Player Classic")[0] + newCurrentSong = self.template % string + else: + newCurrentSong = '' + + if self.currentSong != newCurrentSong: + self.currentSong = newCurrentSong + return True + + return False + + def getStatus( self ): + ''' + check if everything is OK to start the plugin + return a tuple whith a boolean and a message + if OK -> ( True , 'some message' ) + else -> ( False , 'error message' ) + ''' + + if os.name != 'nt': + return ( False, 'This plugin only works on windows systems' ) + + return ( True, 'Ok' ) diff -Nru emesene-1.6.1/plugins_base/currentSong/Mesk.py emesene-1.6.3~peppermint1/plugins_base/currentSong/Mesk.py --- emesene-1.6.1/plugins_base/currentSong/Mesk.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/Mesk.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# devloop.lyua.org - 03/2009 +# CurrentSong Emesene module for the Mesk audio player + +VERSION = '1.0' +IFACE_NAME = 'net.nicfit.mesk.MeskApp.profile_default' +IFACE_PATH = '/net/nicfit/mesk/MeskApp/profile_default' + +import CurrentSong + +class Mesk( CurrentSong.DbusBase ): + '''Mesk Interface''' + + def __init__( self ): + CurrentSong.DbusBase.__init__( self, IFACE_NAME, self.setInterface ) + + try: self.iface + except: self.iface = None + + def setInterface( self ): + self.iface = self.bus.get_object( IFACE_NAME, IFACE_PATH ) + + def setCurrentSongData( self ): + if self.iface: + self.title = self.iface.get_current_title() + self.artist = self.iface.get_current_artist() + self.album = self.iface.get_current_album() + + def isPlaying( self ): + if not self.isNameActive(IFACE_NAME): + return False + if not self.iface: + return False + + if self.iface.get_state() == "playing": + return True + else: + return False + + def check( self ): + if not self.isNameActive(IFACE_NAME): + return False + if not self.iface: + return False + + if self.iface.get_state() == "playing": + if self.iface.get_current_artist() != None and \ + self.iface.get_current_title() != None and \ + self.iface.get_current_album() != None: + self.setCurrentSongData() + return True + + return False diff -Nru emesene-1.6.1/plugins_base/currentSong/OneByOne.py emesene-1.6.3~peppermint1/plugins_base/currentSong/OneByOne.py --- emesene-1.6.1/plugins_base/currentSong/OneByOne.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/OneByOne.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- + +# This file is part of emesene. +# +# Emesene is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# emesene is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with emesene; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +import os +import ctypes +user = ctypes.windll.user32 + +import CurrentSong +from emesenelib import * + +class OneByOne( CurrentSong.CurrentSong ): + + def __init__( self ): + CurrentSong.CurrentSong.__init__( self ) + self.onebyone = None + self.isRunning() + self.currentSong = '' + self.template = "OneByOne\\0Music\\01\\0{0}\\0%s\\0\\0" + + def isPlaying( self ): + if self.onebyone: + st = ctypes.create_unicode_buffer(100) + user.GetWindowTextW(self.onebyone, st, 100) + return st.value != '1by1 - The Directory Player' + else: + return False + + def isRunning( self ): + try: + oneByOneClassName = ctypes.c_wchar_p('1by1WndClass') + self.onebyone = user.FindWindowW(oneByOneClassName, None) + return self.onebyone != 0 + except: + return False + + def getCurrentSong( self ): + return self.currentSong + + def check( self ): + if not self.isRunning(): + self.currentSong = "" + return True + if self.isPlaying(): + st = ctypes.create_unicode_buffer(100) + user.GetWindowTextW(self.onebyone, st, 100) + string = st.value.split(' - ',1)[1].rsplit('.',1)[0] + newCurrentSong = self.template % string + else: + newCurrentSong = '' + + if self.currentSong != newCurrentSong: + self.currentSong = newCurrentSong + return True + + return False + + def getStatus( self ): + ''' + check if everything is OK to start the plugin + return a tuple whith a boolean and a message + if OK -> ( True , 'some message' ) + else -> ( False , 'error message' ) + ''' + + if os.name != 'nt': + return ( False, 'This plugin only works on windows systems' ) + + return ( True, 'Ok' ) diff -Nru emesene-1.6.1/plugins_base/currentSong/RealPlayer.py emesene-1.6.3~peppermint1/plugins_base/currentSong/RealPlayer.py --- emesene-1.6.1/plugins_base/currentSong/RealPlayer.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/RealPlayer.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- + +# This file is part of emesene. +# +# Emesene is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# emesene is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with emesene; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +import os +import ctypes +user = ctypes.windll.user32 + +import CurrentSong +from emesenelib import * + +class RealPlayer( CurrentSong.CurrentSong ): + + def __init__( self ): + CurrentSong.CurrentSong.__init__( self ) + self.real = None + self.isRunning() + self.currentSong = '' + self.template = "RealPlayer\\0Music\\01\\0{0}\\0%s\\0\\0" + + def isPlaying( self ): + if self.real: + st = ctypes.create_unicode_buffer(100) + user.GetWindowTextW(self.real, st, 100) + return st.value != 'RealPlayer' + else: + return False + + def isRunning( self ): + try: + realClassName = ctypes.c_wchar_p('GeminiWindowClass') + self.real = user.FindWindowW(realClassName, None) + print self.real + return self.real != 0 + except: + return False + + def getCurrentSong( self ): + return self.currentSong + + def check( self ): + if not self.isRunning(): + self.currentSong = "" + return True + if self.isPlaying(): + st = ctypes.create_unicode_buffer(100) + user.GetWindowTextW(self.real, st, 100) + string = st.value.split("RealPlayer: ")[1] + newCurrentSong = self.template % string + else: + newCurrentSong = '' + + if self.currentSong != newCurrentSong: + self.currentSong = newCurrentSong + return True + + return False + + def getStatus( self ): + ''' + check if everything is OK to start the plugin + return a tuple whith a boolean and a message + if OK -> ( True , 'some message' ) + else -> ( False , 'error message' ) + ''' + + if os.name != 'nt': + return ( False, 'This plugin only works on windows systems' ) + + return ( True, 'Ok' ) diff -Nru emesene-1.6.1/plugins_base/currentSong/SMPlayer.py emesene-1.6.3~peppermint1/plugins_base/currentSong/SMPlayer.py --- emesene-1.6.1/plugins_base/currentSong/SMPlayer.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/SMPlayer.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- + +# This file is part of emesene. +# +# Emesene is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# emesene is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with emesene; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +import os +from ctypes import * +from ctypes.wintypes import * +user = windll.user32 + +import CurrentSong +from emesenelib import * + + +_window = None + +WNDENUMPROC=WINFUNCTYPE(BOOL, HWND, LPARAM) + +@WNDENUMPROC +def EnumWindowsCallbackFunc(hwnd,lParam): + global _window + st = create_unicode_buffer(100) + user.GetClassNameW(hwnd,st,100) + if st.value.find("QWidget") != -1: + user.GetWindowTextW(hwnd,st,100) + if st.value.endswith("SMPlayer"): + _window = hwnd + return True #Allow windows to keep enumerating + +class SMPlayer( CurrentSong.CurrentSong ): + + def __init__( self ): + CurrentSong.CurrentSong.__init__( self ) + self.isRunning() + self.currentSong = '' + self.template = "SMPlayer\\0Music\\01\\0{0}\\0%s\\0\\0" + + def isPlaying( self ): + st = create_unicode_buffer(100) + user.GetWindowTextW(self.smplayerwindow,st,100) + return st.value != "SMPlayer" + + def isRunning( self ): + global _window + user.EnumWindows(EnumWindowsCallbackFunc,0) + if _window is not None: + self.smplayerwindow = _window + return True + else: + return False + + def getCurrentSong( self ): + return self.currentSong + + def check( self ): + if not self.isRunning(): + self.currentSong = "" + return True + if self.isPlaying(): + st = create_unicode_buffer(100) + user.GetWindowTextW(self.smplayerwindow, st, 100) + string = st.value.split(" - SMPlayer")[0] + newCurrentSong = self.template % string + else: + newCurrentSong = '' + + if self.currentSong != newCurrentSong: + self.currentSong = newCurrentSong + return True + + return False + + def getStatus( self ): + ''' + check if everything is OK to start the plugin + return a tuple whith a boolean and a message + if OK -> ( True , 'some message' ) + else -> ( False , 'error message' ) + ''' + + if os.name != 'nt': + return ( False, 'This plugin only works on windows systems' ) + + return ( True, 'Ok' ) diff -Nru emesene-1.6.1/plugins_base/currentSong/Winamp.py emesene-1.6.3~peppermint1/plugins_base/currentSong/Winamp.py --- emesene-1.6.1/plugins_base/currentSong/Winamp.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/Winamp.py 2010-07-12 23:13:14.000000000 +0100 @@ -18,18 +18,8 @@ import os -import gobject -import gettext - - -ERROR = '' - -try: - import win32api - import win32gui -except: - ERROR = 'cannot import needed modules' - +import ctypes +user = ctypes.windll.user32 import CurrentSong from emesenelib import * @@ -41,17 +31,19 @@ self.winamp = None self.isRunning() self.currentSong = '' + self.template = "Winamp\\0Music\\01\\0{0}\\0%s\\0\\0" def isPlaying( self ): - if self.winamp and win32api.SendMessage(self.winamp, 0x400, 0, 104) != 1: + if self.winamp and user.SendMessageW(self.winamp, 0x400, 0, 104) != 1: return False return True def isRunning( self ): try: - self.winamp = win32gui.FindWindow('Winamp v1.x', None) - return True + winampClassName = ctypes.c_wchar_p('Winamp v1.x') + self.winamp = user.FindWindowW(winampClassName, None) + return self.winamp != 0 except: return False @@ -59,13 +51,14 @@ return self.currentSong def check( self ): - if not self.isRunning(): return False - + if not self.isRunning(): + self.currentSong = "" + return True if self.isPlaying(): - string = 'Winamp\\0Music\\01\\0{0}\\0%s\\0\\0' % \ - win32gui.GetWindowText( self.winamp ).split(". ",1)[-1] .split(" - Winamp")[0] - newCurrentSong = unicode(string,"Windows-1252") - print newCurrentSong + st = ctypes.create_unicode_buffer(100) + user.GetWindowTextW(self.winamp, st, 100) + string = st.value.split(". ",1)[1].split(" - Winamp")[0] + newCurrentSong = self.template % string else: newCurrentSong = '' @@ -86,7 +79,4 @@ if os.name != 'nt': return ( False, 'This plugin only works on windows systems' ) - if ERROR != '': - return ( False, ERROR ) - return ( True, 'Ok' ) diff -Nru emesene-1.6.1/plugins_base/currentSong/XMPlay.py emesene-1.6.3~peppermint1/plugins_base/currentSong/XMPlay.py --- emesene-1.6.1/plugins_base/currentSong/XMPlay.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/currentSong/XMPlay.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- + +# This file is part of emesene. +# +# Emesene is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# emesene is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with emesene; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +import os +import ctypes +user = ctypes.windll.user32 + +import CurrentSong +from emesenelib import * + +class XMPlay( CurrentSong.CurrentSong ): + + def __init__( self ): + CurrentSong.CurrentSong.__init__( self ) + self.xmplay = None + self.isRunning() + self.currentSong = '' + self.template = "XMPlay\\0Music\\01\\0{0}\\0%s\\0\\0" + + def isPlaying( self ): + if self.xmplay: + st = ctypes.create_unicode_buffer(100) + user.GetWindowTextW(self.xmplay, st, 100) + return st.value != 'XMPlay' + else: + return False + + def isRunning( self ): + try: + xmplayClassName = ctypes.c_wchar_p('XMPLAY-MAIN') + self.xmplay = user.FindWindowW(xmplayClassName, None) + return self.xmplay != 0 + except: + return False + + def getCurrentSong( self ): + return self.currentSong + + def check( self ): + if not self.isRunning(): + self.currentSong = "" + return True + if self.isPlaying(): + st = ctypes.create_unicode_buffer(100) + user.GetWindowTextW(self.xmplay, st, 100) + string = st.value + newCurrentSong = self.template % string + else: + newCurrentSong = '' + + if self.currentSong != newCurrentSong: + self.currentSong = newCurrentSong + return True + + return False + + def getStatus( self ): + ''' + check if everything is OK to start the plugin + return a tuple whith a boolean and a message + if OK -> ( True , 'some message' ) + else -> ( False , 'error message' ) + ''' + + if os.name != 'nt': + return ( False, 'This plugin only works on windows systems' ) + + return ( True, 'Ok' ) diff -Nru emesene-1.6.1/plugins_base/CurrentSong.py emesene-1.6.3~peppermint1/plugins_base/CurrentSong.py --- emesene-1.6.1/plugins_base/CurrentSong.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/CurrentSong.py 2010-07-12 23:13:14.000000000 +0100 @@ -230,18 +230,18 @@ ''' get avatar cover art ''' path = self.player.getCoverPath() if path and os.path.exists(path): - print "Current song plugin : getCoverPath : [" + path + "]" + #print "Current song plugin : getCoverPath : [" + path + "]" return path path = self.search_local_image() if path and os.path.exists(path): - print "Current song plugin : getCoverPath : [" + path + "]" + #print "Current song plugin : getCoverPath : [" + path + "]" return path if remote: try: path = self.search_remote_image() - print "Current song plugin : getCoverPath : [" + path + "]" + #print "Current song plugin : getCoverPath : [" + path + "]" return path except: # handle connection errors @@ -278,7 +278,7 @@ if name == _('Autodetect'): for n in players: if n.lower() != 'lastfm': - print "Current song plugin: Trying " + n + #print "Current song plugin: Trying " + n if self._setPlayer(n, players) == 'loaded': if not self.usingDummy and self.player.isRunning(): return @@ -297,7 +297,7 @@ self.usingDummy = False self.action() except Exception, e: - print "error initializing CurrentSong player:", e + #print "error initializing CurrentSong player:", e error = e else: self.player.log('info', _('Player: ') + name) @@ -367,7 +367,7 @@ "&itempage=1&newsearch=1&searchindex=Music" # This is useful to see if we're searching for the right song - print "Current song plugin: " + url + #print "Current song plugin: " + url albumart = urllib.urlopen(url).read() image_url = "" diff -Nru emesene-1.6.1/plugins_base/Dbus.py emesene-1.6.3~peppermint1/plugins_base/Dbus.py --- emesene-1.6.1/plugins_base/Dbus.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/Dbus.py 2010-07-12 23:13:14.000000000 +0100 @@ -295,6 +295,7 @@ @dbus.service.method(BUS_NAME) def get_last_display_picture(self, email='', cache=True): imagePath='noImage' + lista = [] if cache: try: cachePath = self.controller.config.getCachePath() @@ -389,3 +390,6 @@ except Exception, e: dbusError = e + +def debug(string): + print string diff -Nru emesene-1.6.1/plugins_base/Notification.py emesene-1.6.3~peppermint1/plugins_base/Notification.py --- emesene-1.6.1/plugins_base/Notification.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/Notification.py 2010-07-12 23:13:14.000000000 +0100 @@ -20,6 +20,7 @@ import time import gobject import pango +import os import Plugin import dialog @@ -32,6 +33,44 @@ growFactor = 20 # the number of pixels to grow every iteration +# This code is used only on Windows to get the location on the taskbar +taskbarOffsety = 0 +taskbarOffsetx = 0 +if os.name == "nt": + import ctypes + from ctypes.wintypes import RECT, DWORD + user = ctypes.windll.user32 + MONITORINFOF_PRIMARY = 1 + HMONITOR = 1 + + class MONITORINFO(ctypes.Structure): + _fields_ = [ + ('cbSize', DWORD), + ('rcMonitor', RECT), + ('rcWork', RECT), + ('dwFlags', DWORD) + ] + + taskbarSide = "bottom" + taskbarOffset = 30 + info = MONITORINFO() + info.cbSize = ctypes.sizeof(info) + info.dwFlags = MONITORINFOF_PRIMARY + user.GetMonitorInfoW(HMONITOR, ctypes.byref(info)) + if info.rcMonitor.bottom != info.rcWork.bottom: + taskbarOffsety = info.rcMonitor.bottom - info.rcWork.bottom + if info.rcMonitor.top != info.rcWork.top: + taskbarSide = "top" + taskbarOffsety = info.rcWork.top - info.rcMonitor.top + if info.rcMonitor.left != info.rcWork.left: + taskbarSide = "left" + taskbarOffsetx = info.rcWork.left - info.rcMonitor.left + if info.rcMonitor.right != info.rcWork.right: + taskbarSide = "right" + taskbarOffsetx = info.rcMonitor.right - info.rcWork.right + + + class PixmapDialog(gtk.Dialog): '''a dialog to set Notification Pixmap''' def __init__(self, filename, font, color, online, offline, \ @@ -293,7 +332,7 @@ callback = None, params = None, userPixbuf = None, \ font = None, color = None): - gtk.Window.__init__(self, type=gtk.gdk.WINDOW_TOPLEVEL) + gtk.Window.__init__(self, type=gtk.WINDOW_POPUP) if corner == 0: self.set_gravity(gtk.gdk.GRAVITY_NORTH_WEST) @@ -304,9 +343,9 @@ else: self.set_gravity(gtk.gdk.GRAVITY_SOUTH_EAST) - self.set_accept_focus(False) - self.set_decorated(False) - self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_SPLASHSCREEN) + #self.set_accept_focus(False) + #self.set_decorated(False) + #self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_UTILITY) self.corner = corner self.scroll = scroll @@ -395,26 +434,32 @@ def _resize(self): ''' change the size and position ''' - if self.scroll == 0: + if self.offset == 0: + sumx = taskbarOffsetx + sumy = taskbarOffsety + else: + sumx = 0 + sumy = 0 + if self.scroll == 0: if self.corner == 0 or self.corner == 2: - l = self.offset + l = self.offset + sumx else: - l = gtk.gdk.screen_width() - self.offset - self.width + l = gtk.gdk.screen_width() - self.offset - self.width - sumx if self.corner == 0 or self.corner == 1: - t = 0 + t = 0 + taskbarOffsety else: - t = gtk.gdk.screen_height() - self.height + t = gtk.gdk.screen_height() - self.height - taskbarOffsety else: if self.corner == 0 or self.corner == 2: - l = 0 + l = 0 + taskbarOffsetx else: - l = gtk.gdk.screen_width() - self.width + l = gtk.gdk.screen_width() - self.width - taskbarOffsetx if self.corner == 0 or self.corner == 1: - t = self.offset + t = self.offset + sumy else: - t = gtk.gdk.screen_height() - self.offset - self.height + t = gtk.gdk.screen_height() - self.offset - self.height - sumy self.move(l, t) self.resize(self.width, self.height) @@ -432,7 +477,7 @@ if animate and offset < self.offset: self.offset -= growFactor - if offset > offset: + if offset < self.offset: self.offset = offset else: self.offset = offset @@ -676,8 +721,17 @@ self.controller.newConversation(None, params[0], params[1], True) def openMail(self, params): - desktop.open(self.controller.hotmail.getLoginPage\ - (params[0], params[1], params[2])) + if self.config.glob['overrideMail'] == '': + try: + desktop.open(self.controller.hotmail.getLoginPage\ + (params[0], params[1], params[2])) + except OSError: + dialog.error(_('Couldn\'t launch the default browser')) + else: + try: + subprocess.Popen(self.config.glob['overrideMail']) + except: + dialog.error(_('Couldn\'t launch the e-mail client')) def connect_onoff(self, *args): self.onlineId = self.connect('user-online', self.online) diff -Nru emesene-1.6.1/plugins_base/WindowTremblingNudge.py emesene-1.6.3~peppermint1/plugins_base/WindowTremblingNudge.py --- emesene-1.6.1/plugins_base/WindowTremblingNudge.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/WindowTremblingNudge.py 2010-07-12 23:13:14.000000000 +0100 @@ -70,11 +70,13 @@ win = None for switchboard in msnp.switchboards: if mail in switchboard.members: - w, c = self.controller.conversationManager.getOpenConversation(mail, switchboard) - if w is not None: - win = w - break - + response = self.controller.conversationManager.getOpenConversation(mail, switchboard) + if response is not None: + w, c = response + if w is not None: + win = w + break + if win is None: return diff -Nru emesene-1.6.1/plugins_base/WinkReceiving.py emesene-1.6.3~peppermint1/plugins_base/WinkReceiving.py --- emesene-1.6.1/plugins_base/WinkReceiving.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/plugins_base/WinkReceiving.py 2010-07-12 23:13:14.000000000 +0100 @@ -85,7 +85,8 @@ else: #Dont have the command gnash self.hasGnash = False - self.hasGnash = False + else: + self.hasGnash = False def get_conversation(self, switchboard): Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/ar/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/ar/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/ast/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/ast/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/az/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/az/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/bg/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/bg/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/bs/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/bs/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/ca/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/ca/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/cs/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/cs/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/da/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/da/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/de/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/de/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/dv/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/dv/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/el/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/el/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/en_AU/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/en_AU/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/en_CA/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/en_CA/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/en_GB/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/en_GB/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/eo/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/eo/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/es/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/es/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/et/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/et/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/eu/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/eu/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/fi/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/fi/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/fil/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/fil/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/fo/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/fo/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/fr/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/fr/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/ga/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/ga/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/gl/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/gl/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/gv/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/gv/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/he/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/he/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/hr/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/hr/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/hu/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/hu/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/id/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/id/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/is/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/is/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/it/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/it/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/ja/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/ja/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/kn/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/kn/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/ko/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/ko/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/ku/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/ku/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/la/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/la/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/lv/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/lv/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/mk/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/mk/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/ms/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/ms/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/nb/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/nb/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/nds/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/nds/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/nl/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/nl/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/nn/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/nn/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/oc/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/oc/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/pl/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/pl/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/pt/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/pt/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/pt_BR/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/pt_BR/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/ro/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/ro/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/ru/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/ru/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/sk/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/sk/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/sl/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/sl/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/sq/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/sq/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/sr/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/sr/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/sv/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/sv/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/ta/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/ta/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/th/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/th/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/tr/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/tr/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/uk/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/uk/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/zh_CN/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/zh_CN/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/zh_HK/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/zh_HK/LC_MESSAGES/emesene.mo differ Binary files /tmp/LqifKTFuzN/emesene-1.6.1/po/zh_TW/LC_MESSAGES/emesene.mo and /tmp/m3uZc8NVi1/emesene-1.6.3~peppermint1/po/zh_TW/LC_MESSAGES/emesene.mo differ diff -Nru emesene-1.6.1/PreferenceWindow.py emesene-1.6.3~peppermint1/PreferenceWindow.py --- emesene-1.6.1/PreferenceWindow.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/PreferenceWindow.py 2010-07-12 23:13:14.000000000 +0100 @@ -1691,11 +1691,12 @@ return count = 1 for device, name in WebcamDevice.list_devices(): - self.combobox.append_text(name) - self.webcamList.append((device, name)) - if device == self.deviceID: - self.deviceIndex = count - count += 1 + if name is not None: + self.combobox.append_text(name) + self.webcamList.append((device, name)) + if device == self.deviceID: + self.deviceIndex = count + count += 1 def on_set_device(self,button): self.deviceIndex = self.combobox.get_active() diff -Nru emesene-1.6.1/setup.py emesene-1.6.3~peppermint1/setup.py --- emesene-1.6.1/setup.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/setup.py 2010-08-18 23:28:16.000000000 +0100 @@ -6,18 +6,6 @@ import sys if os.name == 'posix': - for arg in sys.argv: - if arg == 'install': - print 'Hello.\nYou are trying to do a system-wide install of emesene '\ - 'using this script, which is a very bad thing to do.\n'\ - 'Seriously, you do NOT want to do this, since it can break '\ - 'other python apps, and emesene too!\n'\ - 'Follow my advice: just run the \"emesene\" script that is '\ - 'in this very same directory and you\'re done. emesene is running '\ - 'and your system is safe. It\'s a win-win, don\'t you think?\n'\ - 'Thanks for trying emesene.' - quit() - # From apport's setup.py mo_files = [] for filepath in glob("po/*/LC_MESSAGES/*.mo"): @@ -50,7 +38,6 @@ ('share/icons/hicolor/scalable/apps', ['misc/emesene.svg']), ('share/man/man1', ['misc/emesene.1']), ('share/applications', ['misc/emesene.desktop'])] + mo_files, - ext_modules = [libmimic_module] ) elif os.name == 'nt': import pygst diff -Nru emesene-1.6.1/SingleInstance.py emesene-1.6.3~peppermint1/SingleInstance.py --- emesene-1.6.1/SingleInstance.py 1970-01-01 01:00:00.000000000 +0100 +++ emesene-1.6.3~peppermint1/SingleInstance.py 2010-07-12 23:13:14.000000000 +0100 @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- + +# This file is a plugin for emesene. +# +# Dbus Emesene Plugin is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Dbus Emesene Plugin is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with emesene; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import sys, os, errno, tempfile + +HAVE_DBUS = False + +BUS_NAME = 'org.emesene.dbus' +OBJECT_PATH = '/org/emesene/dbus' + +if os.name == "posix": + try: + import dbus, dbus.service + dbusError = '' + if getattr(dbus, 'version', (0,0,0)) >= (0,41,0): + import dbus.glib + if getattr(dbus, 'version', (0,0,0)) >= (0,80,0): + import _dbus_bindings as dbus_bindings + from dbus.mainloop.glib import DBusGMainLoop + DBusGMainLoop(set_as_default=True) + NEW_DBUS = True + else: + import dbus.mainloop.glib + import dbus.dbus_bindings as dbus_bindings + NEW_DBUS = False + HAVE_DBUS = True + except Exception, e: + HAVE_DBUS = False + dbusError = e + +class SingleInstance: + def __init__(self): + uid = '' + if os.name == 'posix': + uid = str(os.geteuid()) + self.lockfile = os.path.normpath(tempfile.gettempdir() + '/emesene1-' + uid + '.lock') + + def is_running(self): + if os.name == 'posix': + import fcntl + self.fp = open(self.lockfile, 'w') + try: + fcntl.lockf(self.fp, fcntl.LOCK_EX | fcntl.LOCK_NB) + except IOError: + return True + return False + else: + try: + # if file already exists, we try to remove (in case previous execution was interrupted) + if(os.path.exists(self.lockfile)): + os.unlink(self.lockfile) + self.fd = os.open(self.lockfile, os.O_CREAT|os.O_EXCL|os.O_RDWR) + except OSError, e: + if e.errno == 13: + return True + print e.errno + return False + return False + + def show(self): + if HAVE_DBUS == False: + return + try: + self.bus = dbus.SessionBus() + self.dbus = self.bus.get_object(BUS_NAME, OBJECT_PATH) + self.dbus.show() + except Exception: + pass + + def __del__(self): + if os.name == 'nt': + if hasattr(self, 'fd'): + os.close(self.fd) + os.unlink(self.lockfile) + + diff -Nru emesene-1.6.1/TrayIcon.py emesene-1.6.3~peppermint1/TrayIcon.py --- emesene-1.6.1/TrayIcon.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/TrayIcon.py 2010-07-12 23:13:14.000000000 +0100 @@ -28,7 +28,6 @@ try: import egg.trayicon type_ = 'egg' - disabled = False except: print 'No tray icon library detected' disabled = True @@ -38,23 +37,18 @@ WM_LBUTTONUP = 0x0202 WM_RBUTTONUP = 0x0205 type_ = 'win' - disabled = False except: print 'No tray icon library detected' disabled = True -''' -############################################################################## -#TODO: -#- Find out how to set our nice icons -# because currently it does not work (i.e. after login, items aren't added) -############################################################################## -try: - import appindicator - type_ = 'indicator' - disabled = False -except: - pass -''' + +# WARNING: disable for release until stable enough. +#try: +# import appindicator +# type_ = 'indicator' +# disabled = False +#except: +# pass + class TrayIcon: '''This class creates the tray icon notification - Pre-GTK 2.10''' @@ -262,5 +256,5 @@ def getNotifyObject( self ): if not disabled and not type_ == 'gtk' and not type_ == 'indicator': return self.tray - - return None \ No newline at end of file + return None + diff -Nru emesene-1.6.1/UserPanel.py emesene-1.6.3~peppermint1/UserPanel.py --- emesene-1.6.1/UserPanel.py 2010-03-29 21:27:23.000000000 +0100 +++ emesene-1.6.3~peppermint1/UserPanel.py 2010-07-12 23:13:14.000000000 +0100 @@ -68,10 +68,10 @@ self.mailButton.set_relief(gtk.RELIEF_NONE) self.mailButton.set_tooltip_text(_('Click here to access your mail')) - i = self.controller.contacts.get_status() - status = self.controller.status_ordered[0][i] - self.statusIcon = self.theme.statusToPixbuf(status) + self.statusIcon = self.theme.statusToPixbuf(self.controller.msn.status) self.statusButton = ImageButton(self.statusIcon) + self.controller.msn.connect('self-status-changed',\ + self.update_status_icon) self.statusButton.set_relief(gtk.RELIEF_NONE) self.statusButton.set_tooltip_text(_('Click here to change your status')) @@ -126,11 +126,11 @@ self.pixbuf = self.controller.theme.getImage('userPanel') self.image.set_from_pixbuf(self.pixbuf) - self.tNick.connect('activate', self.on_nick_changed) - self.tNick.connect('focus-out-event', self.on_nick_changed) + self.tNick.connect('activate', self.on_nick_changed, None, False) + self.tNick.connect('focus-out-event', self.on_nick_changed, True) self.bNick.connect('clicked', self.on_nick_clicked) - self.tPersonalMessage.connect('activate', self.on_pm_changed) - self.tPersonalMessage.connect('focus-out-event', self.on_pm_changed) + self.tPersonalMessage.connect('activate', self.on_pm_changed, None, False) + self.tPersonalMessage.connect('focus-out-event', self.on_pm_changed, True) self.bPersonalMessage.connect('clicked', self.on_pm_clicked) self.mediaButton.connect("toggled", self.onToggleMedia) @@ -151,8 +151,6 @@ self.updateMailCount) self.statusButton.connect('button-press-event', self.pop_up_status_menu) - self.controller.msn.connect('self-status-changed',\ - self.update_status_icon) self.hbox = gtk.HBox() self.pack_start(self.imageEventBox, False, False) @@ -239,8 +237,9 @@ def on_nick_activate(self, *args): self.controller.contacts.set_nick(self.tNick.get_text()) - def on_nick_changed(self, *args): - self.controller.contacts.set_nick(self.tNick.get_text()) + def on_nick_changed(self, entry, event, update): + if update: + self.controller.contacts.set_nick(self.tNick.get_text()) self.tNick.hide() self.bNick.show() @@ -253,7 +252,7 @@ self.tNick.grab_focus() def nickRefresh(self): - self.on_nick_changed() + self.on_nick_changed(None, None, False) self.bNick.grab_focus() def nick_parse_hack(self): @@ -264,9 +263,9 @@ self.selfNickChanged(None, None, self.tNick.get_text()) self.personalMessageChanged(None, None, self.tPersonalMessage.get_text()) - def on_pm_changed(self, *args) : - self.controller.contacts.set_message(\ - self.tPersonalMessage.get_text()) + def on_pm_changed(self, entry, event, update) : + if update: + self.controller.contacts.set_message(self.tPersonalMessage.get_text()) self.bMedia.hide() self.lMedia.hide()