merge presence handling modifications changes

This commit is contained in:
Yann Leboulanger 2010-09-23 21:43:07 +02:00
commit e0ac19678c
31 changed files with 290 additions and 199 deletions

View file

@ -270,6 +270,8 @@
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show a list of emoticons (Alt+M)</property>
<property name="relief">none</property> <property name="relief">none</property>
<property name="focus_on_click">False</property> <property name="focus_on_click">False</property>
<child> <child>
@ -292,6 +294,8 @@
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show a list of formattings</property>
<property name="relief">none</property> <property name="relief">none</property>
<property name="focus_on_click">False</property> <property name="focus_on_click">False</property>
<child> <child>
@ -324,6 +328,8 @@
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="no_show_all">True</property> <property name="no_show_all">True</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Add this contact to roster (Ctrl+D)</property>
<property name="relief">none</property> <property name="relief">none</property>
<child> <child>
<object class="GtkImage" id="image9"> <object class="GtkImage" id="image9">
@ -365,6 +371,8 @@
<object class="GtkToggleButton" id="audio_togglebutton"> <object class="GtkToggleButton" id="audio_togglebutton">
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Toggle audio session</property>
<property name="relief">none</property> <property name="relief">none</property>
<child> <child>
<object class="GtkImage" id="audio_image"> <object class="GtkImage" id="audio_image">
@ -383,6 +391,8 @@
<object class="GtkToggleButton" id="video_togglebutton"> <object class="GtkToggleButton" id="video_togglebutton">
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Toggle video session</property>
<property name="relief">none</property> <property name="relief">none</property>
<child> <child>
<object class="GtkImage" id="video_image"> <object class="GtkImage" id="video_image">
@ -403,6 +413,8 @@
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Invite contacts to the conversation (Ctrl+G)</property>
<property name="relief">none</property> <property name="relief">none</property>
<property name="focus_on_click">False</property> <property name="focus_on_click">False</property>
<child> <child>
@ -425,6 +437,8 @@
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show the contact's profile (Ctrl+I)</property>
<property name="relief">none</property> <property name="relief">none</property>
<property name="focus_on_click">False</property> <property name="focus_on_click">False</property>
<child> <child>
@ -447,6 +461,8 @@
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Browse the chat history (Ctrl+H)</property>
<property name="relief">none</property> <property name="relief">none</property>
<property name="focus_on_click">False</property> <property name="focus_on_click">False</property>
<child> <child>
@ -480,6 +496,8 @@
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show a menu of advanced functions (Alt+D)</property>
<property name="relief">none</property> <property name="relief">none</property>
<property name="focus_on_click">False</property> <property name="focus_on_click">False</property>
<child> <child>

View file

@ -166,6 +166,8 @@
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show a list of emoticons (Alt+M)</property>
<property name="relief">none</property> <property name="relief">none</property>
<child> <child>
<object class="GtkImage" id="emoticons_button_image"> <object class="GtkImage" id="emoticons_button_image">
@ -193,6 +195,8 @@
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show a list of formattings</property>
<property name="relief">none</property> <property name="relief">none</property>
<property name="focus_on_click">False</property> <property name="focus_on_click">False</property>
<child> <child>
@ -224,6 +228,8 @@
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Change your nickname (Ctrl+N)</property>
<property name="relief">none</property> <property name="relief">none</property>
<child> <child>
<object class="GtkImage" id="image4"> <object class="GtkImage" id="image4">
@ -246,6 +252,8 @@
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Change the room's subject (Alt+T)</property>
<property name="relief">none</property> <property name="relief">none</property>
<child> <child>
<object class="GtkImage" id="image6"> <object class="GtkImage" id="image6">
@ -269,6 +277,8 @@
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="no_show_all">True</property> <property name="no_show_all">True</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Bookmark this room (Ctrl+B)</property>
<property name="relief">none</property> <property name="relief">none</property>
<child> <child>
<object class="GtkImage" id="image7"> <object class="GtkImage" id="image7">
@ -291,6 +301,8 @@
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Browse the chat history (Ctrl+H)</property>
<property name="relief">none</property> <property name="relief">none</property>
<child> <child>
<object class="GtkImage" id="image8"> <object class="GtkImage" id="image8">
@ -323,6 +335,8 @@
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show a menu of advanced functions (Alt+D)</property>
<property name="relief">none</property> <property name="relief">none</property>
<property name="focus_on_click">False</property> <property name="focus_on_click">False</property>
<child> <child>

View file

@ -3,8 +3,8 @@ INCLUDES = \
gajimpluginsdir = $(gajim_pluginsdir) gajimpluginsdir = $(gajim_pluginsdir)
nobase_dist_gajimplugins_PYTHON = \ nobase_dist_gajimplugins_PYTHON = \
$(srcdir)/*.py \
$(srcdir)/*/*.py \ $(srcdir)/*/*.py \
$(srcdir)/*/manifest.ini \
$(srcdir)/*/*.ui $(srcdir)/*/*.ui
MAINTAINERCLEANFILES = Makefile.in MAINTAINERCLEANFILES = Makefile.in

View file

@ -0,0 +1 @@
from acronyms_expander import AcronymsExpanderPlugin

View file

@ -33,12 +33,6 @@ from plugins import GajimPlugin
from plugins.helpers import log, log_calls from plugins.helpers import log, log_calls
class AcronymsExpanderPlugin(GajimPlugin): class AcronymsExpanderPlugin(GajimPlugin):
name = u'Acronyms Expander'
short_name = u'acronyms_expander'
version = u'0.1'
description = u'''Replaces acronyms (or other strings) with given expansions/substitutes.'''
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it'
@log_calls('AcronymsExpanderPlugin') @log_calls('AcronymsExpanderPlugin')
def init(self): def init(self):

View file

@ -0,0 +1,9 @@
[info]
name: Acronyms Expander
short_name: acronyms_expander
version: 0.1
description: Replaces acronyms (or other strings) with given expansions/substitutes.
authors: Mateusz Biliński <mateusz@bilinski.it>
homepage: http://blog.bilinski.it

View file

@ -0,0 +1,10 @@
[info]
name: Banner Tweaks
short_name: banner_tweaks
version: 0.1
description: Allows user to tweak chat window banner appearance (eg. make it compact).
Based on patch by pb in ticket #4133:
http://trac.gajim.org/attachment/ticket/4133.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it

View file

@ -43,15 +43,6 @@ from plugins.helpers import log, log_calls
from plugins.gui import GajimPluginConfigDialog from plugins.gui import GajimPluginConfigDialog
class BannerTweaksPlugin(GajimPlugin): class BannerTweaksPlugin(GajimPlugin):
name = u'Banner Tweaks'
short_name = u'banner_tweaks'
version = u'0.1'
description = u'''Allows user to tweak chat window banner appearance (eg. make it compact).
Based on patch by pb in ticket #4133:
http://trac.gajim.org/attachment/ticket/4133'''
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it'
@log_calls('BannerTweaksPlugin') @log_calls('BannerTweaksPlugin')
def init(self): def init(self):

View file

@ -0,0 +1,10 @@
[info]
name: D-Bus Support
short_name: dbus
version: 0.1
description: D-Bus support. Based on remote_control module from
Gajim core but uses new events handling system.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it

View file

@ -680,13 +680,6 @@ from plugins.helpers import log_calls, log
from common import ged from common import ged
class DBusPlugin(GajimPlugin): class DBusPlugin(GajimPlugin):
name = u'D-Bus Support'
short_name = u'dbus'
version = u'0.1'
description = u'''D-Bus support. Based on remote_control module from
Gajim core but uses new events handling system.'''
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it'
@log_calls('DBusPlugin') @log_calls('DBusPlugin')
def init(self): def init(self):

View file

@ -0,0 +1,8 @@
[info]
name: Events Dump
short_name: events_dump
version: 0.1
description: Dumps info about selected events to console.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it

View file

@ -33,12 +33,6 @@ from plugins.helpers import log_calls, log
from common import ged from common import ged
class EventsDumpPlugin(GajimPlugin): class EventsDumpPlugin(GajimPlugin):
name = u'Events Dump'
short_name = u'events_dump'
version = u'0.1'
description = u'''Dumps info about selected events to console.'''
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it'
@log_calls('EventsDumpPlugin') @log_calls('EventsDumpPlugin')
def init(self): def init(self):

View file

@ -0,0 +1,8 @@
[info]
name: Google Translation
short_name: google_translation
version: 0.1
description: Translates (currently only incoming) messages using Google Translate.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it

View file

@ -41,12 +41,6 @@ from common import ged
from common import nec from common import nec
class GoogleTranslationPlugin(GajimPlugin): class GoogleTranslationPlugin(GajimPlugin):
name = u'Google Translation'
short_name = u'google_translation'
version = u'0.1'
description = u'''Translates (currently only incoming) messages using Google Translate.'''
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it'
@log_calls('GoogleTranslationPlugin') @log_calls('GoogleTranslationPlugin')
def init(self): def init(self):

View file

@ -34,12 +34,6 @@ from plugins.helpers import log, log_calls
from plugins.gui import GajimPluginConfigDialog from plugins.gui import GajimPluginConfigDialog
class LengthNotifierPlugin(GajimPlugin): class LengthNotifierPlugin(GajimPlugin):
name = u'Message Length Notifier'
short_name = u'length_notifier'
version = u'0.1'
description = u'''Highlights message entry field in chat window when given length of message is exceeded.'''
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it'
@log_calls('LengthNotifierPlugin') @log_calls('LengthNotifierPlugin')
def init(self): def init(self):

View file

@ -0,0 +1,9 @@
[info]
name: Message Length Notifier
short_name: length_notifier
version: 0.1
description: Highlights message entry field in chat window when given length of message is exceeded.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it

View file

@ -0,0 +1,11 @@
[info]
name: New Events Example
short_name: new_events_example
version: 0.1
description: Shows how to generate new network events based on existing one using Network Events Controller.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it

View file

@ -38,12 +38,6 @@ from common import ged
from common import nec from common import nec
class NewEventsExamplePlugin(GajimPlugin): class NewEventsExamplePlugin(GajimPlugin):
name = u'New Events Example'
short_name = u'new_events_example'
version = u'0.1'
description = u'''Shows how to generate new network events based on existing one using Network Events Controller.'''
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it'
@log_calls('NewEventsExamplePlugin') @log_calls('NewEventsExamplePlugin')
def init(self): def init(self):

View file

@ -0,0 +1,10 @@
[info]
name: Roster Buttons
short_name: roster_buttons
version: 0.1
description: Adds quick action buttons to roster window.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it

View file

@ -34,12 +34,6 @@ from plugins import GajimPlugin
from plugins.helpers import log, log_calls from plugins.helpers import log, log_calls
class RosterButtonsPlugin(GajimPlugin): class RosterButtonsPlugin(GajimPlugin):
name = u'Roster Buttons'
short_name = u'roster_buttons'
version = u'0.1'
description = u'''Adds quick action buttons to roster window.'''
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it'
@log_calls('RosterButtonsPlugin') @log_calls('RosterButtonsPlugin')
def init(self): def init(self):

View file

@ -0,0 +1,11 @@
[info]
name: Snarl Notifications
short_name: snarl_notifications
version: 0.1
description: Shows events notification using Snarl (http://www.fullphat.net/) under Windows. Snarl needs to be installed in system.
PySnarl bindings are used (http://code.google.com/p/pysnarl/).
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it

View file

@ -38,13 +38,6 @@ from plugins.helpers import log_calls, log
from common import ged from common import ged
class SnarlNotificationsPlugin(GajimPlugin): class SnarlNotificationsPlugin(GajimPlugin):
name = u'Snarl Notifications'
short_name = u'snarl_notifications'
version = u'0.1'
description = u'''Shows events notification using Snarl (http://www.fullphat.net/) under Windows. Snarl needs to be installed in system.
PySnarl bindings are used (http://code.google.com/p/pysnarl/).'''
authors = [u'Mateusz Biliński <mateusz@bilinski.it>']
homepage = u'http://blog.bilinski.it'
@log_calls('SnarlNotificationsPlugin') @log_calls('SnarlNotificationsPlugin')
def init(self): def init(self):

View file

@ -1777,7 +1777,6 @@ ConnectionJingle, ConnectionIBBytestream):
obj.contact.contact_name != obj.contact_nickname: obj.contact.contact_name != obj.contact_nickname:
obj.contact.contact_name = obj.contact_nickname obj.contact.contact_name = obj.contact_nickname
obj.need_redraw = True obj.need_redraw = True
# gajim.interface.roster.draw_contact(jid, account)
if obj.old_show == obj.new_show and obj.contact.status == \ if obj.old_show == obj.new_show and obj.contact.status == \
obj.status and obj.contact.priority == obj.prio: # no change obj.status and obj.contact.priority == obj.prio: # no change
@ -1811,7 +1810,6 @@ ConnectionJingle, ConnectionIBBytestream):
obj.contact.resource = resource obj.contact.resource = resource
obj.need_add_in_roster = True obj.need_add_in_roster = True
# gajim.interface.roster.add_contact(jid, account)
if not gajim.jid_is_transport(jid) and len(obj.contact_list) == 1: if not gajim.jid_is_transport(jid) and len(obj.contact_list) == 1:
# It's not an agent # It's not an agent
@ -1827,7 +1825,6 @@ ConnectionJingle, ConnectionIBBytestream):
if jid in gajim.newly_added[account]: if jid in gajim.newly_added[account]:
gajim.newly_added[account].remove(jid) gajim.newly_added[account].remove(jid)
obj.need_redraw = True obj.need_redraw = True
# self.roster.draw_contact(jid, account)
obj.contact.show = obj.show obj.contact.show = obj.show
obj.contact.status = obj.status obj.contact.status = obj.status

View file

@ -632,9 +632,6 @@ class PresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
[])) []))
return return
jid_list = gajim.contacts.get_jid_list(self.conn.name) jid_list = gajim.contacts.get_jid_list(self.conn.name)
# if self.jid not in jid_list and self.jid != gajim.get_jid_from_account(
# self.conn.name):
# return
self.timestamp = None self.timestamp = None
self.get_id() self.get_id()
self.is_gc = False # is it a GC presence ? self.is_gc = False # is it a GC presence ?

View file

@ -246,6 +246,9 @@ class JingleRTPContent(JingleContent):
codecs = [] codecs = []
for codec in content.getTag('description').iterTags('payload-type'): for codec in content.getTag('description').iterTags('payload-type'):
if not codec['id'] or not codec['name'] or not codec['clockrate']:
# ignore invalid payload-types
continue
c = farsight.Codec(int(codec['id']), codec['name'], c = farsight.Codec(int(codec['id']), codec['name'],
self.farsight_media, int(codec['clockrate'])) self.farsight_media, int(codec['clockrate']))
if 'channels' in codec: if 'channels' in codec:

View file

@ -847,12 +847,10 @@ class PreferencesWindow:
gajim.config.set('trayicon', 'on_event') gajim.config.set('trayicon', 'on_event')
gajim.interface.systray_enabled = True gajim.interface.systray_enabled = True
gajim.interface.systray.show_icon() gajim.interface.systray.show_icon()
gajim.interface.systray.set_img()
else: else:
gajim.config.set('trayicon', 'always') gajim.config.set('trayicon', 'always')
gajim.interface.systray_enabled = True gajim.interface.systray_enabled = True
gajim.interface.systray.show_icon() gajim.interface.systray.show_icon()
gajim.interface.systray.set_img()
def on_advanced_notifications_button_clicked(self, widget): def on_advanced_notifications_button_clicked(self, widget):
dialogs.AdvancedNotificationsWindow() dialogs.AdvancedNotificationsWindow()

View file

@ -1480,12 +1480,15 @@ class WarningDialog(HigDialog):
HIG compliant warning dialog HIG compliant warning dialog
""" """
def __init__(self, pritext, sectext=''): def __init__(self, pritext, sectext='', transient_for=None):
HigDialog.__init__(self, None, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, HigDialog.__init__(self, None, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK,
pritext, sectext) pritext, sectext)
self.set_modal(False) self.set_modal(False)
if hasattr(gajim.interface, 'roster') and gajim.interface.roster: if transient_for is None and hasattr(gajim.interface, 'roster') and \
self.set_transient_for(gajim.interface.roster.window) gajim.interface.roster:
transient_for = gajim.interface.roster.window
if transient_for:
self.set_transient_for(transient_for)
self.popup() self.popup()
class InformationDialog(HigDialog): class InformationDialog(HigDialog):

View file

@ -1444,8 +1444,6 @@ class GroupchatControl(ChatControlBase):
con = gajim.connections[self.account] con = gajim.connections[self.account]
if gc_c and gc_c.jid: if gc_c and gc_c.jid:
real_jid = gc_c.jid real_jid = gc_c.jid
if gc_c.resource:
real_jid += '/' + gc_c.resource
else: else:
real_jid = fake_jid real_jid = fake_jid
if fake_jid in con.vcard_shas: if fake_jid in con.vcard_shas:

View file

@ -30,7 +30,7 @@ import pango
import gtk, gobject import gtk, gobject
import gtkgui_helpers import gtkgui_helpers
import dialogs from dialogs import WarningDialog, YesNoDialog, ArchiveChooserDialog
from common import gajim from common import gajim
from plugins.helpers import log_calls, log from plugins.helpers import log_calls, log
from common.exceptions import PluginsystemError from common.exceptions import PluginsystemError
@ -104,7 +104,7 @@ class PluginsWindow(object):
def _display_installed_plugin_info(self, plugin): def _display_installed_plugin_info(self, plugin):
self.plugin_name_label.set_text(plugin.name) self.plugin_name_label.set_text(plugin.name)
self.plugin_version_label.set_text(plugin.version) self.plugin_version_label.set_text(plugin.version)
self.plugin_authors_label.set_text(", ".join(plugin.authors)) self.plugin_authors_label.set_text(plugin.authors)
self.plugin_homepage_linkbutton.set_uri(plugin.homepage) self.plugin_homepage_linkbutton.set_uri(plugin.homepage)
self.plugin_homepage_linkbutton.set_label(plugin.homepage) self.plugin_homepage_linkbutton.set_label(plugin.homepage)
self.plugin_homepage_linkbutton.set_property('sensitive', True) self.plugin_homepage_linkbutton.set_property('sensitive', True)
@ -194,17 +194,26 @@ class PluginsWindow(object):
try: try:
gajim.plugin_manager.remove_plugin(plugin) gajim.plugin_manager.remove_plugin(plugin)
except PluginsystemError, e: except PluginsystemError, e:
dialogs.WarningDialog(_('Unable to properly remove the plugin'), WarningDialog(_('Unable to properly remove the plugin'),
str(e)) str(e), self.window)
return return
model.remove(iter) model.remove(iter)
@log_calls('PluginsWindow') @log_calls('PluginsWindow')
def on_install_plugin_button_clicked(self, widget): def on_install_plugin_button_clicked(self, widget):
def show_warn_dialog():
text = _('Archive is malformed')
dialog = WarningDialog(text, '', transient_for=self.window)
dialog.set_modal(False)
dialog.popup()
def _on_plugin_exists(zip_filename): def _on_plugin_exists(zip_filename):
def on_yes(is_checked): def on_yes(is_checked):
plugin = gajim.plugin_manager.install_from_zip(zip_filename, plugin = gajim.plugin_manager.install_from_zip(zip_filename,
True) True)
if not plugin:
show_warn_dialog()
return
model = self.installed_plugins_model model = self.installed_plugins_model
for row in xrange(len(model)): for row in xrange(len(model)):
@ -216,8 +225,8 @@ class PluginsWindow(object):
sel = self.installed_plugins_treeview.get_selection() sel = self.installed_plugins_treeview.get_selection()
sel.select_iter(iter_) sel.select_iter(iter_)
dialogs.YesNoDialog(_('Plugin already exists'), YesNoDialog(_('Plugin already exists'), sectext=_('Overwrite?'),
sectext=_('Overwrite?'), on_response_yes=on_yes) on_response_yes=on_yes)
def _try_install(zip_filename): def _try_install(zip_filename):
try: try:
@ -228,15 +237,17 @@ class PluginsWindow(object):
_on_plugin_exists(zip_filename) _on_plugin_exists(zip_filename)
return return
dialogs.WarningDialog(error_text, '"%s"' % zip_filename) WarningDialog(error_text, '"%s"' % zip_filename, self.window)
return
if not plugin:
show_warn_dialog()
return return
model = self.installed_plugins_model model = self.installed_plugins_model
iter_ = model.append([plugin, plugin.name, False]) iter_ = model.append([plugin, plugin.name, False])
sel = self.installed_plugins_treeview.get_selection() sel = self.installed_plugins_treeview.get_selection()
sel.select_iter(iter_) sel.select_iter(iter_)
self.dialog = dialogs.ArchiveChooserDialog(on_response_ok=_try_install) self.dialog = ArchiveChooserDialog(on_response_ok=_try_install)
class GajimPluginConfigDialog(gtk.Dialog): class GajimPluginConfigDialog(gtk.Dialog):

View file

@ -31,6 +31,7 @@ import sys
import fnmatch import fnmatch
import zipfile import zipfile
from shutil import rmtree from shutil import rmtree
import ConfigParser
from common import gajim from common import gajim
from common import nec from common import nec
@ -46,8 +47,9 @@ class PluginManager(object):
Currently: Currently:
- scans for plugins - scans for plugins
- activates them - activates them
- handles GUI extension points, when called by GUI objects after plugin - handles GUI extension points, when called by GUI objects after
is activated (by dispatching info about call to handlers in plugins) plugin is activated (by dispatching info about call to handlers
in plugins)
:todo: add more info about how GUI extension points work :todo: add more info about how GUI extension points work
:todo: add list of available GUI extension points :todo: add list of available GUI extension points
@ -58,10 +60,11 @@ class PluginManager(object):
deactivation handler) [DONE?] deactivation handler) [DONE?]
:todo: when plug-in is deactivated all GUI extension points are removed :todo: when plug-in is deactivated all GUI extension points are removed
from `PluginManager.gui_extension_points_handlers`. But when from `PluginManager.gui_extension_points_handlers`. But when
object that invoked GUI extension point is abandoned by Gajim, eg. object that invoked GUI extension point is abandoned by Gajim,
closed ChatControl object, the reference to called GUI extension eg. closed ChatControl object, the reference to called GUI
points is still in `PluginManager.gui_extension_points`. These extension points is still in `PluginManager.gui_extension_points`
should be removed, so that object can be destroyed by Python. These should be removed, so that object can be destroyed by
Python.
Possible solution: add call to clean up method in classes Possible solution: add call to clean up method in classes
'destructors' (classes that register GUI extension points) 'destructors' (classes that register GUI extension points)
''' '''
@ -96,16 +99,11 @@ class PluginManager(object):
''' '''
Registered handlers of GUI extension points. Registered handlers of GUI extension points.
''' '''
for path in gajim.PLUGINS_DIRS: for path in gajim.PLUGINS_DIRS:
self.add_plugins(PluginManager.scan_dir_for_plugins(path)) pc = PluginManager.scan_dir_for_plugins(path)
self.add_plugins(pc)
#log.debug('plugins: %s'%(self.plugins))
self._activate_all_plugins_from_global_config() self._activate_all_plugins_from_global_config()
#log.debug('active: %s'%(self.active_plugins))
@log_calls('PluginManager') @log_calls('PluginManager')
def _plugin_has_entry_in_global_config(self, plugin): def _plugin_has_entry_in_global_config(self, plugin):
if gajim.config.get_per('plugins', plugin.short_name) is None: if gajim.config.get_per('plugins', plugin.short_name) is None:
@ -117,6 +115,9 @@ class PluginManager(object):
def _create_plugin_entry_in_global_config(self, plugin): def _create_plugin_entry_in_global_config(self, plugin):
gajim.config.add_per('plugins', plugin.short_name) gajim.config.add_per('plugins', plugin.short_name)
def _remove_plugin_entry_in_global_config(self, plugin):
gajim.config.del_per('plugins', plugin.short_name)
@log_calls('PluginManager') @log_calls('PluginManager')
def add_plugin(self, plugin_class): def add_plugin(self, plugin_class):
''' '''
@ -132,8 +133,9 @@ class PluginManager(object):
self.plugins.append(plugin) self.plugins.append(plugin)
plugin.active = False plugin.active = False
else: else:
log.info('Not loading plugin %s v%s from module %s (identified by short name: %s). Plugin already loaded.'%( log.info('Not loading plugin %s v%s from module %s (identified by'
plugin.name, plugin.version, plugin.__module__, plugin.short_name)) ' short name: %s). Plugin already loaded.' % (plugin.name,
plugin.version, plugin.__module__, plugin.short_name))
@log_calls('PluginManager') @log_calls('PluginManager')
def add_plugins(self, plugin_classes): def add_plugins(self, plugin_classes):
@ -144,14 +146,14 @@ class PluginManager(object):
def gui_extension_point(self, gui_extpoint_name, *args): def gui_extension_point(self, gui_extpoint_name, *args):
''' '''
Invokes all handlers (from plugins) for particular GUI extension point Invokes all handlers (from plugins) for particular GUI extension point
and adds it to collection for further processing (eg. by plugins not active and adds it to collection for further processing (eg. by plugins not
yet). active yet).
:param gui_extpoint_name: name of GUI extension point. :param gui_extpoint_name: name of GUI extension point.
:type gui_extpoint_name: unicode :type gui_extpoint_name: unicode
:param args: parameters to be passed to extension point handlers :param args: parameters to be passed to extension point handlers
(typically and object that invokes `gui_extension_point`; however, (typically and object that invokes `gui_extension_point`;
this can be practically anything) however, this can be practically anything)
:type args: tuple :type args: tuple
:todo: GUI extension points must be documented well - names with :todo: GUI extension points must be documented well - names with
@ -162,12 +164,13 @@ class PluginManager(object):
:bug: what if only some handlers are successfully connected? we should :bug: what if only some handlers are successfully connected? we should
revert all those connections that where successfully made. Maybe revert all those connections that where successfully made. Maybe
call 'self._deactivate_plugin()' or sth similar. call 'self._deactivate_plugin()' or sth similar.
Looking closer - we only rewrite tuples here. Real check should be Looking closer - we only rewrite tuples here. Real check should
made in method that invokes gui_extpoints handlers. be made in method that invokes gui_extpoints handlers.
''' '''
self._add_gui_extension_point_call_to_list(gui_extpoint_name, *args) self._add_gui_extension_point_call_to_list(gui_extpoint_name, *args)
self._execute_all_handlers_of_gui_extension_point(gui_extpoint_name, *args) self._execute_all_handlers_of_gui_extension_point(gui_extpoint_name,
*args)
@log_calls('PluginManager') @log_calls('PluginManager')
def remove_gui_extension_point(self, gui_extpoint_name, *args): def remove_gui_extension_point(self, gui_extpoint_name, *args):
@ -191,11 +194,11 @@ class PluginManager(object):
extension points. The same arguments and the same name mean extension points. The same arguments and the same name mean
the same extension point. the same extension point.
:todo: instead of using argument to identify which extpoint should be :todo: instead of using argument to identify which extpoint should be
removed, maybe add additional 'id' argument - this would work similar removed, maybe add additional 'id' argument - this would work
hash in Python objects. 'id' would be calculated based on arguments similar hash in Python objects. 'id' would be calculated based
passed or on anything else (even could be constant). This would give on arguments passed or on anything else (even could be constant)
core developers (that add new extpoints) more freedom, but is this This would give core developers (that add new extpoints) more
necessary? freedom, but is this necessary?
:param gui_extpoint_name: name of GUI extension point. :param gui_extpoint_name: name of GUI extension point.
:type gui_extpoint_name: unicode :type gui_extpoint_name: unicode
@ -206,10 +209,8 @@ class PluginManager(object):
''' '''
if gui_extpoint_name in self.gui_extension_points: if gui_extpoint_name in self.gui_extension_points:
#log.debug('Removing GUI extpoint\n name: %s\n args: %s'%(gui_extpoint_name, args))
self.gui_extension_points[gui_extpoint_name].remove(args) self.gui_extension_points[gui_extpoint_name].remove(args)
@log_calls('PluginManager') @log_calls('PluginManager')
def _add_gui_extension_point_call_to_list(self, gui_extpoint_name, *args): def _add_gui_extension_point_call_to_list(self, gui_extpoint_name, *args):
''' '''
@ -226,36 +227,37 @@ class PluginManager(object):
:type gui_extpoint_name: str :type gui_extpoint_name: str
:param args: parameters to be passed to extension point handlers :param args: parameters to be passed to extension point handlers
(typically and object that invokes `gui_extension_point`; however, (typically and object that invokes `gui_extension_point`;
this can be practically anything) however, this can be practically anything)
:type args: tuple :type args: tuple
''' '''
if ((gui_extpoint_name not in self.gui_extension_points) if ((gui_extpoint_name not in self.gui_extension_points)
or (args not in self.gui_extension_points[gui_extpoint_name])): or (args not in self.gui_extension_points[gui_extpoint_name])):
self.gui_extension_points.setdefault(gui_extpoint_name, []).append(args) self.gui_extension_points.setdefault(gui_extpoint_name,[]).append(
args)
@log_calls('PluginManager') @log_calls('PluginManager')
def _execute_all_handlers_of_gui_extension_point(self, gui_extpoint_name, *args): def _execute_all_handlers_of_gui_extension_point(self, gui_extpoint_name,
*args):
if gui_extpoint_name in self.gui_extension_points_handlers: if gui_extpoint_name in self.gui_extension_points_handlers:
for handlers in self.gui_extension_points_handlers[gui_extpoint_name]: for handlers in self.gui_extension_points_handlers[
gui_extpoint_name]:
handlers[0](*args) handlers[0](*args)
def _register_events_handlers_in_ged(self, plugin): def _register_events_handlers_in_ged(self, plugin):
for event_name, handler in plugin.events_handlers.iteritems(): for event_name, handler in plugin.events_handlers.iteritems():
priority = handler[0] priority = handler[0]
handler_function = handler[1] handler_function = handler[1]
gajim.ged.register_event_handler(event_name, gajim.ged.register_event_handler(event_name, priority,
priority, handler_function)
handler_function)
def _remove_events_handler_from_ged(self, plugin): def _remove_events_handler_from_ged(self, plugin):
for event_name, handler in plugin.events_handlers.iteritems(): for event_name, handler in plugin.events_handlers.iteritems():
priority = handler[0] priority = handler[0]
handler_function = handler[1] handler_function = handler[1]
gajim.ged.remove_event_handler(event_name, gajim.ged.remove_event_handler(event_name, priority,
priority, handler_function)
handler_function)
def _register_network_events_in_nec(self, plugin): def _register_network_events_in_nec(self, plugin):
for event_class in plugin.events: for event_class in plugin.events:
@ -305,16 +307,18 @@ class PluginManager(object):
# remove GUI extension points handlers (provided by plug-in) from # remove GUI extension points handlers (provided by plug-in) from
# handlers list # handlers list
for gui_extpoint_name, gui_extpoint_handlers in \ for gui_extpoint_name, gui_extpoint_handlers in \
plugin.gui_extension_points.iteritems(): plugin.gui_extension_points.iteritems():
self.gui_extension_points_handlers[gui_extpoint_name].remove(gui_extpoint_handlers) self.gui_extension_points_handlers[gui_extpoint_name].remove(
gui_extpoint_handlers)
# detaching plug-in from handler GUI extension points (calling # detaching plug-in from handler GUI extension points (calling
# cleaning up method that must be provided by plug-in developer # cleaning up method that must be provided by plug-in developer
# for each handled GUI extension point) # for each handled GUI extension point)
for gui_extpoint_name, gui_extpoint_handlers in \ for gui_extpoint_name, gui_extpoint_handlers in \
plugin.gui_extension_points.iteritems(): plugin.gui_extension_points.iteritems():
if gui_extpoint_name in self.gui_extension_points: if gui_extpoint_name in self.gui_extension_points:
for gui_extension_point_args in self.gui_extension_points[gui_extpoint_name]: for gui_extension_point_args in self.gui_extension_points[
gui_extpoint_name]:
handler = gui_extpoint_handlers[1] handler = gui_extpoint_handlers[1]
if handler: if handler:
handler(*gui_extension_point_args) handler(*gui_extension_point_args)
@ -335,16 +339,17 @@ class PluginManager(object):
@log_calls('PluginManager') @log_calls('PluginManager')
def _add_gui_extension_points_handlers_from_plugin(self, plugin): def _add_gui_extension_points_handlers_from_plugin(self, plugin):
for gui_extpoint_name, gui_extpoint_handlers in \ for gui_extpoint_name, gui_extpoint_handlers in \
plugin.gui_extension_points.iteritems(): plugin.gui_extension_points.iteritems():
self.gui_extension_points_handlers.setdefault(gui_extpoint_name, []).append( self.gui_extension_points_handlers.setdefault(gui_extpoint_name,
gui_extpoint_handlers) []).append(gui_extpoint_handlers)
@log_calls('PluginManager') @log_calls('PluginManager')
def _handle_all_gui_extension_points_with_plugin(self, plugin): def _handle_all_gui_extension_points_with_plugin(self, plugin):
for gui_extpoint_name, gui_extpoint_handlers in \ for gui_extpoint_name, gui_extpoint_handlers in \
plugin.gui_extension_points.iteritems(): plugin.gui_extension_points.iteritems():
if gui_extpoint_name in self.gui_extension_points: if gui_extpoint_name in self.gui_extension_points:
for gui_extension_point_args in self.gui_extension_points[gui_extpoint_name]: for gui_extension_point_args in self.gui_extension_points[
gui_extpoint_name]:
handler = gui_extpoint_handlers[0] handler = gui_extpoint_handlers[0]
if handler: if handler:
handler(*gui_extension_point_args) handler(*gui_extension_point_args)
@ -356,7 +361,6 @@ class PluginManager(object):
Activated plugins are appended to `active_plugins` list. Activated plugins are appended to `active_plugins` list.
''' '''
#self.active_plugins = []
for plugin in self.plugins: for plugin in self.plugins:
self.activate_plugin(plugin) self.activate_plugin(plugin)
@ -390,71 +394,78 @@ class PluginManager(object):
:todo: add scanning zipped modules :todo: add scanning zipped modules
''' '''
plugins_found = [] plugins_found = []
if os.path.isdir(path): conf = ConfigParser.ConfigParser()
dir_list = os.listdir(path) fields = ('name', 'short_name', 'version', 'description', 'authors',
#log.debug(dir_list) 'homepage')
if not os.path.isdir(path):
return plugins_found
sys.path.insert(0, path) dir_list = os.listdir(path)
#log.debug(sys.path)
for elem_name in dir_list: sys.path.insert(0, path)
#log.debug('- "%s"'%(elem_name))
file_path = os.path.join(path, elem_name)
#log.debug(' "%s"'%(file_path))
module = None for elem_name in dir_list:
file_path = os.path.join(path, elem_name)
if os.path.isfile(file_path) and fnmatch.fnmatch(file_path, '*.py'): module = None
module_name = os.path.splitext(elem_name)[0]
#log.debug('Possible module detected.')
try:
module = __import__(module_name)
#log.debug('Module imported.')
except ValueError, value_error:
pass
#log.debug('Module not imported successfully. ValueError: %s'%(value_error))
except ImportError, import_error:
pass
#log.debug('Module not imported successfully. ImportError: %s'%(import_error))
elif os.path.isdir(file_path) and scan_dirs: if os.path.isfile(file_path) and fnmatch.fnmatch(file_path, '*.py'):
module_name = elem_name module_name = os.path.splitext(elem_name)[0]
file_path += os.path.sep try:
#log.debug('Possible package detected.') module = __import__(module_name)
try: except ValueError, value_error:
module = __import__(module_name) pass
#log.debug('Package imported.') except ImportError, import_error:
except ValueError, value_error: pass
pass
#log.debug('Package not imported successfully. ValueError: %s'%(value_error)) elif os.path.isdir(file_path) and scan_dirs:
except ImportError, import_error: module_name = elem_name
pass file_path += os.path.sep
#log.debug('Package not imported successfully. ImportError: %s'%(import_error)) try:
module = __import__(module_name)
except ValueError, value_error:
pass
except ImportError, import_error:
pass
if module: if module is None:
log.debug('Attributes processing started') continue
for module_attr_name in [attr_name for attr_name in dir(module)
if not (attr_name.startswith('__') or
attr_name.endswith('__'))]:
module_attr = getattr(module, module_attr_name)
log.debug('%s : %s'%(module_attr_name, module_attr))
try: manifest_path = os.path.join(os.path.dirname(file_path),
if issubclass(module_attr, GajimPlugin) and \ 'manifest.ini')
not module_attr is GajimPlugin: if scan_dirs and (not os.path.isfile(manifest_path)):
log.debug('is subclass of GajimPlugin') continue
#log.debug('file_path: %s\nabspath: %s\ndirname: %s'%(file_path, os.path.abspath(file_path), os.path.dirname(os.path.abspath(file_path))))
#log.debug('file_path: %s\ndirname: %s\nabspath: %s'%(file_path, os.path.dirname(file_path), os.path.abspath(os.path.dirname(file_path))))
module_attr.__path__ = os.path.abspath(os.path.dirname(file_path))
plugins_found.append(module_attr)
except TypeError, type_error:
pass
#log.debug('module_attr: %s, error : %s'%(
#module_name+'.'+module_attr_name,
#type_error))
#log.debug(module) log.debug('Attributes processing started')
for module_attr_name in [attr_name for attr_name in dir(module)
if not (attr_name.startswith('__') or attr_name.endswith('__'))]:
module_attr = getattr(module, module_attr_name)
log.debug('%s : %s' % (module_attr_name, module_attr))
try:
if not issubclass(module_attr, GajimPlugin) or \
module_attr is GajimPlugin:
continue
log.debug('is subclass of GajimPlugin')
module_attr.__path__ = os.path.abspath(
os.path.dirname(file_path))
# read metadata from manifest.ini
conf.readfp(open(manifest_path, 'r'))
for option in fields:
if conf.get('info', option) is '':
raise ConfigParser.NoOptionError, 'field empty'
setattr(module_attr, option, conf.get('info', option))
conf.remove_section('info')
plugins_found.append(module_attr)
except TypeError, type_error:
pass
except ConfigParser.NoOptionError, type_error:
# all fields are required
pass
return plugins_found return plugins_found
@ -475,6 +486,7 @@ class PluginManager(object):
raise PluginsystemError(_('Archive corrupted')) raise PluginsystemError(_('Archive corrupted'))
dirs = [] dirs = []
manifest = None
for filename in zip_file.namelist(): for filename in zip_file.namelist():
if filename.startswith('.') or filename.startswith('/') or \ if filename.startswith('.') or filename.startswith('/') or \
('/' not in filename): ('/' not in filename):
@ -482,16 +494,18 @@ class PluginManager(object):
raise PluginsystemError(_('Archive is malformed')) raise PluginsystemError(_('Archive is malformed'))
if filename.endswith('/') and filename.find('/', 0, -1) < 0: if filename.endswith('/') and filename.find('/', 0, -1) < 0:
dirs.append(filename) dirs.append(filename)
if 'manifest.ini' in filename.split('/')[1]:
manifest = True
if not manifest:
return
if len(dirs) > 1: if len(dirs) > 1:
# several directories in the root of the archive
raise PluginsystemError(_('Archive is malformed')) raise PluginsystemError(_('Archive is malformed'))
base_dir, user_dir = gajim.PLUGINS_DIRS base_dir, user_dir = gajim.PLUGINS_DIRS
plugin_dir = os.path.join(user_dir, dirs[0]) plugin_dir = os.path.join(user_dir, dirs[0])
if os.path.isdir(plugin_dir): if os.path.isdir(plugin_dir):
# Plugin already exists # Plugin dir already exists
if not owerwrite: if not owerwrite:
raise PluginsystemError(_('Plugin already exists')) raise PluginsystemError(_('Plugin already exists'))
self.remove_plugin(self.get_plugin_by_path(plugin_dir)) self.remove_plugin(self.get_plugin_by_path(plugin_dir))
@ -499,7 +513,10 @@ class PluginManager(object):
zip_file.extractall(user_dir) zip_file.extractall(user_dir)
zip_file.close() zip_file.close()
path = os.path.join(user_dir, dirs[0]) path = os.path.join(user_dir, dirs[0])
self.add_plugin(self.scan_dir_for_plugins(plugin_dir, False)[0]) plugins = self.scan_dir_for_plugins(plugin_dir, False)
if not plugins:
return
self.add_plugin(plugins[0])
plugin = self.plugins[-1] plugin = self.plugins[-1]
return plugin return plugin
@ -513,12 +530,15 @@ class PluginManager(object):
os.unlink(path) os.unlink(path)
return return
# access is denied or other # access is denied or other
raise PluginsystemError(error[1]) raise PluginsystemError(error[1][1])
if plugin.active: if plugin:
self.deactivate_plugin(plugin) if plugin.active:
rmtree(plugin.__path__, False, on_error) self.deactivate_plugin(plugin)
self.plugins.remove(plugin) rmtree(plugin.__path__, False, on_error)
self.plugins.remove(plugin)
if self._plugin_has_entry_in_global_config(plugin):
self._remove_plugin_entry_in_global_config(plugin)
def get_plugin_by_path(self, plugin_dir): def get_plugin_by_path(self, plugin_dir):
for plugin in self.plugins: for plugin in self.plugins:

View file

@ -97,7 +97,6 @@ class StatusIcon:
self.on_status_icon_size_changed) self.on_status_icon_size_changed)
self.set_img() self.set_img()
self.status_icon.set_visible(True)
self.subscribe_events() self.subscribe_events()
def on_status_icon_right_clicked(self, widget, event_button, event_time): def on_status_icon_right_clicked(self, widget, event_button, event_time):
@ -131,9 +130,14 @@ class StatusIcon:
""" """
if not gajim.interface.systray_enabled: if not gajim.interface.systray_enabled:
return return
if gajim.config.get('trayicon') == 'always':
self.status_icon.set_visible(True)
if gajim.events.get_nb_systray_events(): if gajim.events.get_nb_systray_events():
self.status_icon.set_visible(True)
self.status_icon.set_blinking(True) self.status_icon.set_blinking(True)
else: else:
if gajim.config.get('trayicon') == 'on_event':
self.status_icon.set_visible(False)
self.status_icon.set_blinking(False) self.status_icon.set_blinking(False)
image = gajim.interface.jabber_state_images[self.statusicon_size][ image = gajim.interface.jabber_state_images[self.statusicon_size][