vcard.py 15.8 KB
Newer Older
nkour's avatar
nkour committed
1
##	vcard.py (has VcardWindow class and a func get_avatar_pixbuf_encoded_mime)
2
##
3 4
## Copyright (C) 2003-2006 Yann Le Boulanger <asterix@lagaule.org>
## Copyright (C) 2005-2006 Nikos Kouremenos <kourem@gmail.com>
5 6 7 8 9 10 11 12 13 14 15 16
##
## This program 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 2 only.
##
## This program 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.
##

import gtk
nkour's avatar
nkour committed
17
import gobject
18
import base64
19 20
import mimetypes
import os
21
import time
22 23
import locale

nkour's avatar
nkour committed
24
import gtkgui_helpers
nkour's avatar
nkour committed
25
import dialogs
nkour's avatar
nkour committed
26 27

from common import helpers
28
from common import gajim
sb's avatar
sb committed
29
from common.i18n import Q_
30

nkour's avatar
nkour committed
31
def get_avatar_pixbuf_encoded_mime(photo):
32 33 34 35 36
	'''return the pixbuf of the image
	photo is a dictionary containing PHOTO information'''
	if not isinstance(photo, dict):
		return None, None, None
	img_decoded = None
37 38
	avatar_encoded = None
	avatar_mime_type = None
sb's avatar
sb committed
39
	if photo.has_key('BINVAL'):
40 41 42 43 44 45 46
		img_encoded = photo['BINVAL']
		avatar_encoded = img_encoded
		try:
			img_decoded = base64.decodestring(img_encoded)
		except:
			pass
	if img_decoded:
sb's avatar
sb committed
47 48 49 50 51 52
		if photo.has_key('TYPE'):
			avatar_mime_type = photo['TYPE']
			pixbuf = gtkgui_helpers.get_pixbuf_from_data(img_decoded)
		else:
			pixbuf, avatar_mime_type = gtkgui_helpers.get_pixbuf_from_data(
							img_decoded, want_type=True)
53 54 55
	else:
		pixbuf = None
	return pixbuf, avatar_encoded, avatar_mime_type
56

57
class VcardWindow:
nkour's avatar
nkour committed
58
	'''Class for contact's information window'''
nkour's avatar
nkour committed
59

sb's avatar
sb committed
60
	def __init__(self, contact, account, is_fake = False):
61
		# the contact variable is the jid if vcard is true
62
		self.xml = gtkgui_helpers.get_glade('vcard_information_window.glade')
nkour's avatar
nkour committed
63
		self.window = self.xml.get_widget('vcard_information_window')
dkirov's avatar
dkirov committed
64
		self.progressbar = self.xml.get_widget('progressbar')
65

sb's avatar
sb committed
66
		self.contact = contact
nkour's avatar
nkour committed
67
		self.account = account
68
		self.is_fake = is_fake
sb's avatar
sb committed
69

nkour's avatar
nkour committed
70 71
		self.avatar_mime_type = None
		self.avatar_encoded = None
dkirov's avatar
dkirov committed
72 73 74 75
		self.vcard_arrived = False
		self.os_info_arrived = False
		self.update_progressbar_timeout_id = gobject.timeout_add(100,
			self.update_progressbar)
nkour's avatar
nkour committed
76

sb's avatar
sb committed
77
		self.fill_jabber_page()
nkour's avatar
nkour committed
78 79 80 81

		self.xml.signal_autoconnect(self)
		self.window.show_all()

dkirov's avatar
dkirov committed
82 83 84 85
	def update_progressbar(self):
		self.progressbar.pulse()
		return True # loop forever

86
	def on_vcard_information_window_destroy(self, widget):
dkirov's avatar
dkirov committed
87 88
		if self.update_progressbar_timeout_id is not None:
			gobject.source_remove(self.update_progressbar_timeout_id)
sb's avatar
sb committed
89
		del gajim.interface.instances[self.account]['infos'][self.contact.jid]
90 91

	def on_vcard_information_window_key_press_event(self, widget, event):
nkour's avatar
nkour committed
92
		if event.keyval == gtk.keysyms.Escape:
93 94
			self.window.destroy()

95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
	def on_log_history_checkbutton_toggled(self, widget):
		#log conversation history?
		oldlog = True
		no_log_for = gajim.config.get_per('accounts', self.account,
			'no_log_for').split()
		if self.contact.jid in no_log_for:
			oldlog = False
		log = widget.get_active()
		if not log and not self.contact.jid in no_log_for:
			no_log_for.append(self.contact.jid)
		if log and self.contact.jid in no_log_for:
			no_log_for.remove(self.contact.jid)
		if oldlog != log:
			gajim.config.set_per('accounts', self.account, 'no_log_for',
				' '.join(no_log_for))
110

sb's avatar
sb committed
111 112 113 114 115 116 117 118 119 120 121 122 123
	def on_PHOTO_eventbox_button_press_event(self, widget, event):
		'''If right-clicked, show popup'''
		if event.button == 3: # right click
			menu = gtk.Menu()
			menuitem = gtk.ImageMenuItem(gtk.STOCK_SAVE_AS)
			menuitem.connect('activate',
				gtkgui_helpers.on_avatar_save_as_menuitem_activate,
				self.contact.jid, self.account, self.contact.name + '.jpeg')
			menu.append(menuitem)
			menu.connect('selection-done', lambda w:w.destroy())	
			# show the menu
			menu.show_all()
			menu.popup(None, None, None, event.button, event.time)
124

125 126
	def set_value(self, entry_name, value):
		try:
dkirov's avatar
dkirov committed
127 128 129 130 131 132 133 134 135
			if value and entry_name == 'URL_label':
				if gtk.pygtk_version >= (2, 10, 0) and gtk.gtk_version >= (2, 10, 0):
					widget = gtk.LinkButton(value, value)
				else:
					widget = gtk.Label(value)
				table = self.xml.get_widget('personal_info_table')
				table.attach(widget, 1, 4, 3, 4, yoptions = 0)
			else:
				self.xml.get_widget(entry_name).set_text(value)
136
		except AttributeError:
137 138 139 140
			pass

	def set_values(self, vcard):
		for i in vcard.keys():
141
			if i == 'PHOTO':
142
				pixbuf, self.avatar_encoded, self.avatar_mime_type = \
nkour's avatar
nkour committed
143
					get_avatar_pixbuf_encoded_mime(vcard[i])
sb's avatar
sb committed
144
				image = self.xml.get_widget('PHOTO_image')
Yann Leboulanger's avatar
Yann Leboulanger committed
145
				if not pixbuf:
sb's avatar
sb committed
146 147
					image.set_from_icon_name('stock_person',
						gtk.ICON_SIZE_DIALOG)
Yann Leboulanger's avatar
Yann Leboulanger committed
148
					continue
149
				pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf, 'vcard')
150
				image.set_from_pixbuf(pixbuf)
151 152 153
				continue
			if i == 'ADR' or i == 'TEL' or i == 'EMAIL':
				for entry in vcard[i]:
154
					add_on = '_HOME'
155
					if 'WORK' in entry:
156
						add_on = '_WORK'
157
					for j in entry.keys():
sb's avatar
sb committed
158
						self.set_value(i + add_on + '_' + j + '_label', entry[j])
nkour's avatar
nkour committed
159
			if isinstance(vcard[i], dict):
160
				for j in vcard[i].keys():
sb's avatar
sb committed
161
					self.set_value(i + '_' + j + '_label', vcard[i][j])
162 163
			else:
				if i == 'DESC':
nkour's avatar
nkour committed
164 165
					self.xml.get_widget('DESC_textview').get_buffer().set_text(
						vcard[i], 0)
dkirov's avatar
dkirov committed
166
				elif i != 'jid': # Do not override jid_label
sb's avatar
sb committed
167
					self.set_value(i + '_label', vcard[i])
dkirov's avatar
dkirov committed
168 169 170 171 172 173 174 175 176
		self.vcard_arrived = True
		self.test_remove_progressbar()

	def test_remove_progressbar(self):
		if self.update_progressbar_timeout_id is not None and \
		self.vcard_arrived and self.os_info_arrived:
			gobject.source_remove(self.update_progressbar_timeout_id)
			self.progressbar.hide()
			self.update_progressbar_timeout_id = None
177 178 179 180

	def set_last_status_time(self):
		self.fill_status_label()

181
	def set_os_info(self, resource, client_info, os_info):
sb's avatar
sb committed
182 183
		if self.xml.get_widget('information_notebook').get_n_pages() < 4:
			return
184 185
		i = 0
		client = ''
nkour's avatar
nkour committed
186
		os = ''
187
		while self.os_info.has_key(i):
Yann Leboulanger's avatar
Yann Leboulanger committed
188 189
			if not self.os_info[i]['resource'] or \
					self.os_info[i]['resource'] == resource:
190
				self.os_info[i]['client'] = client_info
nkour's avatar
nkour committed
191
				self.os_info[i]['os'] = os_info
192 193
			if i > 0:
				client += '\n'
nkour's avatar
nkour committed
194
				os += '\n'
195
			client += self.os_info[i]['client']
nkour's avatar
nkour committed
196
			os += self.os_info[i]['os']
197
			i += 1
198 199

		if client == '':
200
			client = Q_('?Client:Unknown')
201
		if os == '':
202
			os = Q_('?OS:Unknown')
203
		self.xml.get_widget('client_name_version_label').set_text(client)
nkour's avatar
nkour committed
204
		self.xml.get_widget('os_label').set_text(os)
dkirov's avatar
dkirov committed
205 206
		self.os_info_arrived = True
		self.test_remove_progressbar()
207

208
	def fill_status_label(self):
sb's avatar
sb committed
209 210
		if self.xml.get_widget('information_notebook').get_n_pages() < 4:
			return
211 212 213 214 215 216 217 218 219 220 221 222
		contact_list = gajim.contacts.get_contact(self.account, self.contact.jid)
		# stats holds show and status message
		stats = ''
		one = True # Are we adding the first line ?
		if contact_list:
			for c in contact_list:
				if not one:
					stats += '\n'
				stats += helpers.get_uf_show(c.show)
				if c.status:
					stats += ': ' + c.status
				if c.last_status_time:
223
					stats += '\n' + _('since %s') % time.strftime('%c',
224
						c.last_status_time).decode(locale.getpreferredencoding())
225
				one = False
sb's avatar
sb committed
226
		else: # Maybe gc_vcard ?
227 228 229
			stats = helpers.get_uf_show(self.contact.show)
			if self.contact.status:
				stats += ': ' + self.contact.status
230 231 232 233 234 235 236 237
		status_label = self.xml.get_widget('status_label')
		status_label.set_max_width_chars(15)
		status_label.set_text(stats)

		tip = gtk.Tooltips()
		status_label_eventbox = self.xml.get_widget('status_label_eventbox')
		tip.set_tip(status_label_eventbox, stats)

238
	def fill_jabber_page(self):
239
		tooltips = gtk.Tooltips()
sb's avatar
sb committed
240 241 242 243
		self.xml.get_widget('nickname_label').set_markup(
			'<b><span size="x-large">' +
			self.contact.get_shown_name() +
			'</span></b>')
244
		self.xml.get_widget('jid_label').set_text(self.contact.jid)
245 246
		uf_sub = helpers.get_uf_sub(self.contact.sub)
		self.xml.get_widget('subscription_label').set_text(uf_sub)
247 248
		eb = self.xml.get_widget('subscription_label_eventbox')
		if self.contact.sub == 'from':
Yann Leboulanger's avatar
Yann Leboulanger committed
249
			tt_text = _("This contact is interested in your presence information, but you are not interested in his/her presence")
250 251 252 253 254 255 256 257
		elif self.contact.sub == 'to':
			tt_text = _("You are interested in the contact's presence information, but he/she is not interested in yours")
		elif self.contact.sub == 'both':
			tt_text = _("You and the contact are interested in each other's presence information")
		else: # None
			tt_text = _("You are not interested in the contact's presence, and neither he/she is interested in yours")
		tooltips.set_tip(eb, tt_text)

Vincent Hanquez's avatar
Vincent Hanquez committed
258
		label = self.xml.get_widget('ask_label')
259 260
		uf_ask = helpers.get_uf_ask(self.contact.ask)
		label.set_text(uf_ask)
261 262 263 264
		eb = self.xml.get_widget('ask_label_eventbox')
		if self.contact.ask == 'subscribe':
			tooltips.set_tip(eb,
			_("You are waiting contact's answer about your subscription request"))
265
		log = True
266
		if self.contact.jid in gajim.config.get_per('accounts', self.account,
267
			'no_log_for').split(' '):
268
			log = False
269 270 271 272
		checkbutton = self.xml.get_widget('log_history_checkbutton')
		checkbutton.set_active(log)
		checkbutton.connect('toggled', self.on_log_history_checkbutton_toggled)
		
273
		resources = '%s (%s)' % (self.contact.resource, unicode(
nkour's avatar
nkour committed
274
			self.contact.priority))
275
		uf_resources = self.contact.resource + _(' resource with priority ')\
276
			+ unicode(self.contact.priority)
277 278
		if not self.contact.status:
			self.contact.status = ''
279 280 281

		# Request list time status
		gajim.connections[self.account].request_last_status_time(self.contact.jid,
282
			self.contact.resource)
283

dkirov's avatar
dkirov committed
284 285 286 287
		# do not wait for os_info if contact is not connected
		if self.contact.show in ('offline', 'error'):
			self.os_info_arrived = True
		else: # Request os info if contact is connected
sb's avatar
sb committed
288 289
			gobject.idle_add(gajim.connections[self.account].request_os_info,
				self.contact.jid, self.contact.resource)
290
		self.os_info = {0: {'resource': self.contact.resource, 'client': '',
nkour's avatar
nkour committed
291
			'os': ''}}
292
		i = 1
293 294 295
		contact_list = gajim.contacts.get_contact(self.account, self.contact.jid)
		if contact_list:
			for c in contact_list:
296
				if c.resource != self.contact.resource:
297 298
					resources += '\n%s (%s)' % (c.resource,
						unicode(c.priority))
299 300 301
					uf_resources += '\n' + c.resource + \
						_(' resource with priority ') + unicode(c.priority)
					if c.show not in ('offline', 'error'):
sb's avatar
sb committed
302 303
						gobject.idle_add(
							gajim.connections[self.account].request_os_info, c.jid,
304 305
							c.resource)
					gajim.connections[self.account].request_last_status_time(c.jid,
306 307
						c.resource)
					self.os_info[i] = {'resource': c.resource, 'client': '',
308 309
						'os': ''}
					i += 1
310 311 312
		self.xml.get_widget('resource_prio_label').set_text(resources)
		resource_prio_label_eventbox = self.xml.get_widget(
			'resource_prio_label_eventbox')
313 314 315 316
		tooltips.set_tip(resource_prio_label_eventbox, uf_resources)

		self.fill_status_label()

317
		gajim.connections[self.account].request_vcard(self.contact.jid, self.is_fake)
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
	
	def on_close_button_clicked(self, widget):
		self.window.destroy()


class ZeroconfVcardWindow:
	def __init__(self, contact, account, is_fake = False):
		# the contact variable is the jid if vcard is true
		self.xml = gtkgui_helpers.get_glade('zeroconf_information_window.glade')
		self.window = self.xml.get_widget('zeroconf_information_window')

		self.contact = contact
		self.account = account
		self.is_fake = is_fake

	#	self.avatar_mime_type = None
	#	self.avatar_encoded = None

		self.fill_contact_page()
		self.fill_personal_page()

		self.xml.signal_autoconnect(self)
		self.window.show_all()

	def on_zeroconf_information_window_destroy(self, widget):
		del gajim.interface.instances[self.account]['infos'][self.contact.jid]

	def on_zeroconf_information_window_key_press_event(self, widget, event):
		if event.keyval == gtk.keysyms.Escape:
			self.window.destroy()

	def on_log_history_checkbutton_toggled(self, widget):
		#log conversation history?
		oldlog = True
		no_log_for = gajim.config.get_per('accounts', self.account,
			'no_log_for').split()
		if self.contact.jid in no_log_for:
			oldlog = False
		log = widget.get_active()
		if not log and not self.contact.jid in no_log_for:
			no_log_for.append(self.contact.jid)
		if log and self.contact.jid in no_log_for:
			no_log_for.remove(self.contact.jid)
		if oldlog != log:
			gajim.config.set_per('accounts', self.account, 'no_log_for',
				' '.join(no_log_for))

	def on_PHOTO_eventbox_button_press_event(self, widget, event):
		'''If right-clicked, show popup'''
		if event.button == 3: # right click
			menu = gtk.Menu()
			menuitem = gtk.ImageMenuItem(gtk.STOCK_SAVE_AS)
			menuitem.connect('activate',
				gtkgui_helpers.on_avatar_save_as_menuitem_activate,
				self.contact.jid, self.account, self.contact.name + '.jpeg')
			menu.append(menuitem)
			menu.connect('selection-done', lambda w:w.destroy())	
			# show the menu
			menu.show_all()
			menu.popup(None, None, None, event.button, event.time)

	def set_value(self, entry_name, value):
		try:
			if value and entry_name == 'URL_label':
				if gtk.pygtk_version >= (2, 10, 0) and gtk.gtk_version >= (2, 10, 0):
					widget = gtk.LinkButton(value, value)
				else:
					widget = gtk.Label(value)
				table = self.xml.get_widget('personal_info_table')
				table.attach(widget, 1, 4, 3, 4, yoptions = 0)
			else:
				self.xml.get_widget(entry_name).set_text(value)
		except AttributeError:
			pass

	def fill_status_label(self):
		if self.xml.get_widget('information_notebook').get_n_pages() < 2:
			return
		contact_list = gajim.contacts.get_contact(self.account, self.contact.jid)
		# stats holds show and status message
		stats = ''
		one = True # Are we adding the first line ?
		if contact_list:
			for c in contact_list:
				if not one:
					stats += '\n'
				stats += helpers.get_uf_show(c.show)
				if c.status:
					stats += ': ' + c.status
				if c.last_status_time:
					stats += '\n' + _('since %s') % time.strftime('%c',
						c.last_status_time).decode(locale.getpreferredencoding())
				one = False
		else: # Maybe gc_vcard ?
			stats = helpers.get_uf_show(self.contact.show)
			if self.contact.status:
				stats += ': ' + self.contact.status
		status_label = self.xml.get_widget('status_label')
		status_label.set_max_width_chars(15)
		status_label.set_text(stats)

		tip = gtk.Tooltips()
		status_label_eventbox = self.xml.get_widget('status_label_eventbox')
		tip.set_tip(status_label_eventbox, stats)
	
	def fill_contact_page(self):
		tooltips = gtk.Tooltips()
		self.xml.get_widget('nickname_label').set_markup(
			'<b><span size="x-large">' +
			self.contact.get_shown_name() +
			'</span></b>')
		self.xml.get_widget('local_jid_label').set_text(self.contact.jid)

		log = True
		if self.contact.jid in gajim.config.get_per('accounts', self.account,
			'no_log_for').split(' '):
			log = False
		checkbutton = self.xml.get_widget('log_history_checkbutton')
		checkbutton.set_active(log)
		checkbutton.connect('toggled', self.on_log_history_checkbutton_toggled)
		
		resources = '%s (%s)' % (self.contact.resource, unicode(
			self.contact.priority))
		uf_resources = self.contact.resource + _(' resource with priority ')\
			+ unicode(self.contact.priority)
		if not self.contact.status:
			self.contact.status = ''

		# Request list time status
	#	gajim.connections[self.account].request_last_status_time(self.contact.jid,
	#		self.contact.resource)

		self.xml.get_widget('resource_prio_label').set_text(resources)
		resource_prio_label_eventbox = self.xml.get_widget(
			'resource_prio_label_eventbox')
		tooltips.set_tip(resource_prio_label_eventbox, uf_resources)

		self.fill_status_label()

	#	gajim.connections[self.account].request_vcard(self.contact.jid, self.is_fake)
	
	def fill_personal_page(self):
		contact = gajim.connections[gajim.ZEROCONF_ACC_NAME].roster.getItem(self.contact.jid)
		self.xml.get_widget('first_name_label').set_text(contact['txt_dict']['1st'])
		self.xml.get_widget('last_name_label').set_text(contact['txt_dict']['last'])
		self.xml.get_widget('jabber_id_label').set_text(contact['txt_dict']['jid'])
		self.xml.get_widget('email_label').set_text(contact['txt_dict']['email'])
dkirov's avatar
dkirov committed
465 466 467

	def on_close_button_clicked(self, widget):
		self.window.destroy()