~ubuntu-branches/ubuntu/lucid/gajim/lucid-security

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
# -*- coding:utf-8 -*-
## src/notify.py
##
## Copyright (C) 2005 Sebastian Estienne
## Copyright (C) 2005-2006 Andrew Sayman <lorien420 AT myrealbox.com>
## Copyright (C) 2005-2007 Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2005-2008 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2006 Travis Shirk <travis AT pobox.com>
## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
## Copyright (C) 2007 Julien Pivotto <roidelapluie AT gmail.com>
##                    Stephan Erb <steve-e AT h3c.de>
## Copyright (C) 2008 Brendan Taylor <whateley AT gmail.com>
##                    Jonathan Schleifer <js-gajim AT webkeks.org>
##
## This file is part of Gajim.
##
## Gajim 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; version 3 only.
##
## Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
##

import os
import time
import dialogs
import gobject
import gtkgui_helpers
import gtk

from common import gajim
from common import helpers

from common import dbus_support
if dbus_support.supported:
	import dbus
	import dbus.glib


USER_HAS_PYNOTIFY = True # user has pynotify module
try:
	import pynotify
	pynotify.init('Gajim Notification')
except ImportError:
	USER_HAS_PYNOTIFY = False

if gajim.HAVE_INDICATOR:
	import indicate

def setup_indicator_server():
	server = indicate.indicate_server_ref_default()
	server.set_type('message.im')
	server.set_desktop_file('/usr/share/applications/gajim.desktop')
	server.connect('server-display', server_display)
	server.show()

def display(indicator, account, jid, msg_type):
	gajim.interface.handle_event(account, jid, msg_type)
	indicator.hide()

def server_display(server):
	win = gajim.interface.roster.window
	win.present()

def get_show_in_roster(event, account, contact, session=None):
	'''Return True if this event must be shown in roster, else False'''
	if event == 'gc_message_received':
		return True
	num = get_advanced_notification(event, account, contact)
	if num is not None:
		if gajim.config.get_per('notifications', str(num), 'roster') == 'yes':
			return True
		if gajim.config.get_per('notifications', str(num), 'roster') == 'no':
			return False
	if event == 'message_received':
		if session and session.control:
			return False
	return True

def get_show_in_systray(event, account, contact, type_=None):
	'''Return True if this event must be shown in systray, else False'''
	num = get_advanced_notification(event, account, contact)
	if num is not None:
		if gajim.config.get_per('notifications', str(num), 'systray') == 'yes':
			return True
		if gajim.config.get_per('notifications', str(num), 'systray') == 'no':
			return False
	if type_ == 'printed_gc_msg' and not gajim.config.get(
	'notify_on_all_muc_messages'):
		# it's not an highlighted message, don't show in systray
		return False
	return gajim.config.get('trayicon_notification_on_events')

def get_advanced_notification(event, account, contact):
	'''Returns the number of the first (top most)
	advanced notification else None'''
	num = 0
	notif = gajim.config.get_per('notifications', str(num))
	while notif:
		recipient_ok = False
		status_ok = False
		tab_opened_ok = False
		# test event
		if gajim.config.get_per('notifications', str(num), 'event') == event:
			# test recipient
			recipient_type = gajim.config.get_per('notifications', str(num),
				'recipient_type')
			recipients = gajim.config.get_per('notifications', str(num),
				'recipients').split()
			if recipient_type == 'all':
				recipient_ok = True
			elif recipient_type == 'contact' and contact.jid in recipients:
				recipient_ok = True
			elif recipient_type == 'group':
				for group in contact.groups:
					if group in contact.groups:
						recipient_ok = True
						break
		if recipient_ok:
			# test status
			our_status = gajim.SHOW_LIST[gajim.connections[account].connected]
			status = gajim.config.get_per('notifications', str(num), 'status')
			if status == 'all' or our_status in status.split():
				status_ok = True
		if status_ok:
			# test window_opened
			tab_opened = gajim.config.get_per('notifications', str(num),
				'tab_opened')
			if tab_opened == 'both':
				tab_opened_ok = True
			else:
				chat_control = helpers.get_chat_control(account, contact)
				if (chat_control and tab_opened == 'yes') or (not chat_control and \
				tab_opened == 'no'):
					tab_opened_ok = True
		if tab_opened_ok:
			return num

		num += 1
		notif = gajim.config.get_per('notifications', str(num))

def notify(event, jid, account, parameters, advanced_notif_num=None):
	'''Check what type of notifications we want, depending on basic
	and the advanced configuration of notifications and do these notifications;
	advanced_notif_num holds the number of the first (top most) advanced
	notification'''
	# First, find what notifications we want
	do_popup = False
	do_sound = False
	do_cmd = False
	if event == 'status_change':
		new_show = parameters[0]
		status_message = parameters[1]
		# Default: No popup for status change
	elif event == 'contact_connected':
		status_message = parameters
		j = gajim.get_jid_without_resource(jid)
		server = gajim.get_server_from_jid(j)
		account_server = account + '/' + server
		block_transport = False
		if account_server in gajim.block_signed_in_notifications and \
		gajim.block_signed_in_notifications[account_server]:
			block_transport = True
		if helpers.allow_showing_notification(account, 'notify_on_signin') and \
		not gajim.block_signed_in_notifications[account] and not block_transport:
			do_popup = True
		if gajim.config.get_per('soundevents', 'contact_connected',
		'enabled') and not gajim.block_signed_in_notifications[account] and \
		not block_transport:
			do_sound = True
	elif event == 'contact_disconnected':
		status_message = parameters
		if helpers.allow_showing_notification(account, 'notify_on_signout'):
			do_popup = True
		if gajim.config.get_per('soundevents', 'contact_disconnected',
			'enabled'):
			do_sound = True
	elif event == 'new_message':
		message_type = parameters[0]
		is_first_message = parameters[1]
		nickname = parameters[2]
		if gajim.config.get('notification_preview_message'):
			message = parameters[3]
			if message.startswith('/me ') or message.startswith('/me\n'):
				message = '* ' + nickname + message[3:]
		else:
			# We don't want message preview, do_preview = False
			message = ''
		focused = parameters[4]
		if helpers.allow_showing_notification(account, 'notify_on_new_message',
		advanced_notif_num, is_first_message):
			do_popup = True
		if is_first_message and helpers.allow_sound_notification(account,
		'first_message_received', advanced_notif_num):
			do_sound = True
		elif not is_first_message and focused and \
		helpers.allow_sound_notification(account, 'next_message_received_focused',
		advanced_notif_num):
			do_sound = True
		elif not is_first_message and not focused and \
		helpers.allow_sound_notification(account,
		'next_message_received_unfocused', advanced_notif_num):
			do_sound = True
	else:
		print '*Event not implemeted yet*'

	if advanced_notif_num is not None and gajim.config.get_per('notifications',
	str(advanced_notif_num), 'run_command'):
		do_cmd = True

	# Do the wanted notifications
	if do_popup:
		if event in ('contact_connected', 'contact_disconnected',
		'status_change'): # Common code for popup for these three events
			if event == 'contact_disconnected':
				show_image = 'offline.png'
				suffix = '_notif_size_bw'
			else: #Status Change or Connected
				# FIXME: for status change,
				# we don't always 'online.png', but we
				# first need 48x48 for all status
				show_image = 'online.png'
				suffix = '_notif_size_colored'
			transport_name = gajim.get_transport_name_from_jid(jid)
			img = None
			if transport_name:
				img = os.path.join(helpers.get_transport_path(transport_name),
					'48x48', show_image)
			if not img or not os.path.isfile(img):
				iconset = gajim.config.get('iconset')
				img = os.path.join(helpers.get_iconset_path(iconset), '48x48',
					show_image)
			path = gtkgui_helpers.get_path_to_generic_or_avatar(img,
				jid = jid, suffix = suffix)
			if event == 'status_change':
				title = _('%(nick)s Changed Status') % \
					{'nick': gajim.get_name_from_jid(account, jid)}
				text = _('%(nick)s is now %(status)s') % \
					{'nick': gajim.get_name_from_jid(account, jid),\
					'status': helpers.get_uf_show(gajim.SHOW_LIST[new_show])}
				if status_message:
					text = text + " : " + status_message
				popup(_('Contact Changed Status'), jid, account,
					path_to_image=path, title=title, text=text)
			elif event == 'contact_connected':
				title = _('%(nickname)s Signed In') % \
					{'nickname': gajim.get_name_from_jid(account, jid)}
				text = ''
				if status_message:
					text = status_message
				popup(_('Contact Signed In'), jid, account,
					path_to_image=path, title=title, text=text)
			elif event == 'contact_disconnected':
				title = _('%(nickname)s Signed Out') % \
					{'nickname': gajim.get_name_from_jid(account, jid)}
				text = ''
				if status_message:
					text = status_message
				popup(_('Contact Signed Out'), jid, account,
					path_to_image=path, title=title, text=text)
		elif event == 'new_message':
			if message_type == 'normal': # single message
				event_type = _('New Single Message')
				img = os.path.join(gajim.DATA_DIR, 'pixmaps', 'events',
					'single_msg_recv.png')
				title = _('New Single Message from %(nickname)s') % \
					{'nickname': nickname}
				text = message
			elif message_type == 'pm': # private message
				event_type = _('New Private Message')
				room_name = gajim.get_nick_from_jid(jid)
				img = os.path.join(gajim.DATA_DIR, 'pixmaps', 'events',
					'priv_msg_recv.png')
				title = _('New Private Message from group chat %s') % room_name
				if message:
					text = _('%(nickname)s: %(message)s') % {'nickname': nickname,
						'message': message}
				else:
					text = _('Messaged by %(nickname)s') % {'nickname': nickname}

			else: # chat message
				event_type = _('New Message')
				img = os.path.join(gajim.DATA_DIR, 'pixmaps', 'events',
					'chat_msg_recv.png')
				title = _('New Message from %(nickname)s') % \
					{'nickname': nickname}
				text = message
			path = gtkgui_helpers.get_path_to_generic_or_avatar(img)
			popup(event_type, jid, account, message_type,
				path_to_image=path, title=title, text=text)

	if do_sound:
		snd_file = None
		snd_event = None # If not snd_file, play the event
		if event == 'new_message':
			if advanced_notif_num is not None and gajim.config.get_per(
			'notifications', str(advanced_notif_num), 'sound') == 'yes':
				snd_file = gajim.config.get_per('notifications',
					str(advanced_notif_num), 'sound_file')
			elif advanced_notif_num is not None and gajim.config.get_per(
			'notifications', str(advanced_notif_num), 'sound') == 'no':
				pass # do not set snd_event
			elif is_first_message:
				snd_event = 'first_message_received'
			elif focused:
				snd_event = 'next_message_received_focused'
			else:
				snd_event = 'next_message_received_unfocused'
		elif event in ('contact_connected', 'contact_disconnected'):
			snd_event = event
		if snd_file:
			helpers.play_sound_file(snd_file)
		if snd_event:
			helpers.play_sound(snd_event)

	if do_cmd:
		command = gajim.config.get_per('notifications', str(advanced_notif_num),
			'command')
		try:
			helpers.exec_command(command)
		except Exception:
			pass

def popup(event_type, jid, account, msg_type='', path_to_image=None,
	title=None, text=None):
	'''Notifies a user of an event. It first tries to a valid implementation of
	the Desktop Notification Specification. If that fails, then we fall back to
	the older style PopupNotificationWindow method.'''

	# default image
	if not path_to_image:
		path_to_image = os.path.abspath(
			os.path.join(gajim.DATA_DIR, 'pixmaps', 'events',
				'chat_msg_recv.png')) # img to display

	if gajim.HAVE_INDICATOR and event_type in (_('New Message'),
	_('New Single Message'), _('New Private Message')):
		indicator = indicate.Indicator()
		indicator.set_property('subtype', 'im')
		indicator.set_property('sender', jid)
		indicator.set_property('body', text)
		indicator.set_property_time('time', time.time())
		pixbuf = gtk.gdk.pixbuf_new_from_file(path_to_image)
		indicator.set_property_icon('icon', pixbuf)
		indicator.connect('user-display', display, account, jid, msg_type)
		indicator.show()

	# Try to show our popup via D-Bus and notification daemon
	if gajim.config.get('use_notif_daemon') and dbus_support.supported:
		try:
			DesktopNotification(event_type, jid, account, msg_type,
				path_to_image, title, gobject.markup_escape_text(text))
			return	# sucessfully did D-Bus Notification procedure!
		except dbus.DBusException, e:
			# Connection to D-Bus failed
			gajim.log.debug(str(e))
		except TypeError, e:
			# This means that we sent the message incorrectly
			gajim.log.debug(str(e))

	# Ok, that failed. Let's try pynotify, which also uses notification daemon
	if gajim.config.get('use_notif_daemon') and USER_HAS_PYNOTIFY:
		if not text and event_type == 'new_message':
			# empty text for new_message means do_preview = False
			# -> default value for text
			_text = gobject.markup_escape_text(
				gajim.get_name_from_jid(account, jid))
		else:
			_text = gobject.markup_escape_text(text)

		if not title:
			_title = ''
		else:
			_title = title

		notification = pynotify.Notification(_title, _text)
		timeout = gajim.config.get('notification_timeout') * 1000 # make it ms
		notification.set_timeout(timeout)

		notification.set_category(event_type)
		notification.set_data('event_type', event_type)
		notification.set_data('jid', jid)
		notification.set_data('account', account)
		notification.set_data('msg_type', msg_type)
		notification.set_property('icon-name', path_to_image)
		if 'actions' in pynotify.get_server_caps():
			notification.add_action('default', 'Default Action',
				on_pynotify_notification_clicked)

		try:
			notification.show()
			return
		except gobject.GError, e:
			# Connection to notification-daemon failed, see #2893
			gajim.log.debug(str(e))

	# Either nothing succeeded or the user wants old-style notifications
	instance = dialogs.PopupNotificationWindow(event_type, jid, account,
		msg_type, path_to_image, title, text)
	gajim.interface.roster.popup_notification_windows.append(instance)

def on_pynotify_notification_clicked(notification, action):
	jid = notification.get_data('jid')
	account = notification.get_data('account')
	msg_type = notification.get_data('msg_type')

	notification.close()
	gajim.interface.handle_event(account, jid, msg_type)

class NotificationResponseManager:
	'''Collects references to pending DesktopNotifications and manages there
	signalling. This is necessary due to a bug in DBus where you can't remove
	a signal from an interface once it's connected.'''
	def __init__(self):
		self.pending = {}
		self.received = []
		self.interface = None

	def attach_to_interface(self):
		if self.interface is not None:
			return
		self.interface = dbus_support.get_notifications_interface()
		self.interface.connect_to_signal('ActionInvoked', self.on_action_invoked)
		self.interface.connect_to_signal('NotificationClosed', self.on_closed)

	def on_action_invoked(self, id_, reason):
		self.received.append((id_, time.time(), reason))
		if id_ in self.pending:
			notification = self.pending[id_]
			notification.on_action_invoked(id_, reason)
			del self.pending[id_]
		if len(self.received) > 20:
			curt = time.time()
			for rec in self.received:
				diff = curt - rec[1]
				if diff > 10:
					self.received.remove(rec)

	def on_closed(self, id_, reason=None):
		if id_ in self.pending:
			del self.pending[id_]

	def add_pending(self, id_, object_):
		# Check to make sure that we handle an event immediately if we're adding
		# an id that's already been triggered
		for rec in self.received:
			if rec[0] == id_:
				object_.on_action_invoked(id_, rec[2])
				self.received.remove(rec)
				return
		if id_ not in self.pending:
			# Add it
			self.pending[id_] = object_
		else:
			# We've triggered an event that has a duplicate ID!
			gajim.log.debug('Duplicate ID of notification. Can\'t handle this.')

notification_response_manager = NotificationResponseManager()

class DesktopNotification:
	'''A DesktopNotification that interfaces with D-Bus via the Desktop
	Notification specification'''
	def __init__(self, event_type, jid, account, msg_type='',
		path_to_image=None, title=None, text=None):
		self.path_to_image = path_to_image
		self.event_type = event_type
		self.title = title
		self.text = text
		# 0.3.1 is the only version of notification daemon that has no way
		# to determine which version it is. If no method exists, it means
		# they're using that one.
		self.default_version = [0, 3, 1]
		self.account = account
		self.jid = jid
		self.msg_type = msg_type

		# default value of text
		if not text and event_type == 'new_message':
			# empty text for new_message means do_preview = False
			self.text = gajim.get_name_from_jid(account, jid)

		if not title:
			self.title = event_type # default value

		if event_type == _('Contact Signed In'):
			ntype = 'presence.online'
		elif event_type == _('Contact Signed Out'):
			ntype = 'presence.offline'
		elif event_type in (_('New Message'), _('New Single Message'),
			_('New Private Message')):
			ntype = 'im.received'
		elif event_type == _('File Transfer Request'):
			ntype = 'transfer'
		elif event_type == _('File Transfer Error'):
			ntype = 'transfer.error'
		elif event_type in (_('File Transfer Completed'),
		_('File Transfer Stopped')):
			ntype = 'transfer.complete'
		elif event_type == _('New E-mail'):
			ntype = 'email.arrived'
		elif event_type == _('Groupchat Invitation'):
			ntype = 'im.invitation'
		elif event_type == _('Contact Changed Status'):
			ntype = 'presence.status'
		elif event_type == _('Connection Failed'):
			ntype = 'connection.failed'
		elif event_type == _('Subscription request'):
			ntype = 'subscription.request'
		elif event_type == _('Unsubscribed'):
			ntype = 'unsubscribed'
		else:
			# default failsafe values
			self.path_to_image = os.path.abspath(
				os.path.join(gajim.DATA_DIR, 'pixmaps', 'events',
					'chat_msg_recv.png')) # img to display
			ntype = 'im' # Notification Type

		self.notif = dbus_support.get_notifications_interface(self)
		if self.notif is None:
			raise dbus.DBusException('unable to get notifications interface')
		self.ntype = ntype

		if self.kde_notifications:
			self.attempt_notify()
		else:
			self.capabilities = self.notif.GetCapabilities()
			if self.capabilities is None:
				self.capabilities = ['actions']
			self.get_version()

	def attempt_notify(self):
		timeout = gajim.config.get('notification_timeout') # in seconds
		ntype = self.ntype
		if self.kde_notifications:
			notification_text = ('<html><img src="%(image)s" align=left />' \
				'%(title)s<br/>%(text)s</html>') % {'title': self.title,
				'text': self.text, 'image': self.path_to_image}
			gajim_icon = os.path.abspath(os.path.join(gajim.DATA_DIR, 'pixmaps',
				'gajim.png'))
			self.notif.Notify(
				dbus.String(_('Gajim')),			# app_name (string)
				dbus.UInt32(0),						# replaces_id (uint)
				ntype,									# event_id (string)
				dbus.String(gajim_icon),			# app_icon (string)
				dbus.String(''),						# summary (string)
				dbus.String(notification_text),	# body (string)
				# actions (stringlist)
				(dbus.String('default'), dbus.String(self.event_type),
					dbus.String('ignore'), dbus.String(_('Ignore'))),
				[],										# hints (not used in KDE yet)
				dbus.UInt32(timeout*1000),			# timeout (int), in ms
				reply_handler=self.attach_by_id,
				error_handler=self.notify_another_way)
			return
		version = self.version
		if version[:2] == [0, 2]:
			actions = {}
			if 'actions' in self.capabilities:
				actions = {'default': 0}
			try:
				self.notif.Notify(
					dbus.String(_('Gajim')),
					dbus.String(self.path_to_image),
					dbus.UInt32(0),
					ntype,
					dbus.Byte(0),
					dbus.String(self.title),
					dbus.String(self.text),
					[dbus.String(self.path_to_image)],
					actions,
					[''],
					True,
					dbus.UInt32(timeout),
					reply_handler=self.attach_by_id,
					error_handler=self.notify_another_way)
			except AttributeError:
				version = [0, 3, 1] # we're actually dealing with the newer version
		if version > [0, 3]:
			if gajim.interface.systray_enabled and \
			gajim.config.get('attach_notifications_to_systray'):
				x, y = gajim.interface.systray.img_tray.window.get_origin()
				width, height, = \
					gajim.interface.systray.img_tray.window.get_geometry()[2:4]
				pos_x = x + (width / 2)
				pos_y = y + (height / 2)
				hints = {'x': pos_x, 'y': pos_y}
			else:
				hints = {}
			if version >= [0, 3, 2]:
				hints['urgency'] = dbus.Byte(0) # Low Urgency
				hints['category'] = dbus.String(ntype)
				# it seems notification-daemon doesn't like empty text
				if self.text:
					text = self.text
				else:
					text = ' '
				actions = ()
				if 'actions' in self.capabilities:
					actions = (dbus.String('default'), dbus.String(self.event_type))
				self.notif.Notify(
					dbus.String(_('Gajim')),
					dbus.UInt32(0), # this notification does not replace other
					dbus.String(self.path_to_image),
					dbus.String(self.title),
					dbus.String(text),
					actions,
					hints,
					dbus.UInt32(timeout*1000),
					reply_handler=self.attach_by_id,
					error_handler=self.notify_another_way)
			else:
				self.notif.Notify(
					dbus.String(_('Gajim')),
					dbus.String(self.path_to_image),
					dbus.UInt32(0),
					dbus.String(self.title),
					dbus.String(self.text),
					dbus.String(''),
					hints,
					dbus.UInt32(timeout*1000),
					reply_handler=self.attach_by_id,
					error_handler=self.notify_another_way)

	def attach_by_id(self, id_):
		self.id = id_
		notification_response_manager.attach_to_interface()
		notification_response_manager.add_pending(self.id, self)

	def notify_another_way(self,e):
		gajim.log.debug(str(e))
		gajim.log.debug('Need to implement a new way of falling back')

	def on_action_invoked(self, id_, reason):
		if self.notif is None:
			return
		self.notif.CloseNotification(dbus.UInt32(id_))
		self.notif = None

		if reason == 'ignore':
			return

		gajim.interface.handle_event(self.account, self.jid, self.msg_type)

	def version_reply_handler(self, name, vendor, version, spec_version=None):
		if spec_version:
			version = spec_version
		elif vendor == 'Xfce' and version.startswith('0.1.0'):
			version = '0.9'
		version_list = version.split('.')
		self.version = []
		try:
			while len(version_list):
				self.version.append(int(version_list.pop(0)))
		except ValueError:
			self.version_error_handler_3_x_try(None)
		self.attempt_notify()

	def get_version(self):
		self.notif.GetServerInfo(
			reply_handler=self.version_reply_handler,
			error_handler=self.version_error_handler_2_x_try)

	def version_error_handler_2_x_try(self, e):
		self.notif.GetServerInformation(reply_handler=self.version_reply_handler,
			error_handler=self.version_error_handler_3_x_try)

	def version_error_handler_3_x_try(self, e):
		self.version = self.default_version
		self.attempt_notify()

# vim: se ts=3: