more usage of NEC to handle messages
[gajim.git] / src / config.py
blob1db0d30bdbda5ee78aa9a31002dbe9396f09ee26
1 # -*- coding:utf-8 -*-
2 ## src/config.py
3 ##
4 ## Copyright (C) 2003-2005 Vincent Hanquez <tab AT snarc.org>
5 ## Copyright (C) 2003-2010 Yann Leboulanger <asterix AT lagaule.org>
6 ## Copyright (C) 2005 Alex Podaras <bigpod AT gmail.com>
7 ## Stéphan Kochen <stephan AT kochen.nl>
8 ## Copyright (C) 2005-2006 Dimitur Kirov <dkirov AT gmail.com>
9 ## Nikos Kouremenos <kourem AT gmail.com>
10 ## Copyright (C) 2006 Junglecow J <junglecow AT gmail.com>
11 ## Copyright (C) 2006-2007 Travis Shirk <travis AT pobox.com>
12 ## Stefan Bethge <stefan AT lanpartei.de>
13 ## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
14 ## Copyright (C) 2007 James Newton <redshodan AT gmail.com>
15 ## Julien Pivotto <roidelapluie AT gmail.com>
16 ## Copyright (C) 2007-2008 Stephan Erb <steve-e AT h3c.de>
17 ## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
19 ## This file is part of Gajim.
21 ## Gajim is free software; you can redistribute it and/or modify
22 ## it under the terms of the GNU General Public License as published
23 ## by the Free Software Foundation; version 3 only.
25 ## Gajim is distributed in the hope that it will be useful,
26 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
27 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 ## GNU General Public License for more details.
30 ## You should have received a copy of the GNU General Public License
31 ## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
34 import gtk
35 import gobject
36 import os, sys
37 import common.config
38 import common.sleepy
39 from common.i18n import Q_
41 import gtkgui_helpers
42 import dialogs
43 import cell_renderer_image
44 import message_control
45 import chat_control
46 import dataforms_widget
48 try:
49 import gtkspell
50 HAS_GTK_SPELL = True
51 except ImportError:
52 HAS_GTK_SPELL = False
54 from common import helpers
55 from common import gajim
56 from common import connection
57 from common import passwords
58 from common.zeroconf import connection_zeroconf
59 from common import dataforms
60 from common import gpg
61 from common import ged
63 try:
64 from common.multimedia_helpers import AudioInputManager, AudioOutputManager
65 from common.multimedia_helpers import VideoInputManager, VideoOutputManager
66 HAS_GST = True
67 except ImportError:
68 HAS_GST = False
70 from common.exceptions import GajimGeneralException
72 #---------- PreferencesWindow class -------------#
73 class PreferencesWindow:
74 """
75 Class for Preferences window
76 """
78 def on_preferences_window_destroy(self, widget):
79 """
80 Close window
81 """
82 del gajim.interface.instances['preferences']
84 def on_close_button_clicked(self, widget):
85 self.window.destroy()
87 def __init__(self):
88 """
89 Initialize Preferences window
90 """
91 self.xml = gtkgui_helpers.get_gtk_builder('preferences_window.ui')
92 self.window = self.xml.get_object('preferences_window')
93 self.window.set_transient_for(gajim.interface.roster.window)
94 self.notebook = self.xml.get_object('preferences_notebook')
95 self.one_window_type_combobox =\
96 self.xml.get_object('one_window_type_combobox')
97 self.iconset_combobox = self.xml.get_object('iconset_combobox')
98 self.notify_on_signin_checkbutton = self.xml.get_object(
99 'notify_on_signin_checkbutton')
100 self.notify_on_signout_checkbutton = self.xml.get_object(
101 'notify_on_signout_checkbutton')
102 self.auto_popup_away_checkbutton = self.xml.get_object(
103 'auto_popup_away_checkbutton')
104 self.sound_dnd_checkbutton = self.xml.get_object('sound_dnd_checkbutton')
105 self.auto_away_checkbutton = self.xml.get_object('auto_away_checkbutton')
106 self.auto_away_time_spinbutton = self.xml.get_object(
107 'auto_away_time_spinbutton')
108 self.auto_away_message_entry = self.xml.get_object(
109 'auto_away_message_entry')
110 self.auto_xa_checkbutton = self.xml.get_object('auto_xa_checkbutton')
111 self.auto_xa_time_spinbutton = self.xml.get_object(
112 'auto_xa_time_spinbutton')
113 self.auto_xa_message_entry = self.xml.get_object('auto_xa_message_entry')
115 ### General tab ###
116 # Display avatars in roster
117 st = gajim.config.get('show_avatars_in_roster')
118 self.xml.get_object('show_avatars_in_roster_checkbutton'). \
119 set_active(st)
121 # Display status msg under contact name in roster
122 st = gajim.config.get('show_status_msgs_in_roster')
123 self.xml.get_object('show_status_msgs_in_roster_checkbutton'). \
124 set_active( st)
126 # Display mood in roster
127 st = gajim.config.get('show_mood_in_roster')
128 self.xml.get_object('show_mood_in_roster_checkbutton'). \
129 set_active(st)
131 # Display activity in roster
132 st = gajim.config.get('show_activity_in_roster')
133 self.xml.get_object('show_activity_in_roster_checkbutton'). \
134 set_active(st)
136 # Display tunes in roster
137 st = gajim.config.get('show_tunes_in_roster')
138 self.xml.get_object('show_tunes_in_roster_checkbutton'). \
139 set_active(st)
141 # Display location in roster
142 st = gajim.config.get('show_location_in_roster')
143 self.xml.get_object('show_location_in_roster_checkbutton'). \
144 set_active(st)
146 # Sort contacts by show
147 st = gajim.config.get('sort_by_show_in_roster')
148 self.xml.get_object('sort_by_show_in_roster_checkbutton').set_active(st)
149 st = gajim.config.get('sort_by_show_in_muc')
150 self.xml.get_object('sort_by_show_in_muc_checkbutton').set_active(st)
152 # emoticons
153 emoticons_combobox = self.xml.get_object('emoticons_combobox')
154 emoticons_list = os.listdir(os.path.join(gajim.DATA_DIR, 'emoticons'))
155 # user themes
156 if os.path.isdir(gajim.MY_EMOTS_PATH):
157 emoticons_list += os.listdir(gajim.MY_EMOTS_PATH)
158 renderer_text = gtk.CellRendererText()
159 emoticons_combobox.pack_start(renderer_text, True)
160 emoticons_combobox.add_attribute(renderer_text, 'text', 0)
161 model = gtk.ListStore(str)
162 emoticons_combobox.set_model(model)
163 l = []
164 for dir_ in emoticons_list:
165 if not os.path.isdir(os.path.join(gajim.DATA_DIR, 'emoticons', dir_)) \
166 and not os.path.isdir(os.path.join(gajim.MY_EMOTS_PATH, dir_)) :
167 continue
168 if dir_ != '.svn':
169 l.append(dir_)
170 l.append(_('Disabled'))
171 for i in xrange(len(l)):
172 model.append([l[i]])
173 if gajim.config.get('emoticons_theme') == l[i]:
174 emoticons_combobox.set_active(i)
175 if not gajim.config.get('emoticons_theme'):
176 emoticons_combobox.set_active(len(l)-1)
178 # Set default for single window type
179 choices = common.config.opt_one_window_types
180 type_ = gajim.config.get('one_message_window')
181 if type_ in choices:
182 self.one_window_type_combobox.set_active(choices.index(type_))
183 else:
184 self.one_window_type_combobox.set_active(0)
186 # Compact View
187 st = gajim.config.get('compact_view')
188 self.xml.get_object('compact_view_checkbutton').set_active(st)
190 # Ignore XHTML
191 st = gajim.config.get('ignore_incoming_xhtml')
192 self.xml.get_object('xhtml_checkbutton').set_active(st)
194 # use speller
195 if HAS_GTK_SPELL:
196 st = gajim.config.get('use_speller')
197 self.xml.get_object('speller_checkbutton').set_active(st)
198 else:
199 self.xml.get_object('speller_checkbutton').set_sensitive(False)
201 ### Style tab ###
202 # Themes
203 theme_combobox = self.xml.get_object('theme_combobox')
204 cell = gtk.CellRendererText()
205 theme_combobox.pack_start(cell, True)
206 theme_combobox.add_attribute(cell, 'text', 0)
207 self.update_theme_list()
209 # iconset
210 iconsets_list = os.listdir(os.path.join(gajim.DATA_DIR, 'iconsets'))
211 if os.path.isdir(gajim.MY_ICONSETS_PATH):
212 iconsets_list += os.listdir(gajim.MY_ICONSETS_PATH)
213 # new model, image in 0, string in 1
214 model = gtk.ListStore(gtk.Image, str)
215 renderer_image = cell_renderer_image.CellRendererImage(0, 0)
216 renderer_text = gtk.CellRendererText()
217 renderer_text.set_property('xpad', 5)
218 self.iconset_combobox.pack_start(renderer_image, expand = False)
219 self.iconset_combobox.pack_start(renderer_text, expand = True)
220 self.iconset_combobox.set_attributes(renderer_text, text = 1)
221 self.iconset_combobox.add_attribute(renderer_image, 'image', 0)
222 self.iconset_combobox.set_model(model)
223 l = []
224 for dir in iconsets_list:
225 if not os.path.isdir(os.path.join(gajim.DATA_DIR, 'iconsets', dir)) \
226 and not os.path.isdir(os.path.join(gajim.MY_ICONSETS_PATH, dir)):
227 continue
228 if dir != '.svn' and dir != 'transports':
229 l.append(dir)
230 if l.count == 0:
231 l.append(' ')
232 for i in xrange(len(l)):
233 preview = gtk.Image()
234 files = []
235 files.append(os.path.join(helpers.get_iconset_path(l[i]), '16x16',
236 'online.png'))
237 files.append(os.path.join(helpers.get_iconset_path(l[i]), '16x16',
238 'online.gif'))
239 for file_ in files:
240 if os.path.exists(file_):
241 preview.set_from_file(file_)
242 model.append([preview, l[i]])
243 if gajim.config.get('iconset') == l[i]:
244 self.iconset_combobox.set_active(i)
246 # Use transports iconsets
247 st = gajim.config.get('use_transports_iconsets')
248 self.xml.get_object('transports_iconsets_checkbutton').set_active(st)
250 # Color widgets
251 self.draw_color_widgets()
253 # Font for messages
254 font = gajim.config.get('conversation_font')
255 # try to set default font for the current desktop env
256 fontbutton = self.xml.get_object('conversation_fontbutton')
257 if font == '':
258 fontbutton.set_sensitive(False)
259 self.xml.get_object('default_chat_font').set_active(True)
260 else:
261 fontbutton.set_font_name(font)
263 ### Personal Events tab ###
264 # outgoing send chat state notifications
265 st = gajim.config.get('outgoing_chat_state_notifications')
266 combo = self.xml.get_object('outgoing_chat_states_combobox')
267 if st == 'all':
268 combo.set_active(0)
269 elif st == 'composing_only':
270 combo.set_active(1)
271 else: # disabled
272 combo.set_active(2)
274 # displayed send chat state notifications
275 st = gajim.config.get('displayed_chat_state_notifications')
276 combo = self.xml.get_object('displayed_chat_states_combobox')
277 if st == 'all':
278 combo.set_active(0)
279 elif st == 'composing_only':
280 combo.set_active(1)
281 else: # disabled
282 combo.set_active(2)
285 ### Notifications tab ###
286 # On new event
287 on_event_combobox = self.xml.get_object('on_event_combobox')
288 if gajim.config.get('autopopup'):
289 on_event_combobox.set_active(0)
290 elif gajim.config.get('notify_on_new_message'):
291 on_event_combobox.set_active(1)
292 else:
293 on_event_combobox.set_active(2)
295 # notify on online statuses
296 st = gajim.config.get('notify_on_signin')
297 self.notify_on_signin_checkbutton.set_active(st)
299 # notify on offline statuses
300 st = gajim.config.get('notify_on_signout')
301 self.notify_on_signout_checkbutton.set_active(st)
303 # autopopupaway
304 st = gajim.config.get('autopopupaway')
305 self.auto_popup_away_checkbutton.set_active(st)
307 # sounddnd
308 st = gajim.config.get('sounddnd')
309 self.sound_dnd_checkbutton.set_active(st)
311 # Systray
312 systray_combobox = self.xml.get_object('systray_combobox')
313 if gajim.config.get('trayicon') == 'never':
314 systray_combobox.set_active(0)
315 elif gajim.config.get('trayicon') == 'on_event':
316 systray_combobox.set_active(1)
317 else:
318 systray_combobox.set_active(2)
320 # sounds
321 if gajim.config.get('sounds_on'):
322 self.xml.get_object('play_sounds_checkbutton').set_active(True)
323 else:
324 self.xml.get_object('manage_sounds_button').set_sensitive(False)
326 # Notify user of new gmail e-mail messages,
327 # make checkbox sensitive if user has a gtalk account
328 frame_gmail = self.xml.get_object('frame_gmail')
329 notify_gmail_checkbutton = self.xml.get_object('notify_gmail_checkbutton')
330 notify_gmail_extra_checkbutton = self.xml.get_object(
331 'notify_gmail_extra_checkbutton')
333 for account in gajim.config.get_per('accounts'):
334 jid = gajim.get_jid_from_account(account)
335 if gajim.get_server_from_jid(jid) in gajim.gmail_domains:
336 frame_gmail.set_sensitive(True)
337 st = gajim.config.get('notify_on_new_gmail_email')
338 notify_gmail_checkbutton.set_active(st)
339 st = gajim.config.get('notify_on_new_gmail_email_extra')
340 notify_gmail_extra_checkbutton.set_active(st)
341 break
343 #### Status tab ###
344 # Autoaway
345 st = gajim.config.get('autoaway')
346 self.auto_away_checkbutton.set_active(st)
348 # Autoawaytime
349 st = gajim.config.get('autoawaytime')
350 self.auto_away_time_spinbutton.set_value(st)
351 self.auto_away_time_spinbutton.set_sensitive(gajim.config.get('autoaway'))
353 # autoaway message
354 st = gajim.config.get('autoaway_message')
355 self.auto_away_message_entry.set_text(st)
356 self.auto_away_message_entry.set_sensitive(gajim.config.get('autoaway'))
358 # Autoxa
359 st = gajim.config.get('autoxa')
360 self.auto_xa_checkbutton.set_active(st)
362 # Autoxatime
363 st = gajim.config.get('autoxatime')
364 self.auto_xa_time_spinbutton.set_value(st)
365 self.auto_xa_time_spinbutton.set_sensitive(gajim.config.get('autoxa'))
367 # autoxa message
368 st = gajim.config.get('autoxa_message')
369 self.auto_xa_message_entry.set_text(st)
370 self.auto_xa_message_entry.set_sensitive(gajim.config.get('autoxa'))
372 from common import sleepy
373 if not sleepy.SUPPORTED:
374 self.xml.get_object('autoaway_table').set_sensitive(False)
376 # ask_status when online / offline
377 st = gajim.config.get('ask_online_status')
378 self.xml.get_object('prompt_online_status_message_checkbutton').\
379 set_active(st)
380 st = gajim.config.get('ask_offline_status')
381 self.xml.get_object('prompt_offline_status_message_checkbutton').\
382 set_active(st)
384 # Default Status messages
385 self.default_msg_tree = self.xml.get_object('default_msg_treeview')
386 col2 = self.default_msg_tree.rc_get_style().bg[gtk.STATE_ACTIVE].\
387 to_string()
388 # (status, translated_status, message, enabled)
389 model = gtk.ListStore(str, str, str, bool)
390 self.default_msg_tree.set_model(model)
391 col = gtk.TreeViewColumn(_('Status'))
392 col.set_resizable(True)
393 self.default_msg_tree.append_column(col)
394 renderer = gtk.CellRendererText()
395 col.pack_start(renderer, False)
396 col.set_attributes(renderer, text = 1)
397 col = gtk.TreeViewColumn(_('Default Message'))
398 col.set_resizable(True)
399 self.default_msg_tree.append_column(col)
400 renderer = gtk.CellRendererText()
401 col.pack_start(renderer, True)
402 col.set_attributes(renderer, text = 2)
403 renderer.connect('edited', self.on_default_msg_cell_edited)
404 renderer.set_property('editable', True)
405 renderer.set_property('cell-background', col2)
406 col = gtk.TreeViewColumn(_('Enabled'))
407 col.set_resizable(True)
408 self.default_msg_tree.append_column(col)
409 renderer = gtk.CellRendererToggle()
410 col.pack_start(renderer, False)
411 col.set_attributes(renderer, active = 3)
412 renderer.set_property('activatable', True)
413 renderer.connect('toggled', self.default_msg_toggled_cb)
414 self.fill_default_msg_treeview()
416 # Status messages
417 self.msg_tree = self.xml.get_object('msg_treeview')
418 model = gtk.ListStore(str, str, str, str, str, str, str)
419 self.msg_tree.set_model(model)
420 col = gtk.TreeViewColumn('name')
421 self.msg_tree.append_column(col)
422 renderer = gtk.CellRendererText()
423 col.pack_start(renderer, True)
424 col.set_attributes(renderer, text = 0)
425 renderer.connect('edited', self.on_msg_cell_edited)
426 renderer.set_property('editable', True)
427 self.fill_msg_treeview()
428 buf = self.xml.get_object('msg_textview').get_buffer()
429 buf.connect('changed', self.on_msg_textview_changed)
431 ### Audio / Video tab ###
432 def create_av_combobox(opt_name, device_dict, config_name=None,
433 key=None):
434 combobox = self.xml.get_object(opt_name + '_combobox')
435 cell = gtk.CellRendererText()
436 combobox.pack_start(cell, True)
437 combobox.add_attribute(cell, 'text', 0)
438 model = gtk.ListStore(str, str)
439 combobox.set_model(model)
440 if config_name:
441 config = gajim.config.get(config_name)
442 else:
443 config = gajim.config.get(opt_name + '_device')
445 for index, (name, value) in enumerate(sorted(device_dict.\
446 iteritems(), key=key)):
447 model.append((name, value))
448 if config == value:
449 combobox.set_active(index)
451 if HAS_GST:
452 create_av_combobox('audio_input', AudioInputManager().get_devices())
453 create_av_combobox('audio_output', AudioOutputManager().get_devices(
455 create_av_combobox('video_input', VideoInputManager().get_devices())
456 create_av_combobox('video_output', VideoOutputManager().get_devices(
459 create_av_combobox('video_framerate', {_('Default'): '',
460 '15fps': '15/1', '10fps': '10/1', '5fps': '5/1',
461 '2.5fps': '5/2'}, 'video_framerate', key=lambda x: -1 if \
462 not x[1] else float(x[0][:-3]))
463 create_av_combobox('video_size', {_('Default'): '',
464 '800x600': '800x600', '640x480': '640x480',
465 '320x240': '320x240'}, 'video_size', key=lambda x: -1 if \
466 not x[1] else int(x[0][:3]))
468 else:
469 for opt_name in ('audio_input', 'audio_output', 'video_input',
470 'video_output', 'video_framerate', 'video_size'):
471 combobox = self.xml.get_object(opt_name + '_combobox')
472 combobox.set_sensitive(False)
474 # STUN
475 cb = self.xml.get_object('stun_checkbutton')
476 st = gajim.config.get('use_stun_server')
477 cb.set_active(st)
479 entry = self.xml.get_object('stun_server_entry')
480 entry.set_text(gajim.config.get('stun_server'))
481 if not st:
482 entry.set_sensitive(False)
484 ### Advanced tab ###
485 # open links with
486 if os.name == 'nt':
487 applications_frame = self.xml.get_object('applications_frame')
488 applications_frame.set_no_show_all(True)
489 applications_frame.hide()
490 else:
491 self.applications_combobox = self.xml.get_object(
492 'applications_combobox')
493 self.xml.get_object('custom_apps_frame').hide()
494 self.xml.get_object('custom_apps_frame').set_no_show_all(True)
496 if gajim.config.get('autodetect_browser_mailer'):
497 self.applications_combobox.set_active(0)
498 # else autodetect_browser_mailer is False.
499 # so user has 'Always Use GNOME/KDE/Xfce' or Custom
500 elif gajim.config.get('openwith') == 'custom':
501 self.applications_combobox.set_active(1)
502 self.xml.get_object('custom_apps_frame').show()
504 self.xml.get_object('custom_browser_entry').set_text(
505 gajim.config.get('custombrowser'))
506 self.xml.get_object('custom_mail_client_entry').set_text(
507 gajim.config.get('custommailapp'))
508 self.xml.get_object('custom_file_manager_entry').set_text(
509 gajim.config.get('custom_file_manager'))
511 # log status changes of contacts
512 st = gajim.config.get('log_contact_status_changes')
513 self.xml.get_object('log_show_changes_checkbutton').set_active(st)
515 # log encrypted chat sessions
516 w = self.xml.get_object('log_encrypted_chats_checkbutton')
517 st = self.get_per_account_option('log_encrypted_sessions')
518 if st == 'mixed':
519 w.set_inconsistent(True)
520 else:
521 w.set_active(st)
523 # send os info
524 w = self.xml.get_object('send_os_info_checkbutton')
525 st = self.get_per_account_option('send_os_info')
526 if st == 'mixed':
527 w.set_inconsistent(True)
528 else:
529 w.set_active(st)
531 # send idle time
532 w = self.xml.get_object('send_idle_time_checkbutton')
533 st = self.get_per_account_option('send_idle_time')
534 if st == 'mixed':
535 w.set_inconsistent(True)
536 else:
537 w.set_active(st)
539 # check if gajm is default
540 st = gajim.config.get('check_if_gajim_is_default')
541 self.xml.get_object('check_default_client_checkbutton').set_active(st)
543 # Ignore messages from unknown contacts
544 w = self.xml.get_object('ignore_events_from_unknown_contacts_checkbutton')
545 st = self.get_per_account_option('ignore_unknown_contacts')
546 if st == 'mixed':
547 w.set_inconsistent(True)
548 else:
549 w.set_active(st)
551 self.xml.connect_signals(self)
553 self.msg_tree.get_model().connect('row-changed',
554 self.on_msg_treemodel_row_changed)
555 self.msg_tree.get_model().connect('row-deleted',
556 self.on_msg_treemodel_row_deleted)
557 self.default_msg_tree.get_model().connect('row-changed',
558 self.on_default_msg_treemodel_row_changed)
560 self.theme_preferences = None
561 self.sounds_preferences = None
563 self.notebook.set_current_page(0)
565 self.window.show_all()
566 gtkgui_helpers.possibly_move_window_in_current_desktop(self.window)
568 def on_preferences_window_key_press_event(self, widget, event):
569 if event.keyval == gtk.keysyms.Escape:
570 self.window.hide()
572 def get_per_account_option(self, opt):
574 Return the value of the option opt if it's the same in all accounts else
575 returns "mixed"
577 if len(gajim.connections) == 0:
578 # a non existant key return default value
579 return gajim.config.get_per('accounts', '__default__', opt)
580 val = None
581 for account in gajim.connections:
582 v = gajim.config.get_per('accounts', account, opt)
583 if val is None:
584 val = v
585 elif val != v:
586 return 'mixed'
587 return val
589 def on_checkbutton_toggled(self, widget, config_name,
590 change_sensitivity_widgets=None):
591 gajim.config.set(config_name, widget.get_active())
592 if change_sensitivity_widgets:
593 for w in change_sensitivity_widgets:
594 w.set_sensitive(widget.get_active())
595 gajim.interface.save_config()
597 def on_per_account_checkbutton_toggled(self, widget, config_name,
598 change_sensitivity_widgets=None):
599 for account in gajim.connections:
600 gajim.config.set_per('accounts', account, config_name,
601 widget.get_active())
602 if change_sensitivity_widgets:
603 for w in change_sensitivity_widgets:
604 w.set_sensitive(widget.get_active())
605 gajim.interface.save_config()
607 def _get_all_controls(self):
608 for ctrl in gajim.interface.msg_win_mgr.get_controls():
609 yield ctrl
610 for account in gajim.connections:
611 for ctrl in gajim.interface.minimized_controls[account].values():
612 yield ctrl
614 def _get_all_muc_controls(self):
615 for ctrl in gajim.interface.msg_win_mgr.get_controls(
616 message_control.TYPE_GC):
617 yield ctrl
618 for account in gajim.connections:
619 for ctrl in gajim.interface.minimized_controls[account].values():
620 yield ctrl
622 def on_sort_by_show_in_roster_checkbutton_toggled(self, widget):
623 self.on_checkbutton_toggled(widget, 'sort_by_show_in_roster')
624 gajim.interface.roster.setup_and_draw_roster()
626 def on_sort_by_show_in_muc_checkbutton_toggled(self, widget):
627 self.on_checkbutton_toggled(widget, 'sort_by_show_in_muc')
628 # Redraw groupchats
629 for ctrl in self._get_all_muc_controls():
630 ctrl.draw_roster()
632 def on_show_avatars_in_roster_checkbutton_toggled(self, widget):
633 self.on_checkbutton_toggled(widget, 'show_avatars_in_roster')
634 gajim.interface.roster.setup_and_draw_roster()
635 # Redraw groupchats (in an ugly way)
636 for ctrl in self._get_all_muc_controls():
637 ctrl.draw_roster()
639 def on_show_status_msgs_in_roster_checkbutton_toggled(self, widget):
640 self.on_checkbutton_toggled(widget, 'show_status_msgs_in_roster')
641 gajim.interface.roster.setup_and_draw_roster()
642 for ctrl in self._get_all_muc_controls():
643 ctrl.update_ui()
645 def on_show_mood_in_roster_checkbutton_toggled(self, widget):
646 self.on_checkbutton_toggled(widget, 'show_mood_in_roster')
647 gajim.interface.roster.setup_and_draw_roster()
649 def on_show_activity_in_roster_checkbutton_toggled(self, widget):
650 self.on_checkbutton_toggled(widget, 'show_activity_in_roster')
651 gajim.interface.roster.setup_and_draw_roster()
653 def on_show_tunes_in_roster_checkbutton_toggled(self, widget):
654 self.on_checkbutton_toggled(widget, 'show_tunes_in_roster')
655 gajim.interface.roster.setup_and_draw_roster()
657 def on_show_location_in_roster_checkbutton_toggled(self, widget):
658 self.on_checkbutton_toggled(widget, 'show_location_in_roster')
659 gajim.interface.roster.setup_and_draw_roster()
661 def on_emoticons_combobox_changed(self, widget):
662 active = widget.get_active()
663 model = widget.get_model()
664 emot_theme = model[active][0].decode('utf-8')
665 if emot_theme == _('Disabled'):
666 gajim.config.set('emoticons_theme', '')
667 else:
668 gajim.config.set('emoticons_theme', emot_theme)
670 gajim.interface.init_emoticons(need_reload = True)
671 gajim.interface.make_regexps()
672 self.toggle_emoticons()
674 def toggle_emoticons(self):
676 Update emoticons state in Opened Chat Windows
678 for ctrl in self._get_all_controls():
679 ctrl.toggle_emoticons()
681 def on_one_window_type_combo_changed(self, widget):
682 active = widget.get_active()
683 config_type = common.config.opt_one_window_types[active]
684 gajim.config.set('one_message_window', config_type)
685 gajim.interface.save_config()
686 gajim.interface.msg_win_mgr.reconfig()
688 def on_compact_view_checkbutton_toggled(self, widget):
689 active = widget.get_active()
690 for ctrl in self._get_all_controls():
691 ctrl.chat_buttons_set_visible(active)
692 gajim.config.set('compact_view', active)
693 gajim.interface.save_config()
695 def on_xhtml_checkbutton_toggled(self, widget):
696 self.on_checkbutton_toggled(widget, 'ignore_incoming_xhtml')
697 helpers.update_optional_features()
699 def apply_speller(self):
700 for ctrl in self._get_all_controls():
701 if isinstance(ctrl, chat_control.ChatControlBase):
702 try:
703 spell_obj = gtkspell.get_from_text_view(ctrl.msg_textview)
704 except (TypeError, RuntimeError, OSError):
705 spell_obj = None
707 if not spell_obj:
708 ctrl.set_speller()
710 def remove_speller(self):
711 for ctrl in self._get_all_controls():
712 if isinstance(ctrl, chat_control.ChatControlBase):
713 try:
714 spell_obj = gtkspell.get_from_text_view(ctrl.msg_textview)
715 except (TypeError, RuntimeError):
716 spell_obj = None
717 if spell_obj:
718 spell_obj.detach()
720 def on_speller_checkbutton_toggled(self, widget):
721 active = widget.get_active()
722 gajim.config.set('use_speller', active)
723 gajim.interface.save_config()
724 if active:
725 lang = gajim.config.get('speller_language')
726 if not lang:
727 lang = gajim.LANG
728 tv = gtk.TextView()
729 try:
730 gtkspell.Spell(tv, lang)
731 except (TypeError, RuntimeError, OSError):
732 dialogs.ErrorDialog(
733 _('Dictionary for lang %s not available') % lang,
734 _('You have to install %s dictionary to use spellchecking, or '
735 'choose another language by setting the speller_language option.'
736 ) % lang)
737 gajim.config.set('use_speller', False)
738 widget.set_active(False)
739 else:
740 gajim.config.set('speller_language', lang)
741 self.apply_speller()
742 else:
743 self.remove_speller()
745 def on_theme_combobox_changed(self, widget):
746 model = widget.get_model()
747 active = widget.get_active()
748 config_theme = model[active][0].decode('utf-8').replace(' ', '_')
750 gajim.config.set('roster_theme', config_theme)
752 # begin repainting themed widgets throughout
753 gajim.interface.roster.repaint_themed_widgets()
754 gajim.interface.roster.change_roster_style(None)
755 gajim.interface.save_config()
757 def update_theme_list(self):
758 theme_combobox = self.xml.get_object('theme_combobox')
759 model = gtk.ListStore(str)
760 theme_combobox.set_model(model)
761 i = 0
762 for config_theme in gajim.config.get_per('themes'):
763 theme = config_theme.replace('_', ' ')
764 model.append([theme])
765 if gajim.config.get('roster_theme') == config_theme:
766 theme_combobox.set_active(i)
767 i += 1
769 def on_manage_theme_button_clicked(self, widget):
770 if self.theme_preferences is None:
771 self.theme_preferences = dialogs.GajimThemesWindow()
772 else:
773 self.theme_preferences.window.present()
774 self.theme_preferences.select_active_theme()
776 def on_iconset_combobox_changed(self, widget):
777 model = widget.get_model()
778 active = widget.get_active()
779 icon_string = model[active][1].decode('utf-8')
780 gajim.config.set('iconset', icon_string)
781 gtkgui_helpers.reload_jabber_state_images()
782 gajim.interface.save_config()
784 def on_transports_iconsets_checkbutton_toggled(self, widget):
785 self.on_checkbutton_toggled(widget, 'use_transports_iconsets')
786 gtkgui_helpers.reload_jabber_state_images()
788 def on_outgoing_chat_states_combobox_changed(self, widget):
789 active = widget.get_active()
790 old_value = gajim.config.get('outgoing_chat_state_notifications')
791 if active == 0: # all
792 gajim.config.set('outgoing_chat_state_notifications', 'all')
793 elif active == 1: # only composing
794 gajim.config.set('outgoing_chat_state_notifications', 'composing_only')
795 else: # disabled
796 gajim.config.set('outgoing_chat_state_notifications', 'disabled')
797 new_value = gajim.config.get('outgoing_chat_state_notifications')
798 if 'disabled' in (old_value, new_value):
799 # we changed from disabled to sth else or vice versa
800 helpers.update_optional_features()
802 def on_displayed_chat_states_combobox_changed(self, widget):
803 active = widget.get_active()
804 if active == 0: # all
805 gajim.config.set('displayed_chat_state_notifications', 'all')
806 elif active == 1: # only composing
807 gajim.config.set('displayed_chat_state_notifications',
808 'composing_only')
809 else: # disabled
810 gajim.config.set('displayed_chat_state_notifications', 'disabled')
812 def on_ignore_events_from_unknown_contacts_checkbutton_toggled(self, widget):
813 widget.set_inconsistent(False)
814 self.on_per_account_checkbutton_toggled(widget, 'ignore_unknown_contacts')
816 def on_on_event_combobox_changed(self, widget):
817 active = widget.get_active()
818 if active == 0:
819 gajim.config.set('autopopup', True)
820 gajim.config.set('notify_on_new_message', False)
821 elif active == 1:
822 gajim.config.set('autopopup', False)
823 gajim.config.set('notify_on_new_message', True)
824 else:
825 gajim.config.set('autopopup', False)
826 gajim.config.set('notify_on_new_message', False)
828 def on_notify_on_signin_checkbutton_toggled(self, widget):
829 self.on_checkbutton_toggled(widget, 'notify_on_signin')
831 def on_notify_on_signout_checkbutton_toggled(self, widget):
832 self.on_checkbutton_toggled(widget, 'notify_on_signout')
834 def on_auto_popup_away_checkbutton_toggled(self, widget):
835 self.on_checkbutton_toggled(widget, 'autopopupaway')
837 def on_sound_dnd_checkbutton_toggled(self, widget):
838 self.on_checkbutton_toggled(widget, 'sounddnd')
840 def on_systray_combobox_changed(self, widget):
841 active = widget.get_active()
842 if active == 0:
843 gajim.config.set('trayicon', 'never')
844 gajim.interface.systray_enabled = False
845 gajim.interface.systray.hide_icon()
846 elif active == 1:
847 gajim.config.set('trayicon', 'on_event')
848 gajim.interface.systray_enabled = True
849 gajim.interface.systray.show_icon()
850 else:
851 gajim.config.set('trayicon', 'always')
852 gajim.interface.systray_enabled = True
853 gajim.interface.systray.show_icon()
855 def on_advanced_notifications_button_clicked(self, widget):
856 dialogs.AdvancedNotificationsWindow()
858 def on_play_sounds_checkbutton_toggled(self, widget):
859 self.on_checkbutton_toggled(widget, 'sounds_on',
860 [self.xml.get_object('manage_sounds_button')])
862 def on_manage_sounds_button_clicked(self, widget):
863 if self.sounds_preferences is None:
864 self.sounds_preferences = ManageSoundsWindow()
865 else:
866 self.sounds_preferences.window.present()
868 def update_text_tags(self):
870 Update color tags in opened chat windows
872 for ctrl in self._get_all_controls():
873 ctrl.update_tags()
875 def on_preference_widget_color_set(self, widget, text):
876 color = widget.get_color()
877 color_string = gtkgui_helpers.make_color_string(color)
878 gajim.config.set(text, color_string)
879 self.update_text_tags()
880 gajim.interface.save_config()
882 def on_preference_widget_font_set(self, widget, text):
883 if widget:
884 font = widget.get_font_name()
885 else:
886 font = ''
887 gajim.config.set(text, font)
888 self.update_text_font()
889 gajim.interface.save_config()
891 def update_text_font(self):
893 Update text font in opened chat windows
895 for ctrl in self._get_all_controls():
896 ctrl.update_font()
898 def on_incoming_nick_colorbutton_color_set(self, widget):
899 self.on_preference_widget_color_set(widget, 'inmsgcolor')
901 def on_outgoing_nick_colorbutton_color_set(self, widget):
902 self.on_preference_widget_color_set(widget, 'outmsgcolor')
904 def on_incoming_msg_colorbutton_color_set(self, widget):
905 self.on_preference_widget_color_set(widget, 'inmsgtxtcolor')
907 def on_outgoing_msg_colorbutton_color_set(self, widget):
908 self.on_preference_widget_color_set(widget, 'outmsgtxtcolor')
910 def on_url_msg_colorbutton_color_set(self, widget):
911 self.on_preference_widget_color_set(widget, 'urlmsgcolor')
913 def on_status_msg_colorbutton_color_set(self, widget):
914 self.on_preference_widget_color_set(widget, 'statusmsgcolor')
916 def on_conversation_fontbutton_font_set(self, widget):
917 self.on_preference_widget_font_set(widget, 'conversation_font')
919 def on_default_chat_font_toggled(self, widget):
920 font_widget = self.xml.get_object('conversation_fontbutton')
921 if widget.get_active():
922 font_widget.set_sensitive(False)
923 font_widget = None
924 else:
925 font_widget.set_sensitive(True)
926 self.on_preference_widget_font_set(font_widget, 'conversation_font')
928 def draw_color_widgets(self):
929 col_to_widget = {'inmsgcolor': 'incoming_nick_colorbutton',
930 'outmsgcolor': 'outgoing_nick_colorbutton',
931 'inmsgtxtcolor': ['incoming_msg_colorbutton',
932 'incoming_msg_checkbutton'],
933 'outmsgtxtcolor': ['outgoing_msg_colorbutton',
934 'outgoing_msg_checkbutton'],
935 'statusmsgcolor': 'status_msg_colorbutton',
936 'urlmsgcolor': 'url_msg_colorbutton'}
937 for c in col_to_widget:
938 col = gajim.config.get(c)
939 if col:
940 if isinstance(col_to_widget[c], list):
941 self.xml.get_object(col_to_widget[c][0]).set_color(
942 gtk.gdk.color_parse(col))
943 self.xml.get_object(col_to_widget[c][0]).set_sensitive(True)
944 self.xml.get_object(col_to_widget[c][1]).set_active(True)
945 else:
946 self.xml.get_object(col_to_widget[c]).set_color(
947 gtk.gdk.color_parse(col))
948 else:
949 if isinstance(col_to_widget[c], list):
950 self.xml.get_object(col_to_widget[c][0]).set_color(
951 gtk.gdk.color_parse('#000000'))
952 self.xml.get_object(col_to_widget[c][0]).set_sensitive(False)
953 self.xml.get_object(col_to_widget[c][1]).set_active(False)
954 else:
955 self.xml.get_object(col_to_widget[c]).set_color(
956 gtk.gdk.color_parse('#000000'))
958 def on_reset_colors_button_clicked(self, widget):
959 col_to_widget = {'inmsgcolor': 'incoming_nick_colorbutton',
960 'outmsgcolor': 'outgoing_nick_colorbutton',
961 'inmsgtxtcolor': 'incoming_msg_colorbutton',
962 'outmsgtxtcolor': 'outgoing_msg_colorbutton',
963 'statusmsgcolor': 'status_msg_colorbutton',
964 'urlmsgcolor': 'url_msg_colorbutton'}
965 for c in col_to_widget:
966 gajim.config.set(c, gajim.interface.default_colors[c])
967 self.draw_color_widgets()
969 self.update_text_tags()
970 gajim.interface.save_config()
972 def _set_color(self, state, widget_name, option):
974 Set color value in prefs and update the UI
976 if state:
977 color = self.xml.get_object(widget_name).get_color()
978 color_string = gtkgui_helpers.make_color_string(color)
979 else:
980 color_string = ''
981 gajim.config.set(option, color_string)
982 gajim.interface.save_config()
984 def on_incoming_msg_checkbutton_toggled(self, widget):
985 state = widget.get_active()
986 self.xml.get_object('incoming_msg_colorbutton').set_sensitive(state)
987 self._set_color(state, 'incoming_msg_colorbutton', 'inmsgtxtcolor')
989 def on_outgoing_msg_checkbutton_toggled(self, widget):
990 state = widget.get_active()
991 self.xml.get_object('outgoing_msg_colorbutton').set_sensitive(state)
992 self._set_color(state, 'outgoing_msg_colorbutton', 'outmsgtxtcolor')
994 def on_auto_away_checkbutton_toggled(self, widget):
995 self.on_checkbutton_toggled(widget, 'autoaway',
996 [self.auto_away_time_spinbutton, self.auto_away_message_entry])
998 def on_auto_away_time_spinbutton_value_changed(self, widget):
999 aat = widget.get_value_as_int()
1000 gajim.config.set('autoawaytime', aat)
1001 gajim.interface.sleeper = common.sleepy.Sleepy(
1002 gajim.config.get('autoawaytime') * 60,
1003 gajim.config.get('autoxatime') * 60)
1004 gajim.interface.save_config()
1006 def on_auto_away_message_entry_changed(self, widget):
1007 gajim.config.set('autoaway_message', widget.get_text().decode('utf-8'))
1009 def on_auto_xa_checkbutton_toggled(self, widget):
1010 self.on_checkbutton_toggled(widget, 'autoxa',
1011 [self.auto_xa_time_spinbutton, self.auto_xa_message_entry])
1013 def on_auto_xa_time_spinbutton_value_changed(self, widget):
1014 axt = widget.get_value_as_int()
1015 gajim.config.set('autoxatime', axt)
1016 gajim.interface.sleeper = common.sleepy.Sleepy(
1017 gajim.config.get('autoawaytime') * 60,
1018 gajim.config.get('autoxatime') * 60)
1019 gajim.interface.save_config()
1021 def on_auto_xa_message_entry_changed(self, widget):
1022 gajim.config.set('autoxa_message', widget.get_text().decode('utf-8'))
1024 def on_prompt_online_status_message_checkbutton_toggled(self, widget):
1025 self.on_checkbutton_toggled(widget, 'ask_online_status')
1027 def on_prompt_offline_status_message_checkbutton_toggled(self, widget):
1028 self.on_checkbutton_toggled(widget, 'ask_offline_status')
1030 def fill_default_msg_treeview(self):
1031 model = self.default_msg_tree.get_model()
1032 model.clear()
1033 status = []
1034 for status_ in gajim.config.get_per('defaultstatusmsg'):
1035 status.append(status_)
1036 status.sort()
1037 for status_ in status:
1038 msg = gajim.config.get_per('defaultstatusmsg', status_, 'message')
1039 msg = helpers.from_one_line(msg)
1040 enabled = gajim.config.get_per('defaultstatusmsg', status_, 'enabled')
1041 iter_ = model.append()
1042 uf_show = helpers.get_uf_show(status_)
1043 model.set(iter_, 0, status_, 1, uf_show, 2, msg, 3, enabled)
1045 def on_default_msg_cell_edited(self, cell, row, new_text):
1046 model = self.default_msg_tree.get_model()
1047 iter_ = model.get_iter_from_string(row)
1048 model.set_value(iter_, 2, new_text)
1050 def default_msg_toggled_cb(self, cell, path):
1051 model = self.default_msg_tree.get_model()
1052 model[path][3] = not model[path][3]
1054 def on_default_msg_treemodel_row_changed(self, model, path, iter_):
1055 status = model[iter_][0]
1056 message = model[iter_][2].decode('utf-8')
1057 message = helpers.to_one_line(message)
1058 gajim.config.set_per('defaultstatusmsg', status, 'enabled',
1059 model[iter_][3])
1060 gajim.config.set_per('defaultstatusmsg', status, 'message', message)
1062 def on_default_status_expander_activate(self, expander):
1063 eventbox = self.xml.get_object('default_status_eventbox')
1064 vbox = self.xml.get_object('status_vbox')
1065 vbox.set_child_packing(eventbox, not expander.get_expanded(), True, 0,
1066 gtk.PACK_START)
1068 def save_status_messages(self, model):
1069 for msg in gajim.config.get_per('statusmsg'):
1070 gajim.config.del_per('statusmsg', msg)
1071 iter_ = model.get_iter_first()
1072 while iter_:
1073 val = model[iter_][0].decode('utf-8')
1074 if model[iter_][1]: # we have a preset message
1075 if not val: # no title, use message text for title
1076 val = model[iter_][1]
1077 gajim.config.add_per('statusmsg', val)
1078 msg = helpers.to_one_line(model[iter_][1].decode('utf-8'))
1079 gajim.config.set_per('statusmsg', val, 'message', msg)
1080 i = 2
1081 # store mood / activity
1082 for subname in ('activity', 'subactivity', 'activity_text',
1083 'mood', 'mood_text'):
1084 gajim.config.set_per('statusmsg', val, subname,
1085 model[iter_][i].decode('utf-8'))
1086 i += 1
1087 iter_ = model.iter_next(iter_)
1088 gajim.interface.save_config()
1090 def on_msg_treemodel_row_changed(self, model, path, iter_):
1091 self.save_status_messages(model)
1093 def on_msg_treemodel_row_deleted(self, model, path):
1094 self.save_status_messages(model)
1096 def on_av_combobox_changed(self, combobox, config_name):
1097 model = combobox.get_model()
1098 active = combobox.get_active()
1099 device = model[active][1].decode('utf-8')
1100 gajim.config.set(config_name, device)
1102 def on_audio_input_combobox_changed(self, widget):
1103 self.on_av_combobox_changed(widget, 'audio_input_device')
1105 def on_audio_output_combobox_changed(self, widget):
1106 self.on_av_combobox_changed(widget, 'audio_output_device')
1108 def on_video_input_combobox_changed(self, widget):
1109 self.on_av_combobox_changed(widget, 'video_input_device')
1111 def on_video_output_combobox_changed(self, widget):
1112 self.on_av_combobox_changed(widget, 'video_output_device')
1114 def on_video_framerate_combobox_changed(self, widget):
1115 self.on_av_combobox_changed(widget, 'video_framerate')
1117 def on_video_size_combobox_changed(self, widget):
1118 self.on_av_combobox_changed(widget, 'video_size')
1120 def on_stun_checkbutton_toggled(self, widget):
1121 self.on_checkbutton_toggled(widget, 'use_stun_server',
1122 [self.xml.get_object('stun_server_entry')])
1124 def stun_server_entry_changed(self, widget):
1125 gajim.config.set('stun_server', widget.get_text().decode('utf-8'))
1127 def on_applications_combobox_changed(self, widget):
1128 if widget.get_active() == 0:
1129 gajim.config.set('autodetect_browser_mailer', True)
1130 self.xml.get_object('custom_apps_frame').hide()
1131 elif widget.get_active() == 1:
1132 gajim.config.set('autodetect_browser_mailer', False)
1133 self.xml.get_object('custom_apps_frame').show()
1134 gajim.config.set('openwith', 'custom')
1135 gajim.interface.save_config()
1137 def on_custom_browser_entry_changed(self, widget):
1138 gajim.config.set('custombrowser', widget.get_text().decode('utf-8'))
1139 gajim.interface.save_config()
1141 def on_custom_mail_client_entry_changed(self, widget):
1142 gajim.config.set('custommailapp', widget.get_text().decode('utf-8'))
1143 gajim.interface.save_config()
1145 def on_custom_file_manager_entry_changed(self, widget):
1146 gajim.config.set('custom_file_manager', widget.get_text().decode('utf-8'))
1147 gajim.interface.save_config()
1149 def on_log_show_changes_checkbutton_toggled(self, widget):
1150 self.on_checkbutton_toggled(widget, 'log_contact_status_changes')
1152 def on_log_encrypted_chats_checkbutton_toggled(self, widget):
1153 widget.set_inconsistent(False)
1154 self.on_per_account_checkbutton_toggled(widget, 'log_encrypted_sessions')
1156 def on_send_os_info_checkbutton_toggled(self, widget):
1157 widget.set_inconsistent(False)
1158 self.on_per_account_checkbutton_toggled(widget, 'send_os_info')
1160 def on_send_idle_time_checkbutton_toggled(self, widget):
1161 widget.set_inconsistent(False)
1162 self.on_per_account_checkbutton_toggled(widget, 'send_idle_time')
1164 def on_check_default_client_checkbutton_toggled(self, widget):
1165 self.on_checkbutton_toggled(widget, 'check_if_gajim_is_default')
1167 def on_notify_gmail_checkbutton_toggled(self, widget):
1168 self.on_checkbutton_toggled(widget, 'notify_on_new_gmail_email')
1170 def on_notify_gmail_extra_checkbutton_toggled(self, widget):
1171 self.on_checkbutton_toggled(widget, 'notify_on_new_gmail_email_extra')
1173 def fill_msg_treeview(self):
1174 self.xml.get_object('delete_msg_button').set_sensitive(False)
1175 model = self.msg_tree.get_model()
1176 model.clear()
1177 preset_status = []
1178 for msg_name in gajim.config.get_per('statusmsg'):
1179 if msg_name.startswith('_last_'):
1180 continue
1181 preset_status.append(msg_name)
1182 preset_status.sort()
1183 for msg_name in preset_status:
1184 msg_text = gajim.config.get_per('statusmsg', msg_name, 'message')
1185 msg_text = helpers.from_one_line(msg_text)
1186 activity = gajim.config.get_per('statusmsg', msg_name, 'activity')
1187 subactivity = gajim.config.get_per('statusmsg', msg_name,
1188 'subactivity')
1189 activity_text = gajim.config.get_per('statusmsg', msg_name,
1190 'activity_text')
1191 mood = gajim.config.get_per('statusmsg', msg_name, 'mood')
1192 mood_text = gajim.config.get_per('statusmsg', msg_name, 'mood_text')
1193 iter_ = model.append()
1194 model.set(iter_, 0, msg_name, 1, msg_text, 2, activity, 3,
1195 subactivity, 4, activity_text, 5, mood, 6, mood_text)
1197 def on_msg_cell_edited(self, cell, row, new_text):
1198 model = self.msg_tree.get_model()
1199 iter_ = model.get_iter_from_string(row)
1200 model.set_value(iter_, 0, new_text)
1202 def on_msg_treeview_cursor_changed(self, widget, data = None):
1203 (model, iter_) = self.msg_tree.get_selection().get_selected()
1204 if not iter_:
1205 return
1206 self.xml.get_object('delete_msg_button').set_sensitive(True)
1207 buf = self.xml.get_object('msg_textview').get_buffer()
1208 msg = model[iter_][1]
1209 buf.set_text(msg)
1211 def on_new_msg_button_clicked(self, widget, data = None):
1212 model = self.msg_tree.get_model()
1213 iter_ = model.append()
1214 model.set(iter_, 0, _('status message title'), 1, _('status message text'))
1215 self.msg_tree.set_cursor(model.get_path(iter_))
1217 def on_delete_msg_button_clicked(self, widget, data = None):
1218 (model, iter_) = self.msg_tree.get_selection().get_selected()
1219 if not iter_:
1220 return
1221 buf = self.xml.get_object('msg_textview').get_buffer()
1222 model.remove(iter_)
1223 buf.set_text('')
1224 self.xml.get_object('delete_msg_button').set_sensitive(False)
1226 def on_msg_textview_changed(self, widget, data = None):
1227 (model, iter_) = self.msg_tree.get_selection().get_selected()
1228 if not iter_:
1229 return
1230 buf = self.xml.get_object('msg_textview').get_buffer()
1231 first_iter, end_iter = buf.get_bounds()
1232 model.set_value(iter_, 1, buf.get_text(first_iter, end_iter))
1234 def on_msg_treeview_key_press_event(self, widget, event):
1235 if event.keyval == gtk.keysyms.Delete:
1236 self.on_delete_msg_button_clicked(widget)
1238 def on_open_advanced_editor_button_clicked(self, widget, data = None):
1239 if 'advanced_config' in gajim.interface.instances:
1240 gajim.interface.instances['advanced_config'].window.present()
1241 else:
1242 gajim.interface.instances['advanced_config'] = \
1243 dialogs.AdvancedConfigurationWindow()
1245 #---------- ManageProxiesWindow class -------------#
1246 class ManageProxiesWindow:
1247 def __init__(self):
1248 self.xml = gtkgui_helpers.get_gtk_builder('manage_proxies_window.ui')
1249 self.window = self.xml.get_object('manage_proxies_window')
1250 self.window.set_transient_for(gajim.interface.roster.window)
1251 self.proxies_treeview = self.xml.get_object('proxies_treeview')
1252 self.proxyname_entry = self.xml.get_object('proxyname_entry')
1253 self.proxytype_combobox = self.xml.get_object('proxytype_combobox')
1255 self.init_list()
1256 self.block_signal = False
1257 self.xml.connect_signals(self)
1258 self.window.show_all()
1259 # hide the BOSH fields by default
1260 self.show_bosh_fields()
1262 def show_bosh_fields(self, show=True):
1263 if show:
1264 self.xml.get_object('boshuri_entry').show()
1265 self.xml.get_object('boshuri_label').show()
1266 self.xml.get_object('boshuseproxy_checkbutton').show()
1267 else:
1268 cb = self.xml.get_object('boshuseproxy_checkbutton')
1269 cb.hide()
1270 cb.set_active(True)
1271 self.on_boshuseproxy_checkbutton_toggled(cb)
1272 self.xml.get_object('boshuri_entry').hide()
1273 self.xml.get_object('boshuri_label').hide()
1276 def fill_proxies_treeview(self):
1277 model = self.proxies_treeview.get_model()
1278 model.clear()
1279 iter_ = model.append()
1280 model.set(iter_, 0, _('None'))
1281 for p in gajim.config.get_per('proxies'):
1282 iter_ = model.append()
1283 model.set(iter_, 0, p)
1285 def init_list(self):
1286 self.xml.get_object('remove_proxy_button').set_sensitive(False)
1287 self.proxytype_combobox.set_sensitive(False)
1288 self.xml.get_object('proxy_table').set_sensitive(False)
1289 model = gtk.ListStore(str)
1290 self.proxies_treeview.set_model(model)
1291 col = gtk.TreeViewColumn('Proxies')
1292 self.proxies_treeview.append_column(col)
1293 renderer = gtk.CellRendererText()
1294 col.pack_start(renderer, True)
1295 col.set_attributes(renderer, text = 0)
1296 self.fill_proxies_treeview()
1297 self.xml.get_object('proxytype_combobox').set_active(0)
1299 def on_manage_proxies_window_destroy(self, widget):
1300 if 'accounts' in gajim.interface.instances:
1301 gajim.interface.instances['accounts'].\
1302 update_proxy_list()
1303 del gajim.interface.instances['manage_proxies']
1305 def on_add_proxy_button_clicked(self, widget):
1306 model = self.proxies_treeview.get_model()
1307 proxies = gajim.config.get_per('proxies')
1308 i = 1
1309 while ('proxy' + unicode(i)) in proxies:
1310 i += 1
1311 iter_ = model.append()
1312 model.set(iter_, 0, 'proxy' + unicode(i))
1313 gajim.config.add_per('proxies', 'proxy' + unicode(i))
1314 self.proxies_treeview.set_cursor(model.get_path(iter_))
1316 def on_remove_proxy_button_clicked(self, widget):
1317 (model, iter_) = self.proxies_treeview.get_selection().get_selected()
1318 if not iter_:
1319 return
1320 proxy = model[iter_][0].decode('utf-8')
1321 model.remove(iter_)
1322 gajim.config.del_per('proxies', proxy)
1323 self.xml.get_object('remove_proxy_button').set_sensitive(False)
1324 self.block_signal = True
1325 self.on_proxies_treeview_cursor_changed(self.proxies_treeview)
1326 self.block_signal = False
1328 def on_close_button_clicked(self, widget):
1329 self.window.destroy()
1331 def on_useauth_checkbutton_toggled(self, widget):
1332 if self.block_signal:
1333 return
1334 act = widget.get_active()
1335 proxy = self.proxyname_entry.get_text().decode('utf-8')
1336 gajim.config.set_per('proxies', proxy, 'useauth', act)
1337 self.xml.get_object('proxyuser_entry').set_sensitive(act)
1338 self.xml.get_object('proxypass_entry').set_sensitive(act)
1340 def on_boshuseproxy_checkbutton_toggled(self, widget):
1341 if self.block_signal:
1342 return
1343 act = widget.get_active()
1344 proxy = self.proxyname_entry.get_text().decode('utf-8')
1345 gajim.config.set_per('proxies', proxy, 'bosh_useproxy', act)
1346 self.xml.get_object('proxyhost_entry').set_sensitive(act)
1347 self.xml.get_object('proxyport_entry').set_sensitive(act)
1349 def on_proxies_treeview_cursor_changed(self, widget):
1350 #FIXME: check if off proxy settings are correct (see
1351 # http://trac.gajim.org/changeset/1921#file2 line 1221
1352 proxyhost_entry = self.xml.get_object('proxyhost_entry')
1353 proxyport_entry = self.xml.get_object('proxyport_entry')
1354 proxyuser_entry = self.xml.get_object('proxyuser_entry')
1355 proxypass_entry = self.xml.get_object('proxypass_entry')
1356 boshuri_entry = self.xml.get_object('boshuri_entry')
1357 useauth_checkbutton = self.xml.get_object('useauth_checkbutton')
1358 boshuseproxy_checkbutton = self.xml.get_object('boshuseproxy_checkbutton')
1359 self.block_signal = True
1360 proxyhost_entry.set_text('')
1361 proxyport_entry.set_text('')
1362 proxyuser_entry.set_text('')
1363 proxypass_entry.set_text('')
1364 boshuri_entry.set_text('')
1366 #boshuseproxy_checkbutton.set_active(False)
1367 #self.on_boshuseproxy_checkbutton_toggled(boshuseproxy_checkbutton)
1369 #useauth_checkbutton.set_active(False)
1370 #self.on_useauth_checkbutton_toggled(useauth_checkbutton)
1372 (model, iter_) = widget.get_selection().get_selected()
1373 if not iter_:
1374 self.xml.get_object('proxyname_entry').set_text('')
1375 self.xml.get_object('proxytype_combobox').set_sensitive(False)
1376 self.xml.get_object('proxy_table').set_sensitive(False)
1377 self.block_signal = False
1378 return
1380 proxy = model[iter_][0]
1381 self.xml.get_object('proxyname_entry').set_text(proxy)
1383 if proxy == _('None'): # special proxy None
1384 self.show_bosh_fields(False)
1385 self.proxyname_entry.set_editable(False)
1386 self.xml.get_object('remove_proxy_button').set_sensitive(False)
1387 self.xml.get_object('proxytype_combobox').set_sensitive(False)
1388 self.xml.get_object('proxy_table').set_sensitive(False)
1389 else:
1390 proxytype = gajim.config.get_per('proxies', proxy, 'type')
1392 self.show_bosh_fields(proxytype=='bosh')
1394 self.proxyname_entry.set_editable(True)
1395 self.xml.get_object('remove_proxy_button').set_sensitive(True)
1396 self.xml.get_object('proxytype_combobox').set_sensitive(True)
1397 self.xml.get_object('proxy_table').set_sensitive(True)
1398 proxyhost_entry.set_text(gajim.config.get_per('proxies', proxy,
1399 'host'))
1400 proxyport_entry.set_text(unicode(gajim.config.get_per('proxies',
1401 proxy, 'port')))
1402 proxyuser_entry.set_text(gajim.config.get_per('proxies', proxy,
1403 'user'))
1404 proxypass_entry.set_text(gajim.config.get_per('proxies', proxy,
1405 'pass'))
1406 boshuri_entry.set_text(gajim.config.get_per('proxies', proxy,
1407 'bosh_uri'))
1408 types = ['http', 'socks5', 'bosh']
1409 self.proxytype_combobox.set_active(types.index(proxytype))
1410 boshuseproxy_checkbutton.set_active(
1411 gajim.config.get_per('proxies', proxy, 'bosh_useproxy'))
1412 useauth_checkbutton.set_active(
1413 gajim.config.get_per('proxies', proxy, 'useauth'))
1414 self.block_signal = False
1416 def on_proxies_treeview_key_press_event(self, widget, event):
1417 if event.keyval == gtk.keysyms.Delete:
1418 self.on_remove_proxy_button_clicked(widget)
1420 def on_proxyname_entry_changed(self, widget):
1421 if self.block_signal:
1422 return
1423 (model, iter_) = self.proxies_treeview.get_selection().get_selected()
1424 if not iter_:
1425 return
1426 old_name = model.get_value(iter_, 0).decode('utf-8')
1427 new_name = widget.get_text().decode('utf-8')
1428 if new_name == '':
1429 return
1430 if new_name == old_name:
1431 return
1432 config = gajim.config.get_per('proxies', old_name)
1433 gajim.config.del_per('proxies', old_name)
1434 gajim.config.add_per('proxies', new_name)
1435 for option in config:
1436 gajim.config.set_per('proxies', new_name, option,
1437 config[option][common.config.OPT_VAL])
1438 model.set_value(iter_, 0, new_name)
1440 def on_proxytype_combobox_changed(self, widget):
1441 if self.block_signal:
1442 return
1443 types = ['http', 'socks5', 'bosh']
1444 type_ = self.proxytype_combobox.get_active()
1445 self.show_bosh_fields(types[type_]=='bosh')
1446 proxy = self.proxyname_entry.get_text().decode('utf-8')
1447 gajim.config.set_per('proxies', proxy, 'type', types[type_])
1449 def on_proxyhost_entry_changed(self, widget):
1450 if self.block_signal:
1451 return
1452 value = widget.get_text().decode('utf-8')
1453 proxy = self.proxyname_entry.get_text().decode('utf-8')
1454 gajim.config.set_per('proxies', proxy, 'host', value)
1456 def on_proxyport_entry_changed(self, widget):
1457 if self.block_signal:
1458 return
1459 value = widget.get_text().decode('utf-8')
1460 proxy = self.proxyname_entry.get_text().decode('utf-8')
1461 gajim.config.set_per('proxies', proxy, 'port', value)
1463 def on_proxyuser_entry_changed(self, widget):
1464 if self.block_signal:
1465 return
1466 value = widget.get_text().decode('utf-8')
1467 proxy = self.proxyname_entry.get_text().decode('utf-8')
1468 gajim.config.set_per('proxies', proxy, 'user', value)
1470 def on_boshuri_entry_changed(self, widget):
1471 if self.block_signal:
1472 return
1473 value = widget.get_text().decode('utf-8')
1474 proxy = self.proxyname_entry.get_text().decode('utf-8')
1475 gajim.config.set_per('proxies', proxy, 'bosh_uri', value)
1477 def on_proxypass_entry_changed(self, widget):
1478 if self.block_signal:
1479 return
1480 value = widget.get_text().decode('utf-8')
1481 proxy = self.proxyname_entry.get_text().decode('utf-8')
1482 gajim.config.set_per('proxies', proxy, 'pass', value)
1485 #---------- AccountsWindow class -------------#
1486 class AccountsWindow:
1488 Class for accounts window: list of accounts
1491 def on_accounts_window_destroy(self, widget):
1492 del gajim.interface.instances['accounts']
1494 def on_close_button_clicked(self, widget):
1495 self.check_resend_relog()
1496 self.window.destroy()
1498 def __init__(self):
1499 self.xml = gtkgui_helpers.get_gtk_builder('accounts_window.ui')
1500 self.window = self.xml.get_object('accounts_window')
1501 self.window.set_transient_for(gajim.interface.roster.window)
1502 self.accounts_treeview = self.xml.get_object('accounts_treeview')
1503 self.remove_button = self.xml.get_object('remove_button')
1504 self.rename_button = self.xml.get_object('rename_button')
1505 path_to_kbd_input_img = gtkgui_helpers.get_icon_path('gajim-kbd_input')
1506 img = self.xml.get_object('rename_image')
1507 img.set_from_file(path_to_kbd_input_img)
1508 self.notebook = self.xml.get_object('notebook')
1509 # Name
1510 model = gtk.ListStore(str)
1511 self.accounts_treeview.set_model(model)
1512 # column
1513 renderer = gtk.CellRendererText()
1514 self.accounts_treeview.insert_column_with_attributes(-1, _('Name'),
1515 renderer, text=0)
1517 self.current_account = None
1518 # When we fill info, we don't want to handle the changed signals
1519 self.ignore_events = False
1520 self.need_relogin = False
1521 self.resend_presence = False
1523 self.update_proxy_list()
1524 self.xml.connect_signals(self)
1525 self.init_accounts()
1526 self.window.show_all()
1528 # Merge accounts
1529 st = gajim.config.get('mergeaccounts')
1530 checkbutton = self.xml.get_object('merge_checkbutton')
1531 checkbutton.set_active(st)
1532 # prevent roster redraws by connecting the signal after button state is
1533 # set
1534 checkbutton.connect('toggled', self.on_merge_checkbutton_toggled)
1536 self.avahi_available = True
1537 try:
1538 import avahi
1539 except ImportError:
1540 self.avahi_available = False
1542 def on_accounts_window_key_press_event(self, widget, event):
1543 if event.keyval == gtk.keysyms.Escape:
1544 self.check_resend_relog()
1545 self.window.destroy()
1547 def select_account(self, account):
1548 model = self.accounts_treeview.get_model()
1549 iter_ = model.get_iter_root()
1550 while iter_:
1551 acct = model[iter_][0].decode('utf-8')
1552 if account == acct:
1553 self.accounts_treeview.set_cursor(model.get_path(iter_))
1554 return
1555 iter_ = model.iter_next(iter_)
1557 def init_accounts(self):
1559 Initialize listStore with existing accounts
1561 self.remove_button.set_sensitive(False)
1562 self.rename_button.set_sensitive(False)
1563 self.current_account = None
1564 model = self.accounts_treeview.get_model()
1565 model.clear()
1566 for account in gajim.config.get_per('accounts'):
1567 iter_ = model.append()
1568 model.set(iter_, 0, account)
1570 def resend(self, account):
1571 if not account in gajim.connections:
1572 return
1573 show = gajim.SHOW_LIST[gajim.connections[account].connected]
1574 status = gajim.connections[account].status
1575 gajim.connections[account].change_status(show, status)
1577 def check_resend_relog(self):
1578 if self.need_relogin and self.current_account == gajim.ZEROCONF_ACC_NAME:
1579 if gajim.ZEROCONF_ACC_NAME in gajim.connections:
1580 gajim.connections[gajim.ZEROCONF_ACC_NAME].update_details()
1581 return
1583 elif self.need_relogin and self.current_account and \
1584 gajim.connections[self.current_account].connected > 0:
1585 def login(account, show_before, status_before):
1587 Login with previous status
1589 # first make sure connection is really closed,
1590 # 0.5 may not be enough
1591 gajim.connections[account].disconnect(True)
1592 gajim.interface.roster.send_status(account, show_before,
1593 status_before)
1595 def relog(account):
1596 self.dialog.destroy()
1597 show_before = gajim.SHOW_LIST[gajim.connections[account].connected]
1598 status_before = gajim.connections[account].status
1599 gajim.interface.roster.send_status(account, 'offline',
1600 _('Be right back.'))
1601 gobject.timeout_add(500, login, account, show_before, status_before)
1603 def on_yes(checked, account):
1604 relog(account)
1605 def on_no(account):
1606 if self.resend_presence:
1607 self.resend(account)
1608 if self.current_account in gajim.connections:
1609 self.dialog = dialogs.YesNoDialog(_('Relogin now?'),
1610 _('If you want all the changes to apply instantly, '
1611 'you must relogin.'), on_response_yes=(on_yes,
1612 self.current_account), on_response_no=(on_no,
1613 self.current_account))
1614 elif self.resend_presence:
1615 self.resend(self.current_account)
1617 self.need_relogin = False
1618 self.resend_presence = False
1620 def on_accounts_treeview_cursor_changed(self, widget):
1622 Activate modify buttons when a row is selected, update accounts info
1624 sel = self.accounts_treeview.get_selection()
1625 (model, iter_) = sel.get_selected()
1626 if iter_:
1627 account = model[iter_][0].decode('utf-8')
1628 else:
1629 account = None
1630 if self.current_account and self.current_account == account:
1631 # We're comming back to our current account, no need to update widgets
1632 return
1633 # Save config for previous account if needed cause focus_out event is
1634 # called after the changed event
1635 if self.current_account and self.window.get_focus():
1636 focused_widget = self.window.get_focus()
1637 focused_widget_name = focused_widget.get_name()
1638 if focused_widget_name in ('jid_entry1', 'resource_entry1',
1639 'custom_port_entry', 'cert_entry1'):
1640 if focused_widget_name == 'jid_entry1':
1641 func = self.on_jid_entry1_focus_out_event
1642 elif focused_widget_name == 'resource_entry1':
1643 func = self.on_resource_entry1_focus_out_event
1644 elif focused_widget_name == 'custom_port_entry':
1645 func = self.on_custom_port_entry_focus_out_event
1646 elif focused_widget_name == 'cert_entry1':
1647 func = self.on_cert_entry1_focus_out_event
1648 if func(focused_widget, None):
1649 # Error detected in entry, don't change account, re-put cursor on
1650 # previous row
1651 self.select_account(self.current_account)
1652 return True
1653 self.window.set_focus(widget)
1655 self.check_resend_relog()
1657 if account:
1658 self.remove_button.set_sensitive(True)
1659 self.rename_button.set_sensitive(True)
1660 else:
1661 self.remove_button.set_sensitive(False)
1662 self.rename_button.set_sensitive(False)
1663 if iter_:
1664 self.current_account = account
1665 if account == gajim.ZEROCONF_ACC_NAME:
1666 self.remove_button.set_sensitive(False)
1667 self.init_account()
1668 self.update_proxy_list()
1670 def on_browse_for_client_cert_button_clicked(self, widget, data=None):
1671 def on_ok(widget, path_to_clientcert_file):
1672 self.dialog.destroy()
1673 if not path_to_clientcert_file:
1674 return
1675 self.xml.get_object('cert_entry1').set_text(path_to_clientcert_file)
1676 gajim.config.set_per('accounts', self.current_account,
1677 'client_cert', path_to_clientcert_file)
1679 def on_cancel(widget):
1680 self.dialog.destroy()
1682 path_to_clientcert_file = self.xml.get_object('cert_entry1').get_text()
1683 self.dialog = dialogs.ClientCertChooserDialog(path_to_clientcert_file,
1684 on_ok, on_cancel)
1686 def update_proxy_list(self):
1687 if self.current_account:
1688 our_proxy = gajim.config.get_per('accounts', self.current_account,
1689 'proxy')
1690 else:
1691 our_proxy = ''
1693 if not our_proxy:
1694 our_proxy = _('None')
1695 proxy_combobox = self.xml.get_object('proxies_combobox1')
1696 model = gtk.ListStore(str)
1697 proxy_combobox.set_model(model)
1698 l = gajim.config.get_per('proxies')
1699 l.insert(0, _('None'))
1700 for i in xrange(len(l)):
1701 model.append([l[i]])
1702 if our_proxy == l[i]:
1703 proxy_combobox.set_active(i)
1705 def init_account(self):
1706 if not self.current_account:
1707 self.notebook.set_current_page(0)
1708 return
1709 if gajim.config.get_per('accounts', self.current_account, 'is_zeroconf'):
1710 self.ignore_events = True
1711 self.init_zeroconf_account()
1712 self.ignore_events = False
1713 self.notebook.set_current_page(2)
1714 return
1715 self.ignore_events = True
1716 self.init_normal_account()
1717 self.ignore_events = False
1718 self.notebook.set_current_page(1)
1720 def init_zeroconf_account(self):
1721 active = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1722 'active')
1723 self.xml.get_object('enable_zeroconf_checkbutton2').set_active(active)
1724 if not gajim.HAVE_ZEROCONF:
1725 self.xml.get_object('enable_zeroconf_checkbutton2').set_sensitive(
1726 False)
1727 self.xml.get_object('zeroconf_notebook').set_sensitive(active)
1728 # General tab
1729 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1730 'autoconnect')
1731 self.xml.get_object('autoconnect_checkbutton2').set_active(st)
1733 list_no_log_for = gajim.config.get_per('accounts',
1734 gajim.ZEROCONF_ACC_NAME, 'no_log_for').split()
1735 if gajim.ZEROCONF_ACC_NAME in list_no_log_for:
1736 self.xml.get_object('log_history_checkbutton2').set_active(0)
1737 else:
1738 self.xml.get_object('log_history_checkbutton2').set_active(1)
1740 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1741 'sync_with_global_status')
1742 self.xml.get_object('sync_with_global_status_checkbutton2').set_active(st)
1744 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1745 'use_custom_host')
1746 self.xml.get_object('custom_port_checkbutton2').set_active(st)
1747 self.xml.get_object('custom_port_entry2').set_sensitive(st)
1749 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1750 'custom_port')
1751 if not st:
1752 gajim.config.set_per('accounts', gajim.ZEROCONF_ACC_NAME,
1753 'custom_port', '5298')
1754 st = '5298'
1755 self.xml.get_object('custom_port_entry2').set_text(str(st))
1757 # Personal tab
1758 gpg_key_label = self.xml.get_object('gpg_key_label2')
1759 if gajim.ZEROCONF_ACC_NAME in gajim.connections and \
1760 gajim.connections[gajim.ZEROCONF_ACC_NAME].gpg:
1761 self.xml.get_object('gpg_choose_button2').set_sensitive(True)
1762 self.init_account_gpg()
1763 else:
1764 gpg_key_label.set_text(_('OpenPGP is not usable on this computer'))
1765 self.xml.get_object('gpg_choose_button2').set_sensitive(False)
1767 for opt in ('first_name', 'last_name', 'jabber_id', 'email'):
1768 st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
1769 'zeroconf_' + opt)
1770 self.xml.get_object(opt + '_entry2').set_text(st)
1772 def init_account_gpg(self):
1773 account = self.current_account
1774 keyid = gajim.config.get_per('accounts', account, 'keyid')
1775 keyname = gajim.config.get_per('accounts', account, 'keyname')
1776 use_gpg_agent = gajim.config.get('use_gpg_agent')
1778 if account == gajim.ZEROCONF_ACC_NAME:
1779 widget_name_add = '2'
1780 else:
1781 widget_name_add = '1'
1783 gpg_key_label = self.xml.get_object('gpg_key_label' + widget_name_add)
1784 gpg_name_label = self.xml.get_object('gpg_name_label' + widget_name_add)
1785 use_gpg_agent_checkbutton = self.xml.get_object(
1786 'use_gpg_agent_checkbutton' + widget_name_add)
1788 if not keyid:
1789 use_gpg_agent_checkbutton.set_sensitive(False)
1790 gpg_key_label.set_text(_('No key selected'))
1791 gpg_name_label.set_text('')
1792 return
1794 gpg_key_label.set_text(keyid)
1795 gpg_name_label.set_text(keyname)
1796 use_gpg_agent_checkbutton.set_sensitive(True)
1797 use_gpg_agent_checkbutton.set_active(use_gpg_agent)
1799 def draw_normal_jid(self):
1800 account = self.current_account
1801 self.ignore_events = True
1802 active = gajim.config.get_per('accounts', account, 'active')
1803 self.xml.get_object('enable_checkbutton1').set_active(active)
1804 self.xml.get_object('normal_notebook1').set_sensitive(active)
1805 if gajim.config.get_per('accounts', account, 'anonymous_auth'):
1806 self.xml.get_object('anonymous_checkbutton1').set_active(True)
1807 self.xml.get_object('jid_label1').set_text(_('Server:'))
1808 save_password = self.xml.get_object('save_password_checkbutton1')
1809 save_password.set_active(False)
1810 save_password.set_sensitive(False)
1811 password_entry = self.xml.get_object('password_entry1')
1812 password_entry.set_text('')
1813 password_entry.set_sensitive(False)
1814 jid = gajim.config.get_per('accounts', account, 'hostname')
1815 else:
1816 self.xml.get_object('anonymous_checkbutton1').set_active(False)
1817 self.xml.get_object('jid_label1').set_text(_('Jabber ID:'))
1818 savepass = gajim.config.get_per('accounts', account, 'savepass')
1819 save_password = self.xml.get_object('save_password_checkbutton1')
1820 save_password.set_sensitive(True)
1821 save_password.set_active(savepass)
1822 password_entry = self.xml.get_object('password_entry1')
1823 if savepass:
1824 passstr = passwords.get_password(account) or ''
1825 password_entry.set_sensitive(True)
1826 else:
1827 passstr = ''
1828 password_entry.set_sensitive(False)
1829 password_entry.set_text(passstr)
1831 jid = gajim.config.get_per('accounts', account, 'name') \
1832 + '@' + gajim.config.get_per('accounts', account, 'hostname')
1833 self.xml.get_object('jid_entry1').set_text(jid)
1834 self.ignore_events = False
1836 def init_normal_account(self):
1837 account = self.current_account
1838 # Account tab
1839 self.draw_normal_jid()
1840 self.xml.get_object('resource_entry1').set_text(gajim.config.get_per(
1841 'accounts', account, 'resource'))
1843 client_cert = gajim.config.get_per('accounts', account, 'client_cert')
1844 self.xml.get_object('cert_entry1').set_text(client_cert)
1846 self.xml.get_object('adjust_priority_with_status_checkbutton1').\
1847 set_active(gajim.config.get_per('accounts', account,
1848 'adjust_priority_with_status'))
1849 spinbutton = self.xml.get_object('priority_spinbutton1')
1850 if gajim.config.get('enable_negative_priority'):
1851 spinbutton.set_range(-128, 127)
1852 else:
1853 spinbutton.set_range(0, 127)
1854 spinbutton.set_value(gajim.config.get_per('accounts', account,
1855 'priority'))
1857 # Connection tab
1858 use_env_http_proxy = gajim.config.get_per('accounts', account,
1859 'use_env_http_proxy')
1860 self.xml.get_object('use_env_http_proxy_checkbutton1').set_active(
1861 use_env_http_proxy)
1862 self.xml.get_object('proxy_hbox1').set_sensitive(not use_env_http_proxy)
1864 warn_when_insecure_ssl = gajim.config.get_per('accounts', account,
1865 'warn_when_insecure_ssl_connection')
1866 self.xml.get_object('warn_when_insecure_connection_checkbutton1').\
1867 set_active(warn_when_insecure_ssl)
1869 self.xml.get_object('send_keepalive_checkbutton1').set_active(
1870 gajim.config.get_per('accounts', account, 'keep_alives_enabled'))
1872 use_custom_host = gajim.config.get_per('accounts', account,
1873 'use_custom_host')
1874 self.xml.get_object('custom_host_port_checkbutton1').set_active(
1875 use_custom_host)
1876 custom_host = gajim.config.get_per('accounts', account, 'custom_host')
1877 if not custom_host:
1878 custom_host = gajim.config.get_per('accounts', account, 'hostname')
1879 gajim.config.set_per('accounts', account, 'custom_host', custom_host)
1880 self.xml.get_object('custom_host_entry1').set_text(custom_host)
1881 custom_port = gajim.config.get_per('accounts', account, 'custom_port')
1882 if not custom_port:
1883 custom_port = 5222
1884 gajim.config.set_per('accounts', account, 'custom_port', custom_port)
1885 self.xml.get_object('custom_port_entry1').set_text(unicode(custom_port))
1887 # Personal tab
1888 gpg_key_label = self.xml.get_object('gpg_key_label1')
1889 if gajim.HAVE_GPG:
1890 self.xml.get_object('gpg_choose_button1').set_sensitive(True)
1891 self.init_account_gpg()
1892 else:
1893 gpg_key_label.set_text(_('OpenPGP is not usable on this computer'))
1894 self.xml.get_object('gpg_choose_button1').set_sensitive(False)
1896 # General tab
1897 self.xml.get_object('autoconnect_checkbutton1').set_active(gajim.config.\
1898 get_per('accounts', account, 'autoconnect'))
1899 self.xml.get_object('autoreconnect_checkbutton1').set_active(gajim.
1900 config.get_per('accounts', account, 'autoreconnect'))
1902 list_no_log_for = gajim.config.get_per('accounts', account,
1903 'no_log_for').split()
1904 if account in list_no_log_for:
1905 self.xml.get_object('log_history_checkbutton1').set_active(False)
1906 else:
1907 self.xml.get_object('log_history_checkbutton1').set_active(True)
1909 self.xml.get_object('sync_with_global_status_checkbutton1').set_active(
1910 gajim.config.get_per('accounts', account, 'sync_with_global_status'))
1911 self.xml.get_object('use_ft_proxies_checkbutton1').set_active(
1912 gajim.config.get_per('accounts', account, 'use_ft_proxies'))
1914 def on_add_button_clicked(self, widget):
1916 When add button is clicked: open an account information window
1918 if 'account_creation_wizard' in gajim.interface.instances:
1919 gajim.interface.instances['account_creation_wizard'].window.present()
1920 else:
1921 gajim.interface.instances['account_creation_wizard'] = \
1922 AccountCreationWizardWindow()
1924 def on_remove_button_clicked(self, widget):
1926 When delete button is clicked: Remove an account from the listStore and
1927 from the config file
1929 if not self.current_account:
1930 return
1931 account = self.current_account
1932 if len(gajim.events.get_events(account)):
1933 dialogs.ErrorDialog(_('Unread events'),
1934 _('Read all pending events before removing this account.'))
1935 return
1937 if gajim.config.get_per('accounts', account, 'is_zeroconf'):
1938 # Should never happen as button is insensitive
1939 return
1941 win_opened = False
1942 if gajim.interface.msg_win_mgr.get_controls(acct=account):
1943 win_opened = True
1944 elif account in gajim.interface.instances:
1945 for key in gajim.interface.instances[account]:
1946 if gajim.interface.instances[account][key] and key != \
1947 'remove_account':
1948 win_opened = True
1949 break
1950 # Detect if we have opened windows for this account
1951 def remove(account):
1952 if account in gajim.interface.instances and \
1953 'remove_account' in gajim.interface.instances[account]:
1954 gajim.interface.instances[account]['remove_account'].window.\
1955 present()
1956 else:
1957 if not account in gajim.interface.instances:
1958 gajim.interface.instances[account] = {}
1959 gajim.interface.instances[account]['remove_account'] = \
1960 RemoveAccountWindow(account)
1961 if win_opened:
1962 dialogs.ConfirmationDialog(
1963 _('You have opened chat in account %s') % account,
1964 _('All chat and groupchat windows will be closed. Do you want to '
1965 'continue?'),
1966 on_response_ok = (remove, account))
1967 else:
1968 remove(account)
1970 def on_rename_button_clicked(self, widget):
1971 if not self.current_account:
1972 return
1973 active = gajim.config.get_per('accounts', self.current_account, 'active')
1974 if active and gajim.connections[self.current_account].connected != 0:
1975 dialogs.ErrorDialog(
1976 _('You are currently connected to the server'),
1977 _('To change the account name, you must be disconnected.'))
1978 return
1979 if len(gajim.events.get_events(self.current_account)):
1980 dialogs.ErrorDialog(_('Unread events'),
1981 _('To change the account name, you must read all pending '
1982 'events.'))
1983 return
1984 # Get the new name
1985 def on_renamed(new_name, old_name):
1986 if new_name in gajim.connections:
1987 dialogs.ErrorDialog(_('Account Name Already Used'),
1988 _('This name is already used by another of your accounts. '
1989 'Please choose another name.'))
1990 return
1991 if (new_name == ''):
1992 dialogs.ErrorDialog(_('Invalid account name'),
1993 _('Account name cannot be empty.'))
1994 return
1995 if new_name.find(' ') != -1:
1996 dialogs.ErrorDialog(_('Invalid account name'),
1997 _('Account name cannot contain spaces.'))
1998 return
1999 if active:
2000 # update variables
2001 gajim.interface.instances[new_name] = gajim.interface.instances[
2002 old_name]
2003 gajim.interface.minimized_controls[new_name] = \
2004 gajim.interface.minimized_controls[old_name]
2005 gajim.nicks[new_name] = gajim.nicks[old_name]
2006 gajim.block_signed_in_notifications[new_name] = \
2007 gajim.block_signed_in_notifications[old_name]
2008 gajim.groups[new_name] = gajim.groups[old_name]
2009 gajim.gc_connected[new_name] = gajim.gc_connected[old_name]
2010 gajim.automatic_rooms[new_name] = gajim.automatic_rooms[old_name]
2011 gajim.newly_added[new_name] = gajim.newly_added[old_name]
2012 gajim.to_be_removed[new_name] = gajim.to_be_removed[old_name]
2013 gajim.sleeper_state[new_name] = gajim.sleeper_state[old_name]
2014 gajim.encrypted_chats[new_name] = gajim.encrypted_chats[old_name]
2015 gajim.last_message_time[new_name] = \
2016 gajim.last_message_time[old_name]
2017 gajim.status_before_autoaway[new_name] = \
2018 gajim.status_before_autoaway[old_name]
2019 gajim.transport_avatar[new_name] = gajim.transport_avatar[old_name]
2020 gajim.gajim_optional_features[new_name] = \
2021 gajim.gajim_optional_features[old_name]
2022 gajim.caps_hash[new_name] = gajim.caps_hash[old_name]
2024 gajim.contacts.change_account_name(old_name, new_name)
2025 gajim.events.change_account_name(old_name, new_name)
2027 # change account variable for chat / gc controls
2028 gajim.interface.msg_win_mgr.change_account_name(old_name, new_name)
2029 # upgrade account variable in opened windows
2030 for kind in ('infos', 'disco', 'gc_config', 'search',
2031 'online_dialog'):
2032 for j in gajim.interface.instances[new_name][kind]:
2033 gajim.interface.instances[new_name][kind][j].account = \
2034 new_name
2036 # ServiceCache object keep old property account
2037 if hasattr(gajim.connections[old_name], 'services_cache'):
2038 gajim.connections[old_name].services_cache.account = new_name
2039 del gajim.interface.instances[old_name]
2040 del gajim.interface.minimized_controls[old_name]
2041 del gajim.nicks[old_name]
2042 del gajim.block_signed_in_notifications[old_name]
2043 del gajim.groups[old_name]
2044 del gajim.gc_connected[old_name]
2045 del gajim.automatic_rooms[old_name]
2046 del gajim.newly_added[old_name]
2047 del gajim.to_be_removed[old_name]
2048 del gajim.sleeper_state[old_name]
2049 del gajim.encrypted_chats[old_name]
2050 del gajim.last_message_time[old_name]
2051 del gajim.status_before_autoaway[old_name]
2052 del gajim.transport_avatar[old_name]
2053 del gajim.gajim_optional_features[old_name]
2054 del gajim.caps_hash[old_name]
2055 gajim.connections[old_name].name = new_name
2056 gajim.connections[old_name].pep_change_account_name(new_name)
2057 gajim.connections[old_name].caps_change_account_name(new_name)
2058 gajim.connections[new_name] = gajim.connections[old_name]
2059 del gajim.connections[old_name]
2060 gajim.config.add_per('accounts', new_name)
2061 old_config = gajim.config.get_per('accounts', old_name)
2062 for opt in old_config:
2063 gajim.config.set_per('accounts', new_name, opt, old_config[opt][1])
2064 gajim.config.del_per('accounts', old_name)
2065 if self.current_account == old_name:
2066 self.current_account = new_name
2067 if old_name == gajim.ZEROCONF_ACC_NAME:
2068 gajim.ZEROCONF_ACC_NAME = new_name
2069 # refresh roster
2070 gajim.interface.roster.setup_and_draw_roster()
2071 self.init_accounts()
2072 self.select_account(new_name)
2074 title = _('Rename Account')
2075 message = _('Enter a new name for account %s') % self.current_account
2076 old_text = self.current_account
2077 dialogs.InputDialog(title, message, old_text, is_modal=False,
2078 ok_handler=(on_renamed, self.current_account))
2080 def option_changed(self, option, value):
2081 return gajim.config.get_per('accounts', self.current_account, option) != \
2082 value
2084 def on_jid_entry1_focus_out_event(self, widget, event):
2085 if self.ignore_events:
2086 return
2087 jid = widget.get_text()
2088 # check if jid is conform to RFC and stringprep it
2089 try:
2090 jid = helpers.parse_jid(jid)
2091 except helpers.InvalidFormat, s:
2092 if not widget.is_focus():
2093 pritext = _('Invalid Jabber ID')
2094 dialogs.ErrorDialog(pritext, str(s))
2095 gobject.idle_add(lambda: widget.grab_focus())
2096 return True
2098 jid_splited = jid.split('@', 1)
2099 if len(jid_splited) != 2 and not gajim.config.get_per('accounts',
2100 self.current_account, 'anonymous_auth'):
2101 if not widget.is_focus():
2102 pritext = _('Invalid Jabber ID')
2103 sectext = _('A Jabber ID must be in the form "user@servername".')
2104 dialogs.ErrorDialog(pritext, sectext)
2105 gobject.idle_add(lambda: widget.grab_focus())
2106 return True
2109 if gajim.config.get_per('accounts', self.current_account,
2110 'anonymous_auth'):
2111 gajim.config.set_per('accounts', self.current_account, 'hostname',
2112 jid_splited[0])
2113 if self.option_changed('hostname', jid_splited[0]):
2114 self.need_relogin = True
2115 else:
2116 if self.option_changed('name', jid_splited[0]) or \
2117 self.option_changed('hostname', jid_splited[1]):
2118 self.need_relogin = True
2120 gajim.config.set_per('accounts', self.current_account, 'name',
2121 jid_splited[0])
2122 gajim.config.set_per('accounts', self.current_account, 'hostname',
2123 jid_splited[1])
2125 def on_cert_entry1_focus_out_event(self, widget, event):
2126 if self.ignore_events:
2127 return
2128 client_cert = widget.get_text()
2129 if self.option_changed('client_cert', client_cert):
2130 self.need_relogin = True
2131 gajim.config.set_per('accounts', self.current_account, 'client_cert',
2132 client_cert)
2134 def on_anonymous_checkbutton1_toggled(self, widget):
2135 if self.ignore_events:
2136 return
2137 active = widget.get_active()
2138 gajim.config.set_per('accounts', self.current_account, 'anonymous_auth',
2139 active)
2140 self.draw_normal_jid()
2142 def on_password_entry1_changed(self, widget):
2143 if self.ignore_events:
2144 return
2145 passwords.save_password(self.current_account, widget.get_text().decode(
2146 'utf-8'))
2148 def on_save_password_checkbutton1_toggled(self, widget):
2149 if self.ignore_events:
2150 return
2151 active = widget.get_active()
2152 password_entry = self.xml.get_object('password_entry1')
2153 password_entry.set_sensitive(active)
2154 gajim.config.set_per('accounts', self.current_account, 'savepass', active)
2155 if active:
2156 password = password_entry.get_text()
2157 passwords.save_password(self.current_account, password)
2158 else:
2159 passwords.save_password(self.current_account, '')
2161 def on_resource_entry1_focus_out_event(self, widget, event):
2162 if self.ignore_events:
2163 return
2164 resource = self.xml.get_object('resource_entry1').get_text().decode(
2165 'utf-8')
2166 try:
2167 resource = helpers.parse_resource(resource)
2168 except helpers.InvalidFormat, s:
2169 if not widget.is_focus():
2170 pritext = _('Invalid Jabber ID')
2171 dialogs.ErrorDialog(pritext, str(s))
2172 gobject.idle_add(lambda: widget.grab_focus())
2173 return True
2175 if self.option_changed('resource', resource):
2176 self.need_relogin = True
2178 gajim.config.set_per('accounts', self.current_account, 'resource',
2179 resource)
2181 def on_adjust_priority_with_status_checkbutton1_toggled(self, widget):
2182 self.xml.get_object('priority_spinbutton1').set_sensitive(
2183 not widget.get_active())
2184 self.on_checkbutton_toggled(widget, 'adjust_priority_with_status',
2185 account = self.current_account)
2187 def on_priority_spinbutton1_value_changed(self, widget):
2188 prio = widget.get_value_as_int()
2190 if self.option_changed('priority', prio):
2191 self.resend_presence = True
2193 gajim.config.set_per('accounts', self.current_account, 'priority', prio)
2195 def on_synchronise_contacts_button1_clicked(self, widget):
2196 try:
2197 dialogs.SynchroniseSelectAccountDialog(self.current_account)
2198 except GajimGeneralException:
2199 # If we showed ErrorDialog, there will not be dialog instance
2200 return
2202 def on_change_password_button1_clicked(self, widget):
2203 def on_changed(new_password):
2204 if new_password is not None:
2205 gajim.connections[self.current_account].change_password(
2206 new_password)
2207 if self.xml.get_object('save_password_checkbutton1').get_active():
2208 self.xml.get_object('password_entry1').set_text(new_password)
2210 try:
2211 dialogs.ChangePasswordDialog(self.current_account, on_changed)
2212 except GajimGeneralException:
2213 # if we showed ErrorDialog, there will not be dialog instance
2214 return
2216 def on_autoconnect_checkbutton_toggled(self, widget):
2217 if self.ignore_events:
2218 return
2219 self.on_checkbutton_toggled(widget, 'autoconnect',
2220 account=self.current_account)
2222 def on_autoreconnect_checkbutton_toggled(self, widget):
2223 if self.ignore_events:
2224 return
2225 self.on_checkbutton_toggled(widget, 'autoreconnect',
2226 account=self.current_account)
2228 def on_log_history_checkbutton_toggled(self, widget):
2229 if self.ignore_events:
2230 return
2231 list_no_log_for = gajim.config.get_per('accounts', self.current_account,
2232 'no_log_for').split()
2233 if self.current_account in list_no_log_for:
2234 list_no_log_for.remove(self.current_account)
2236 if not widget.get_active():
2237 list_no_log_for.append(self.current_account)
2238 gajim.config.set_per('accounts', self.current_account, 'no_log_for',
2239 ' '.join(list_no_log_for))
2241 def on_sync_with_global_status_checkbutton_toggled(self, widget):
2242 if self.ignore_events:
2243 return
2244 self.on_checkbutton_toggled(widget, 'sync_with_global_status',
2245 account=self.current_account)
2246 gajim.interface.roster.update_status_combobox()
2248 def on_use_ft_proxies_checkbutton1_toggled(self, widget):
2249 if self.ignore_events:
2250 return
2251 self.on_checkbutton_toggled(widget, 'use_ft_proxies',
2252 account=self.current_account)
2254 def on_use_env_http_proxy_checkbutton1_toggled(self, widget):
2255 if self.ignore_events:
2256 return
2257 self.on_checkbutton_toggled(widget, 'use_env_http_proxy',
2258 account=self.current_account)
2259 hbox = self.xml.get_object('proxy_hbox1')
2260 hbox.set_sensitive(not widget.get_active())
2262 def on_proxies_combobox1_changed(self, widget):
2263 active = widget.get_active()
2264 proxy = widget.get_model()[active][0].decode('utf-8')
2265 if proxy == _('None'):
2266 proxy = ''
2268 if self.option_changed('proxy', proxy):
2269 self.need_relogin = True
2271 gajim.config.set_per('accounts', self.current_account, 'proxy', proxy)
2273 def on_manage_proxies_button1_clicked(self, widget):
2274 if 'manage_proxies' in gajim.interface.instances:
2275 gajim.interface.instances['manage_proxies'].window.present()
2276 else:
2277 gajim.interface.instances['manage_proxies'] = ManageProxiesWindow()
2279 def on_warn_when_insecure_connection_checkbutton1_toggled(self, widget):
2280 if self.ignore_events:
2281 return
2283 self.on_checkbutton_toggled(widget, 'warn_when_insecure_ssl_connection',
2284 account=self.current_account)
2286 def on_send_keepalive_checkbutton1_toggled(self, widget):
2287 if self.ignore_events:
2288 return
2289 self.on_checkbutton_toggled(widget, 'keep_alives_enabled',
2290 account=self.current_account)
2291 gajim.config.set_per('accounts', self.current_account,
2292 'ping_alives_enabled', widget.get_active())
2294 def on_custom_host_port_checkbutton1_toggled(self, widget):
2295 if self.option_changed('use_custom_host', widget.get_active()):
2296 self.need_relogin = True
2298 self.on_checkbutton_toggled(widget, 'use_custom_host',
2299 account=self.current_account)
2300 active = widget.get_active()
2301 self.xml.get_object('custom_host_port_hbox1').set_sensitive(active)
2303 def on_custom_host_entry1_changed(self, widget):
2304 if self.ignore_events:
2305 return
2306 host = widget.get_text().decode('utf-8')
2307 if self.option_changed('custom_host', host):
2308 self.need_relogin = True
2309 gajim.config.set_per('accounts', self.current_account, 'custom_host',
2310 host)
2312 def on_custom_port_entry_focus_out_event(self, widget, event):
2313 if self.ignore_events:
2314 return
2315 custom_port = widget.get_text()
2316 try:
2317 custom_port = int(custom_port)
2318 except Exception:
2319 if not widget.is_focus():
2320 dialogs.ErrorDialog(_('Invalid entry'),
2321 _('Custom port must be a port number.'))
2322 gobject.idle_add(lambda: widget.grab_focus())
2323 return True
2324 if self.option_changed('custom_port', custom_port):
2325 self.need_relogin = True
2326 gajim.config.set_per('accounts', self.current_account, 'custom_port',
2327 custom_port)
2329 def on_gpg_choose_button_clicked(self, widget, data = None):
2330 if self.current_account in gajim.connections and \
2331 gajim.connections[self.current_account].gpg:
2332 secret_keys = gajim.connections[self.current_account].\
2333 ask_gpg_secrete_keys()
2335 # self.current_account is None and/or gajim.connections is {}
2336 else:
2337 if gajim.HAVE_GPG:
2338 secret_keys = gpg.GnuPG().get_secret_keys()
2339 else:
2340 secret_keys = []
2341 if not secret_keys:
2342 dialogs.ErrorDialog(_('Failed to get secret keys'),
2343 _('There is no OpenPGP secret key available.'))
2344 secret_keys[_('None')] = _('None')
2346 def on_key_selected(keyID):
2347 if keyID is None:
2348 return
2349 if self.current_account == gajim.ZEROCONF_ACC_NAME:
2350 wiget_name_ext = '2'
2351 else:
2352 wiget_name_ext = '1'
2353 gpg_key_label = self.xml.get_object('gpg_key_label' + wiget_name_ext)
2354 gpg_name_label = self.xml.get_object('gpg_name_label' + wiget_name_ext)
2355 use_gpg_agent_checkbutton = self.xml.get_object(
2356 'use_gpg_agent_checkbutton' + wiget_name_ext)
2357 if keyID[0] == _('None'):
2358 gpg_key_label.set_text(_('No key selected'))
2359 gpg_name_label.set_text('')
2360 use_gpg_agent_checkbutton.set_sensitive(False)
2361 if self.option_changed('keyid', ''):
2362 self.need_relogin = True
2363 gajim.config.set_per('accounts', self.current_account, 'keyname',
2365 gajim.config.set_per('accounts', self.current_account, 'keyid', '')
2366 else:
2367 gpg_key_label.set_text(keyID[0])
2368 gpg_name_label.set_text(keyID[1])
2369 use_gpg_agent_checkbutton.set_sensitive(True)
2370 if self.option_changed('keyid', keyID[0]):
2371 self.need_relogin = True
2372 gajim.config.set_per('accounts', self.current_account, 'keyname',
2373 keyID[1])
2374 gajim.config.set_per('accounts', self.current_account, 'keyid',
2375 keyID[0])
2377 dialogs.ChooseGPGKeyDialog(_('OpenPGP Key Selection'),
2378 _('Choose your OpenPGP key'), secret_keys, on_key_selected)
2380 def on_use_gpg_agent_checkbutton_toggled(self, widget):
2381 self.on_checkbutton_toggled(widget, 'use_gpg_agent')
2383 def on_edit_details_button1_clicked(self, widget):
2384 if self.current_account not in gajim.interface.instances:
2385 dialogs.ErrorDialog(_('No such account available'),
2386 _('You must create your account before editing your personal '
2387 'information.'))
2388 return
2390 # show error dialog if account is newly created (not in gajim.connections)
2391 if self.current_account not in gajim.connections or \
2392 gajim.connections[self.current_account].connected < 2:
2393 dialogs.ErrorDialog(_('You are not connected to the server'),
2394 _('Without a connection, you can not edit your personal information.'))
2395 return
2397 if not gajim.connections[self.current_account].vcard_supported:
2398 dialogs.ErrorDialog(_("Your server doesn't support Vcard"),
2399 _("Your server can't save your personal information."))
2400 return
2402 gajim.interface.edit_own_details(self.current_account)
2404 def on_checkbutton_toggled(self, widget, config_name,
2405 change_sensitivity_widgets = None, account = None):
2406 if account:
2407 gajim.config.set_per('accounts', account, config_name,
2408 widget.get_active())
2409 else:
2410 gajim.config.set(config_name, widget.get_active())
2411 if change_sensitivity_widgets:
2412 for w in change_sensitivity_widgets:
2413 w.set_sensitive(widget.get_active())
2414 gajim.interface.save_config()
2416 def on_merge_checkbutton_toggled(self, widget):
2417 self.on_checkbutton_toggled(widget, 'mergeaccounts')
2418 if len(gajim.connections) >= 2: # Do not merge accounts if only one active
2419 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
2420 else:
2421 gajim.interface.roster.regroup = False
2422 gajim.interface.roster.setup_and_draw_roster()
2424 def _disable_account(self, account):
2425 gajim.interface.roster.close_all(account)
2426 if account == gajim.ZEROCONF_ACC_NAME:
2427 gajim.connections[account].disable_account()
2428 del gajim.connections[account]
2429 gajim.interface.save_config()
2430 del gajim.interface.instances[account]
2431 del gajim.interface.minimized_controls[account]
2432 del gajim.nicks[account]
2433 del gajim.block_signed_in_notifications[account]
2434 del gajim.groups[account]
2435 gajim.contacts.remove_account(account)
2436 del gajim.gc_connected[account]
2437 del gajim.automatic_rooms[account]
2438 del gajim.to_be_removed[account]
2439 del gajim.newly_added[account]
2440 del gajim.sleeper_state[account]
2441 del gajim.encrypted_chats[account]
2442 del gajim.last_message_time[account]
2443 del gajim.status_before_autoaway[account]
2444 del gajim.transport_avatar[account]
2445 del gajim.gajim_optional_features[account]
2446 del gajim.caps_hash[account]
2447 if len(gajim.connections) >= 2:
2448 # Do not merge accounts if only one exists
2449 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
2450 else:
2451 gajim.interface.roster.regroup = False
2452 gajim.interface.roster.setup_and_draw_roster()
2453 gajim.interface.roster.set_actions_menu_needs_rebuild()
2455 def _enable_account(self, account):
2456 if account == gajim.ZEROCONF_ACC_NAME:
2457 gajim.connections[account] = connection_zeroconf.ConnectionZeroconf(
2458 account)
2459 if gajim.connections[account].gpg:
2460 self.xml.get_object('gpg_choose_button2').set_sensitive(True)
2461 else:
2462 gajim.connections[account] = common.connection.Connection(account)
2463 if gajim.connections[account].gpg:
2464 self.xml.get_object('gpg_choose_button1').set_sensitive(True)
2465 self.init_account_gpg()
2466 # update variables
2467 gajim.interface.instances[account] = {'infos': {},
2468 'disco': {}, 'gc_config': {}, 'search': {}, 'online_dialog': {}}
2469 gajim.interface.minimized_controls[account] = {}
2470 gajim.connections[account].connected = 0
2471 gajim.groups[account] = {}
2472 gajim.contacts.add_account(account)
2473 gajim.gc_connected[account] = {}
2474 gajim.automatic_rooms[account] = {}
2475 gajim.newly_added[account] = []
2476 gajim.to_be_removed[account] = []
2477 if account == gajim.ZEROCONF_ACC_NAME:
2478 gajim.nicks[account] = gajim.ZEROCONF_ACC_NAME
2479 else:
2480 gajim.nicks[account] = gajim.config.get_per('accounts', account,
2481 'name')
2482 gajim.block_signed_in_notifications[account] = True
2483 gajim.sleeper_state[account] = 'off'
2484 gajim.encrypted_chats[account] = []
2485 gajim.last_message_time[account] = {}
2486 gajim.status_before_autoaway[account] = ''
2487 gajim.transport_avatar[account] = {}
2488 gajim.gajim_optional_features[account] = []
2489 gajim.caps_hash[account] = ''
2490 # refresh roster
2491 if len(gajim.connections) >= 2:
2492 # Do not merge accounts if only one exists
2493 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
2494 else:
2495 gajim.interface.roster.regroup = False
2496 gajim.interface.roster.setup_and_draw_roster()
2497 gajim.interface.roster.set_actions_menu_needs_rebuild()
2498 gajim.interface.save_config()
2500 def on_enable_zeroconf_checkbutton2_toggled(self, widget):
2501 # don't do anything if there is an account with the local name but is a
2502 # normal account
2503 if self.ignore_events:
2504 return
2505 if self.current_account in gajim.connections and \
2506 gajim.connections[self.current_account].connected > 0:
2507 self.ignore_events = True
2508 self.xml.get_object('enable_zeroconf_checkbutton2').set_active(True)
2509 self.ignore_events = False
2510 dialogs.ErrorDialog(
2511 _('You are currently connected to the server'),
2512 _('To disable the account, you must be disconnected.'))
2513 return
2514 if gajim.ZEROCONF_ACC_NAME in gajim.connections and not \
2515 gajim.connections[gajim.ZEROCONF_ACC_NAME].is_zeroconf:
2516 gajim.connections[gajim.ZEROCONF_ACC_NAME].dispatch('ERROR',
2517 (_('Account Local already exists.'),
2518 _('Please rename or remove it before enabling link-local messaging'
2519 '.')))
2520 return
2522 if gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'active') \
2523 and not widget.get_active():
2524 self.xml.get_object('zeroconf_notebook').set_sensitive(False)
2525 # disable
2526 self._disable_account(gajim.ZEROCONF_ACC_NAME)
2528 elif not gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
2529 'active') and widget.get_active():
2530 self.xml.get_object('zeroconf_notebook').set_sensitive(True)
2531 # enable (will create new account if not present)
2532 self._enable_account(gajim.ZEROCONF_ACC_NAME)
2534 self.on_checkbutton_toggled(widget, 'active',
2535 account=gajim.ZEROCONF_ACC_NAME)
2537 def on_enable_checkbutton1_toggled(self, widget):
2538 if self.ignore_events:
2539 return
2540 if self.current_account in gajim.connections and \
2541 gajim.connections[self.current_account].connected > 0:
2542 # connecting or connected
2543 self.ignore_events = True
2544 self.xml.get_object('enable_checkbutton1').set_active(True)
2545 self.ignore_events = False
2546 dialogs.ErrorDialog(
2547 _('You are currently connected to the server'),
2548 _('To disable the account, you must be disconnected.'))
2549 return
2550 # add/remove account in roster and all variables
2551 if widget.get_active():
2552 # enable
2553 self._enable_account(self.current_account)
2554 else:
2555 # disable
2556 self._disable_account(self.current_account)
2557 self.on_checkbutton_toggled(widget, 'active',
2558 account=self.current_account, change_sensitivity_widgets=[
2559 self.xml.get_object('normal_notebook1')])
2561 def on_custom_port_checkbutton2_toggled(self, widget):
2562 self.xml.get_object('custom_port_entry2').set_sensitive(
2563 widget.get_active())
2564 self.on_checkbutton_toggled(widget, 'use_custom_host',
2565 account = self.current_account)
2566 if not widget.get_active():
2567 self.xml.get_object('custom_port_entry2').set_text('5298')
2569 def on_first_name_entry2_changed(self, widget):
2570 if self.ignore_events:
2571 return
2572 name = widget.get_text().decode('utf-8')
2573 if self.option_changed('zeroconf_first_name', name):
2574 self.need_relogin = True
2575 gajim.config.set_per('accounts', self.current_account,
2576 'zeroconf_first_name', name)
2578 def on_last_name_entry2_changed(self, widget):
2579 if self.ignore_events:
2580 return
2581 name = widget.get_text().decode('utf-8')
2582 if self.option_changed('zeroconf_last_name', name):
2583 self.need_relogin = True
2584 gajim.config.set_per('accounts', self.current_account,
2585 'zeroconf_last_name', name)
2587 def on_jabber_id_entry2_changed(self, widget):
2588 if self.ignore_events:
2589 return
2590 id_ = widget.get_text().decode('utf-8')
2591 if self.option_changed('zeroconf_jabber_id', id_):
2592 self.need_relogin = True
2593 gajim.config.set_per('accounts', self.current_account,
2594 'zeroconf_jabber_id', id_)
2596 def on_email_entry2_changed(self, widget):
2597 if self.ignore_events:
2598 return
2599 email = widget.get_text().decode('utf-8')
2600 if self.option_changed('zeroconf_email', email):
2601 self.need_relogin = True
2602 gajim.config.set_per('accounts', self.current_account,
2603 'zeroconf_email', email)
2605 class FakeDataForm(gtk.Table, object):
2607 Class for forms that are in XML format <entry1>value1</entry1> infos in a
2608 table {entry1: value1}
2611 def __init__(self, infos):
2612 gtk.Table.__init__(self)
2613 self.infos = infos
2614 self.entries = {}
2615 self._draw_table()
2617 def _draw_table(self):
2619 Draw the table
2621 nbrow = 0
2622 if 'instructions' in self.infos:
2623 nbrow = 1
2624 self.resize(rows = nbrow, columns = 2)
2625 label = gtk.Label(self.infos['instructions'])
2626 self.attach(label, 0, 2, 0, 1, 0, 0, 0, 0)
2627 for name in self.infos.keys():
2628 if name in ('key', 'instructions', 'x', 'registered'):
2629 continue
2630 if not name:
2631 continue
2633 nbrow = nbrow + 1
2634 self.resize(rows = nbrow, columns = 2)
2635 label = gtk.Label(name.capitalize() + ':')
2636 self.attach(label, 0, 1, nbrow - 1, nbrow, 0, 0, 0, 0)
2637 entry = gtk.Entry()
2638 entry.set_activates_default(True)
2639 if self.infos[name]:
2640 entry.set_text(self.infos[name])
2641 if name == 'password':
2642 entry.set_visibility(False)
2643 self.attach(entry, 1, 2, nbrow - 1, nbrow, 0, 0, 0, 0)
2644 self.entries[name] = entry
2645 if nbrow == 1:
2646 entry.grab_focus()
2648 def get_infos(self):
2649 for name in self.entries.keys():
2650 self.infos[name] = self.entries[name].get_text().decode('utf-8')
2651 return self.infos
2653 class ServiceRegistrationWindow:
2655 Class for Service registration window. Window that appears when we want to
2656 subscribe to a service if is_form we use dataforms_widget else we use
2657 service_registarion_window
2659 def __init__(self, service, infos, account, is_form):
2660 self.service = service
2661 self.account = account
2662 self.is_form = is_form
2663 self.xml = gtkgui_helpers.get_gtk_builder('service_registration_window.ui')
2664 self.window = self.xml.get_object('service_registration_window')
2665 self.window.set_transient_for(gajim.interface.roster.window)
2666 if self.is_form:
2667 dataform = dataforms.ExtendForm(node = infos)
2668 self.data_form_widget = dataforms_widget.DataFormWidget(dataform)
2669 if self.data_form_widget.title:
2670 self.window.set_title('%s - Gajim' % self.data_form_widget.title)
2671 table = self.xml.get_object('table')
2672 table.attach(self.data_form_widget, 0, 2, 0, 1)
2673 else:
2674 if 'registered' in infos:
2675 self.window.set_title(_('Edit %s') % service)
2676 else:
2677 self.window.set_title(_('Register to %s') % service)
2678 self.data_form_widget = FakeDataForm(infos)
2679 table = self.xml.get_object('table')
2680 table.attach(self.data_form_widget, 0, 2, 0, 1)
2682 self.xml.connect_signals(self)
2683 self.window.show_all()
2685 def on_cancel_button_clicked(self, widget):
2686 self.window.destroy()
2688 def on_ok_button_clicked(self, widget):
2689 # send registration info to the core
2690 if self.is_form:
2691 form = self.data_form_widget.data_form
2692 gajim.connections[self.account].register_agent(self.service,
2693 form, True) # True is for is_form
2694 else:
2695 infos = self.data_form_widget.get_infos()
2696 if 'instructions' in infos:
2697 del infos['instructions']
2698 if 'registered' in infos:
2699 del infos['registered']
2700 gajim.connections[self.account].register_agent(self.service, infos)
2702 self.window.destroy()
2704 class GroupchatConfigWindow:
2706 def __init__(self, account, room_jid, form=None):
2707 self.account = account
2708 self.room_jid = room_jid
2709 self.form = form
2710 self.remove_button = {}
2711 self.affiliation_treeview = {}
2712 self.start_users_dict = {} # list at the beginning
2713 self.affiliation_labels = {'outcast': _('Ban List'),
2714 'member': _('Member List'), 'owner': _('Owner List'),
2715 'admin':_('Administrator List')}
2717 self.xml = gtkgui_helpers.get_gtk_builder('data_form_window.ui',
2718 'data_form_window')
2719 self.window = self.xml.get_object('data_form_window')
2720 self.window.set_transient_for(gajim.interface.roster.window)
2722 if self.form:
2723 config_vbox = self.xml.get_object('config_vbox')
2724 self.data_form_widget = dataforms_widget.DataFormWidget(self.form)
2725 # hide scrollbar of this data_form_widget, we already have in this
2726 # widget
2727 sw = self.data_form_widget.xml.get_object(
2728 'single_form_scrolledwindow')
2729 sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
2730 if self.form.title:
2731 self.xml.get_object('title_label').set_text(self.form.title)
2732 else:
2733 self.xml.get_object('title_hseparator').set_no_show_all(True)
2734 self.xml.get_object('title_hseparator').hide()
2736 self.data_form_widget.show()
2737 config_vbox.pack_start(self.data_form_widget)
2738 else:
2739 self.xml.get_object('title_label').set_no_show_all(True)
2740 self.xml.get_object('title_label').hide()
2741 self.xml.get_object('title_hseparator').set_no_show_all(True)
2742 self.xml.get_object('title_hseparator').hide()
2743 self.xml.get_object('config_hseparator').set_no_show_all(True)
2744 self.xml.get_object('config_hseparator').hide()
2746 # Draw the edit affiliation list things
2747 add_on_vbox = self.xml.get_object('add_on_vbox')
2749 for affiliation in self.affiliation_labels.keys():
2750 self.start_users_dict[affiliation] = {}
2751 hbox = gtk.HBox(spacing=5)
2752 add_on_vbox.pack_start(hbox, False)
2754 label = gtk.Label(self.affiliation_labels[affiliation])
2755 hbox.pack_start(label, False)
2757 bb = gtk.HButtonBox()
2758 bb.set_layout(gtk.BUTTONBOX_END)
2759 bb.set_spacing(5)
2760 hbox.pack_start(bb)
2761 add_button = gtk.Button(stock=gtk.STOCK_ADD)
2762 add_button.connect('clicked', self.on_add_button_clicked,
2763 affiliation)
2764 bb.pack_start(add_button)
2765 self.remove_button[affiliation] = gtk.Button(stock=gtk.STOCK_REMOVE)
2766 self.remove_button[affiliation].set_sensitive(False)
2767 self.remove_button[affiliation].connect('clicked',
2768 self.on_remove_button_clicked, affiliation)
2769 bb.pack_start(self.remove_button[affiliation])
2771 # jid, reason, nick, role
2772 liststore = gtk.ListStore(str, str, str, str)
2773 self.affiliation_treeview[affiliation] = gtk.TreeView(liststore)
2774 self.affiliation_treeview[affiliation].get_selection().set_mode(
2775 gtk.SELECTION_MULTIPLE)
2776 self.affiliation_treeview[affiliation].connect('cursor-changed',
2777 self.on_affiliation_treeview_cursor_changed, affiliation)
2778 renderer = gtk.CellRendererText()
2779 col = gtk.TreeViewColumn(_('JID'), renderer)
2780 col.add_attribute(renderer, 'text', 0)
2781 col.set_resizable(True)
2782 col.set_sort_column_id(0)
2783 self.affiliation_treeview[affiliation].append_column(col)
2785 if affiliation == 'outcast':
2786 renderer = gtk.CellRendererText()
2787 renderer.set_property('editable', True)
2788 renderer.connect('edited', self.on_cell_edited)
2789 col = gtk.TreeViewColumn(_('Reason'), renderer)
2790 col.add_attribute(renderer, 'text', 1)
2791 col.set_resizable(True)
2792 col.set_sort_column_id(1)
2793 self.affiliation_treeview[affiliation].append_column(col)
2794 elif affiliation == 'member':
2795 renderer = gtk.CellRendererText()
2796 col = gtk.TreeViewColumn(_('Nick'), renderer)
2797 col.add_attribute(renderer, 'text', 2)
2798 col.set_resizable(True)
2799 col.set_sort_column_id(2)
2800 self.affiliation_treeview[affiliation].append_column(col)
2801 renderer = gtk.CellRendererText()
2802 col = gtk.TreeViewColumn(_('Role'), renderer)
2803 col.add_attribute(renderer, 'text', 3)
2804 col.set_resizable(True)
2805 col.set_sort_column_id(3)
2806 self.affiliation_treeview[affiliation].append_column(col)
2808 sw = gtk.ScrolledWindow()
2809 sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_NEVER)
2810 sw.add(self.affiliation_treeview[affiliation])
2811 add_on_vbox.pack_start(sw)
2812 gajim.connections[self.account].get_affiliation_list(self.room_jid,
2813 affiliation)
2815 self.xml.connect_signals(self)
2816 self.window.show_all()
2818 def on_cancel_button_clicked(self, widget):
2819 self.window.destroy()
2821 def on_cell_edited(self, cell, path, new_text):
2822 model = self.affiliation_treeview['outcast'].get_model()
2823 new_text = new_text.decode('utf-8')
2824 iter_ = model.get_iter(path)
2825 model[iter_][1] = new_text
2827 def on_add_button_clicked(self, widget, affiliation):
2828 if affiliation == 'outcast':
2829 title = _('Banning...')
2830 #You can move '\n' before user@domain if that line is TOO BIG
2831 prompt = _('<b>Whom do you want to ban?</b>\n\n')
2832 elif affiliation == 'member':
2833 title = _('Adding Member...')
2834 prompt = _('<b>Whom do you want to make a member?</b>\n\n')
2835 elif affiliation == 'owner':
2836 title = _('Adding Owner...')
2837 prompt = _('<b>Whom do you want to make an owner?</b>\n\n')
2838 else:
2839 title = _('Adding Administrator...')
2840 prompt = _('<b>Whom do you want to make an administrator?</b>\n\n')
2841 prompt += _('Can be one of the following:\n'
2842 '1. user@domain/resource (only that resource matches).\n'
2843 '2. user@domain (any resource matches).\n'
2844 '3. domain/resource (only that resource matches).\n'
2845 '4. domain (the domain itself matches, as does any user@domain,\n'
2846 'domain/resource, or address containing a subdomain).')
2848 def on_ok(jid):
2849 if not jid:
2850 return
2851 model = self.affiliation_treeview[affiliation].get_model()
2852 model.append((jid, '', '', ''))
2853 dialogs.InputDialog(title, prompt, ok_handler=on_ok)
2855 def on_remove_button_clicked(self, widget, affiliation):
2856 selection = self.affiliation_treeview[affiliation].get_selection()
2857 model, paths = selection.get_selected_rows()
2858 row_refs = []
2859 for path in paths:
2860 row_refs.append(gtk.TreeRowReference(model, path))
2861 for row_ref in row_refs:
2862 path = row_ref.get_path()
2863 iter_ = model.get_iter(path)
2864 model.remove(iter_)
2865 self.remove_button[affiliation].set_sensitive(False)
2867 def on_affiliation_treeview_cursor_changed(self, widget, affiliation):
2868 self.remove_button[affiliation].set_sensitive(True)
2870 def affiliation_list_received(self, users_dict):
2872 Fill the affiliation treeview
2874 for jid in users_dict:
2875 affiliation = users_dict[jid]['affiliation']
2876 if affiliation not in self.affiliation_labels.keys():
2877 # Unknown affiliation or 'none' affiliation, do not show it
2878 continue
2879 self.start_users_dict[affiliation][jid] = users_dict[jid]
2880 tv = self.affiliation_treeview[affiliation]
2881 model = tv.get_model()
2882 reason = users_dict[jid].get('reason', '')
2883 nick = users_dict[jid].get('nick', '')
2884 role = users_dict[jid].get('role', '')
2885 model.append((jid, reason, nick, role))
2887 def on_data_form_window_destroy(self, widget):
2888 del gajim.interface.instances[self.account]['gc_config'][self.room_jid]
2890 def on_ok_button_clicked(self, widget):
2891 if self.form:
2892 form = self.data_form_widget.data_form
2893 gajim.connections[self.account].send_gc_config(self.room_jid, form)
2894 for affiliation in self.affiliation_labels.keys():
2895 users_dict = {}
2896 actual_jid_list = []
2897 model = self.affiliation_treeview[affiliation].get_model()
2898 iter_ = model.get_iter_first()
2899 # add new jid
2900 while iter_:
2901 jid = model[iter_][0].decode('utf-8')
2902 actual_jid_list.append(jid)
2903 if jid not in self.start_users_dict[affiliation] or \
2904 (affiliation == 'outcast' and 'reason' in self.start_users_dict[
2905 affiliation][jid] and self.start_users_dict[affiliation][jid]\
2906 ['reason'] != model[iter_][1].decode('utf-8')):
2907 users_dict[jid] = {'affiliation': affiliation}
2908 if affiliation == 'outcast':
2909 users_dict[jid]['reason'] = model[iter_][1].decode(
2910 'utf-8')
2911 iter_ = model.iter_next(iter_)
2912 # remove removed one
2913 for jid in self.start_users_dict[affiliation]:
2914 if jid not in actual_jid_list:
2915 users_dict[jid] = {'affiliation': 'none'}
2916 if users_dict:
2917 gajim.connections[self.account].send_gc_affiliation_list(
2918 self.room_jid, users_dict)
2919 self.window.destroy()
2921 #---------- RemoveAccountWindow class -------------#
2922 class RemoveAccountWindow:
2924 Ask for removing from gajim only or from gajim and server too and do
2925 removing of the account given
2928 def on_remove_account_window_destroy(self, widget):
2929 if self.account in gajim.interface.instances:
2930 del gajim.interface.instances[self.account]['remove_account']
2932 def on_cancel_button_clicked(self, widget):
2933 self.window.destroy()
2935 def __init__(self, account):
2936 self.account = account
2937 xml = gtkgui_helpers.get_gtk_builder('remove_account_window.ui')
2938 self.window = xml.get_object('remove_account_window')
2939 self.window.set_transient_for(gajim.interface.roster.window)
2940 self.remove_and_unregister_radiobutton = xml.get_object(
2941 'remove_and_unregister_radiobutton')
2942 self.window.set_title(_('Removing %s account') % self.account)
2943 xml.connect_signals(self)
2944 self.window.show_all()
2946 def on_remove_button_clicked(self, widget):
2947 def remove():
2948 if self.account in gajim.connections and \
2949 gajim.connections[self.account].connected and \
2950 not self.remove_and_unregister_radiobutton.get_active():
2951 # change status to offline only if we will not remove this JID from
2952 # server
2953 gajim.connections[self.account].change_status('offline', 'offline')
2954 if self.remove_and_unregister_radiobutton.get_active():
2955 if not self.account in gajim.connections:
2956 dialogs.ErrorDialog(
2957 _('Account is disabled'),
2958 _('To unregister from a server, account must be '
2959 'enabled.'))
2960 return
2961 if not gajim.connections[self.account].password:
2962 def on_ok(passphrase, checked):
2963 if passphrase == -1:
2964 # We don't remove account cause we canceled pw window
2965 return
2966 gajim.connections[self.account].password = passphrase
2967 gajim.connections[self.account].unregister_account(
2968 self._on_remove_success)
2970 dialogs.PassphraseDialog(
2971 _('Password Required'),
2972 _('Enter your password for account %s') % self.account,
2973 _('Save password'), ok_handler=on_ok)
2974 return
2975 gajim.connections[self.account].unregister_account(
2976 self._on_remove_success)
2977 else:
2978 self._on_remove_success(True)
2980 if self.account in gajim.connections and \
2981 gajim.connections[self.account].connected:
2982 dialogs.ConfirmationDialog(
2983 _('Account "%s" is connected to the server') % self.account,
2984 _('If you remove it, the connection will be lost.'),
2985 on_response_ok=remove)
2986 else:
2987 remove()
2989 def on_remove_responce_ok(self, is_checked):
2990 if is_checked[0]:
2991 self._on_remove_success(True)
2993 def _on_remove_success(self, res):
2994 # action of unregistration has failed, we don't remove the account
2995 # Error message is send by connect_and_auth()
2996 if not res:
2997 dialogs.ConfirmationDialogDoubleRadio(
2998 _('Connection to server %s failed') % self.account,
2999 _('What would you like to do?'),
3000 _('Remove only from Gajim'),
3001 _('Don\'t remove anything. I\'ll try again later'),
3002 on_response_ok=self.on_remove_responce_ok, is_modal=False)
3003 return
3004 # Close all opened windows
3005 gajim.interface.roster.close_all(self.account, force=True)
3006 if self.account in gajim.connections:
3007 gajim.connections[self.account].disconnect(on_purpose=True)
3008 del gajim.connections[self.account]
3009 gajim.logger.remove_roster(gajim.get_jid_from_account(self.account))
3010 gajim.config.del_per('accounts', self.account)
3011 gajim.interface.save_config()
3012 del gajim.interface.instances[self.account]
3013 if self.account in gajim.nicks:
3014 del gajim.interface.minimized_controls[self.account]
3015 del gajim.nicks[self.account]
3016 del gajim.block_signed_in_notifications[self.account]
3017 del gajim.groups[self.account]
3018 gajim.contacts.remove_account(self.account)
3019 del gajim.gc_connected[self.account]
3020 del gajim.automatic_rooms[self.account]
3021 del gajim.to_be_removed[self.account]
3022 del gajim.newly_added[self.account]
3023 del gajim.sleeper_state[self.account]
3024 del gajim.encrypted_chats[self.account]
3025 del gajim.last_message_time[self.account]
3026 del gajim.status_before_autoaway[self.account]
3027 del gajim.transport_avatar[self.account]
3028 del gajim.gajim_optional_features[self.account]
3029 del gajim.caps_hash[self.account]
3030 if len(gajim.connections) >= 2: # Do not merge accounts if only one exists
3031 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
3032 else:
3033 gajim.interface.roster.regroup = False
3034 gajim.interface.roster.setup_and_draw_roster()
3035 gajim.interface.roster.set_actions_menu_needs_rebuild()
3036 if 'accounts' in gajim.interface.instances:
3037 gajim.interface.instances['accounts'].init_accounts()
3038 gajim.interface.instances['accounts'].init_account()
3039 self.window.destroy()
3041 #---------- ManageBookmarksWindow class -------------#
3042 class ManageBookmarksWindow:
3043 def __init__(self):
3044 self.xml = gtkgui_helpers.get_gtk_builder('manage_bookmarks_window.ui')
3045 self.window = self.xml.get_object('manage_bookmarks_window')
3046 self.window.set_transient_for(gajim.interface.roster.window)
3048 # Account-JID, RoomName, Room-JID, Autojoin, Minimize, Passowrd, Nick,
3049 # Show_Status
3050 self.treestore = gtk.TreeStore(str, str, str, bool, bool, str, str, str)
3051 self.treestore.set_sort_column_id(1, gtk.SORT_ASCENDING)
3053 # Store bookmarks in treeview.
3054 for account in gajim.connections:
3055 if gajim.connections[account].connected <= 1:
3056 continue
3057 if gajim.connections[account].is_zeroconf:
3058 continue
3059 if not gajim.connections[account].private_storage_supported:
3060 continue
3061 iter_ = self.treestore.append(None, [None, account, None, None,
3062 None, None, None, None])
3064 for bookmark in gajim.connections[account].bookmarks:
3065 if bookmark['name'] == '':
3066 # No name was given for this bookmark.
3067 # Use the first part of JID instead...
3068 name = bookmark['jid'].split("@")[0]
3069 bookmark['name'] = name
3071 # make '1', '0', 'true', 'false' (or other) to True/False
3072 autojoin = helpers.from_xs_boolean_to_python_boolean(
3073 bookmark['autojoin'])
3075 minimize = helpers.from_xs_boolean_to_python_boolean(
3076 bookmark['minimize'])
3078 print_status = bookmark.get('print_status', '')
3079 if print_status not in ('', 'all', 'in_and_out', 'none'):
3080 print_status = ''
3081 self.treestore.append(iter_, [
3082 account,
3083 bookmark['name'],
3084 bookmark['jid'],
3085 autojoin,
3086 minimize,
3087 bookmark['password'],
3088 bookmark['nick'],
3089 print_status ])
3091 self.print_status_combobox = self.xml.get_object('print_status_combobox')
3092 model = gtk.ListStore(str, str)
3094 self.option_list = {'': _('Default'), 'all': Q_('?print_status:All'),
3095 'in_and_out': _('Enter and leave only'),
3096 'none': Q_('?print_status:None')}
3097 opts = sorted(self.option_list.keys())
3098 for opt in opts:
3099 model.append([self.option_list[opt], opt])
3101 self.print_status_combobox.set_model(model)
3102 self.print_status_combobox.set_active(1)
3104 self.view = self.xml.get_object('bookmarks_treeview')
3105 self.view.set_model(self.treestore)
3106 self.view.expand_all()
3108 renderer = gtk.CellRendererText()
3109 column = gtk.TreeViewColumn('Bookmarks', renderer, text=1)
3110 self.view.append_column(column)
3112 self.selection = self.view.get_selection()
3113 self.selection.connect('changed', self.bookmark_selected)
3115 #Prepare input fields
3116 self.title_entry = self.xml.get_object('title_entry')
3117 self.title_entry.connect('changed', self.on_title_entry_changed)
3118 self.nick_entry = self.xml.get_object('nick_entry')
3119 self.nick_entry.connect('changed', self.on_nick_entry_changed)
3120 self.server_entry = self.xml.get_object('server_entry')
3121 self.server_entry.connect('changed', self.on_server_entry_changed)
3122 self.room_entry = self.xml.get_object('room_entry')
3123 self.room_entry.connect('changed', self.on_room_entry_changed)
3124 self.pass_entry = self.xml.get_object('pass_entry')
3125 self.pass_entry.connect('changed', self.on_pass_entry_changed)
3126 self.autojoin_checkbutton = self.xml.get_object('autojoin_checkbutton')
3127 self.minimize_checkbutton = self.xml.get_object('minimize_checkbutton')
3129 self.xml.connect_signals(self)
3130 self.window.show_all()
3131 # select root iter
3132 self.selection.select_iter(self.treestore.get_iter_root())
3134 def on_bookmarks_treeview_button_press_event(self, widget, event):
3135 (model, iter_) = self.selection.get_selected()
3136 if not iter_:
3137 # Removed a bookmark before
3138 return
3140 if model.iter_parent(iter_):
3141 # The currently selected node is a bookmark
3142 return not self.check_valid_bookmark()
3144 def on_manage_bookmarks_window_destroy(self, widget, event):
3145 del gajim.interface.instances['manage_bookmarks']
3147 def on_add_bookmark_button_clicked(self, widget):
3149 Add a new bookmark
3151 # Get the account that is currently used
3152 # (the parent of the currently selected item)
3153 (model, iter_) = self.selection.get_selected()
3154 if not iter_: # Nothing selected, do nothing
3155 return
3157 parent = model.iter_parent(iter_)
3159 if parent:
3160 # We got a bookmark selected, so we add_to the parent
3161 add_to = parent
3162 else:
3163 # No parent, so we got an account -> add to this.
3164 add_to = iter_
3166 account = model[add_to][1].decode('utf-8')
3167 nick = gajim.nicks[account]
3168 iter_ = self.treestore.append(add_to, [account, _('New Group Chat'),
3169 '@', False, False, '', nick, 'in_and_out'])
3171 self.view.expand_row(model.get_path(add_to), True)
3172 self.view.set_cursor(model.get_path(iter_))
3174 def on_remove_bookmark_button_clicked(self, widget):
3176 Remove selected bookmark
3178 (model, iter_) = self.selection.get_selected()
3179 if not iter_: # Nothing selected
3180 return
3182 if not model.iter_parent(iter_):
3183 # Don't remove account iters
3184 return
3186 model.remove(iter_)
3187 self.clear_fields()
3189 def check_valid_bookmark(self):
3191 Check if all neccessary fields are entered correctly
3193 (model, iter_) = self.selection.get_selected()
3195 if not model.iter_parent(iter_):
3196 #Account data can't be changed
3197 return
3199 if self.server_entry.get_text().decode('utf-8') == '' or \
3200 self.room_entry.get_text().decode('utf-8') == '':
3201 dialogs.ErrorDialog(_('This bookmark has invalid data'),
3202 _('Please be sure to fill out server and room fields or remove this'
3203 ' bookmark.'))
3204 return False
3206 return True
3208 def on_ok_button_clicked(self, widget):
3210 Parse the treestore data into our new bookmarks array, then send the new
3211 bookmarks to the server.
3213 (model, iter_) = self.selection.get_selected()
3214 if iter_ and model.iter_parent(iter_):
3215 #bookmark selected, check it
3216 if not self.check_valid_bookmark():
3217 return
3219 for account in self.treestore:
3220 account_unicode = account[1].decode('utf-8')
3221 gajim.connections[account_unicode].bookmarks = []
3223 for bm in account.iterchildren():
3224 #Convert True/False/None to '1' or '0'
3225 autojoin = unicode(int(bm[3]))
3226 minimize = unicode(int(bm[4]))
3228 #create the bookmark-dict
3229 bmdict = { 'name': bm[1], 'jid': bm[2], 'autojoin': autojoin,
3230 'minimize': minimize, 'password': bm[5], 'nick': bm[6],
3231 'print_status': bm[7]}
3233 gajim.connections[account_unicode].bookmarks.append(bmdict)
3235 gajim.connections[account_unicode].store_bookmarks()
3236 gajim.interface.roster.set_actions_menu_needs_rebuild()
3237 self.window.destroy()
3239 def on_cancel_button_clicked(self, widget):
3240 self.window.destroy()
3242 def bookmark_selected(self, selection):
3244 Fill in the bookmark's data into the fields.
3246 (model, iter_) = selection.get_selected()
3248 if not iter_:
3249 # After removing the last bookmark for one account
3250 # this will be None, so we will just:
3251 return
3253 widgets = [ self.title_entry, self.nick_entry, self.room_entry,
3254 self.server_entry, self.pass_entry, self.autojoin_checkbutton,
3255 self.minimize_checkbutton, self.print_status_combobox]
3257 if model.iter_parent(iter_):
3258 # make the fields sensitive
3259 for field in widgets:
3260 field.set_sensitive(True)
3261 else:
3262 # Top-level has no data (it's the account fields)
3263 # clear fields & make them insensitive
3264 self.clear_fields()
3265 for field in widgets:
3266 field.set_sensitive(False)
3267 return
3269 # Fill in the data for childs
3270 self.title_entry.set_text(model[iter_][1])
3271 room_jid = model[iter_][2].decode('utf-8')
3272 (room, server) = room_jid.split('@')
3273 self.room_entry.set_text(room)
3274 self.server_entry.set_text(server)
3276 self.autojoin_checkbutton.set_active(model[iter_][3])
3277 self.minimize_checkbutton.set_active(model[iter_][4])
3278 # sensitive only if auto join is checked
3279 self.minimize_checkbutton.set_sensitive(model[iter_][3])
3281 if model[iter_][5] is not None:
3282 password = model[iter_][5].decode('utf-8')
3283 else:
3284 password = None
3286 if password:
3287 self.pass_entry.set_text(password)
3288 else:
3289 self.pass_entry.set_text('')
3290 nick = model[iter_][6]
3291 if nick:
3292 nick = nick.decode('utf-8')
3293 self.nick_entry.set_text(nick)
3294 else:
3295 self.nick_entry.set_text('')
3297 print_status = model[iter_][7]
3298 opts = sorted(self.option_list.keys())
3299 self.print_status_combobox.set_active(opts.index(print_status))
3301 def on_title_entry_changed(self, widget):
3302 (model, iter_) = self.selection.get_selected()
3303 if iter_: # After removing a bookmark, we got nothing selected
3304 if model.iter_parent(iter_):
3305 # Don't clear the title field for account nodes
3306 model[iter_][1] = self.title_entry.get_text()
3308 def on_nick_entry_changed(self, widget):
3309 (model, iter_) = self.selection.get_selected()
3310 if iter_:
3311 nick = self.nick_entry.get_text().decode('utf-8')
3312 try:
3313 nick = helpers.parse_resource(nick)
3314 except helpers.InvalidFormat, e:
3315 dialogs.ErrorDialog(_('Invalid nickname'),
3316 _('Character not allowed'))
3317 self.nick_entry.set_text(model[iter_][6])
3318 return True
3319 model[iter_][6] = nick
3321 def on_server_entry_changed(self, widget):
3322 (model, iter_) = self.selection.get_selected()
3323 if not iter_:
3324 return
3325 server = widget.get_text().decode('utf-8')
3326 if '@' in server:
3327 dialogs.ErrorDialog(_('Invalid server'), _('Character not allowed'))
3328 widget.set_text(server.replace('@', ''))
3330 room_jid = self.room_entry.get_text().decode('utf-8').strip() + '@' + \
3331 server.strip()
3332 try:
3333 room_jid = helpers.parse_resource(room_jid)
3334 except helpers.InvalidFormat, e:
3335 dialogs.ErrorDialog(_('Invalid server'),
3336 _('Character not allowed'))
3337 self.server_entry.set_text(model[iter_][2].split('@')[1])
3338 return True
3339 model[iter_][2] = room_jid
3341 def on_room_entry_changed(self, widget):
3342 (model, iter_) = self.selection.get_selected()
3343 if not iter_:
3344 return
3345 room = widget.get_text().decode('utf-8')
3346 if '@' in room:
3347 dialogs.ErrorDialog(_('Invalid server'), _('Character not allowed'))
3348 widget.set_text(room.replace('@', ''))
3349 room_jid = self.room_entry.get_text().decode('utf-8').strip() + '@' + \
3350 room.strip()
3351 try:
3352 room_jid = helpers.parse_resource(room_jid)
3353 except helpers.InvalidFormat, e:
3354 dialogs.ErrorDialog(_('Invalid room'),
3355 _('Character not allowed'))
3356 self.room_entry.set_text(model[iter_][2].split('@')[0])
3357 return True
3358 model[iter_][2] = room_jid
3360 def on_pass_entry_changed(self, widget):
3361 (model, iter_) = self.selection.get_selected()
3362 if iter_:
3363 model[iter_][5] = self.pass_entry.get_text()
3365 def on_autojoin_checkbutton_toggled(self, widget):
3366 (model, iter_) = self.selection.get_selected()
3367 if iter_:
3368 model[iter_][3] = self.autojoin_checkbutton.get_active()
3369 self.minimize_checkbutton.set_sensitive(model[iter_][3])
3371 def on_minimize_checkbutton_toggled(self, widget):
3372 (model, iter_) = self.selection.get_selected()
3373 if iter_:
3374 model[iter_][4] = self.minimize_checkbutton.get_active()
3376 def on_print_status_combobox_changed(self, widget):
3377 active = widget.get_active()
3378 model = widget.get_model()
3379 print_status = model[active][1]
3380 (model2, iter_) = self.selection.get_selected()
3381 if iter_:
3382 model2[iter_][7] = print_status
3384 def clear_fields(self):
3385 widgets = [ self.title_entry, self.nick_entry, self.room_entry,
3386 self.server_entry, self.pass_entry ]
3387 for field in widgets:
3388 field.set_text('')
3389 self.autojoin_checkbutton.set_active(False)
3390 self.minimize_checkbutton.set_active(False)
3391 self.print_status_combobox.set_active(1)
3393 class AccountCreationWizardWindow:
3394 def __init__(self):
3395 self.xml = gtkgui_helpers.get_gtk_builder(
3396 'account_creation_wizard_window.ui')
3397 self.window = self.xml.get_object('account_creation_wizard_window')
3398 self.window.set_transient_for(gajim.interface.roster.window)
3400 completion = gtk.EntryCompletion()
3401 completion1 = gtk.EntryCompletion()
3402 # Connect events from comboboxentry.child
3403 server_comboboxentry = self.xml.get_object('server_comboboxentry')
3404 entry = server_comboboxentry.child
3405 entry.connect('key_press_event',
3406 self.on_server_comboboxentry_key_press_event, server_comboboxentry)
3407 entry.set_completion(completion)
3408 # Do the same for the other server comboboxentry
3409 server_comboboxentry1 = self.xml.get_object('server_comboboxentry1')
3410 entry = server_comboboxentry1.child
3411 entry.set_completion(completion1)
3413 self.update_proxy_list()
3415 # parse servers.xml
3416 servers_xml = os.path.join(gajim.DATA_DIR, 'other', 'servers.xml')
3417 servers = gtkgui_helpers.parse_server_xml(servers_xml)
3418 servers_model = gtk.ListStore(str)
3419 for server in servers:
3420 servers_model.append((server,))
3422 completion.set_model(servers_model)
3423 completion.set_text_column(0)
3424 completion1.set_model(servers_model)
3425 completion1.set_text_column(0)
3427 # Put servers into comboboxentries
3428 server_comboboxentry.set_model(servers_model)
3429 server_comboboxentry.set_text_column(0)
3430 server_comboboxentry1.set_model(servers_model)
3431 server_comboboxentry1.set_text_column(0)
3433 # Generic widgets
3434 self.notebook = self.xml.get_object('notebook')
3435 self.cancel_button = self.xml.get_object('cancel_button')
3436 self.back_button = self.xml.get_object('back_button')
3437 self.forward_button = self.xml.get_object('forward_button')
3438 self.finish_button = self.xml.get_object('finish_button')
3439 self.advanced_button = self.xml.get_object('advanced_button')
3440 self.finish_label = self.xml.get_object('finish_label')
3441 self.go_online_checkbutton = self.xml.get_object(
3442 'go_online_checkbutton')
3443 self.show_vcard_checkbutton = self.xml.get_object(
3444 'show_vcard_checkbutton')
3445 self.progressbar = self.xml.get_object('progressbar')
3447 # some vars
3448 self.update_progressbar_timeout_id = None
3450 self.notebook.set_current_page(0)
3451 self.xml.connect_signals(self)
3452 self.window.show_all()
3453 gajim.ged.register_event_handler('new-account-connected', ged.GUI1,
3454 self._nec_new_acc_connected)
3455 gajim.ged.register_event_handler('new-account-not-connected', ged.GUI1,
3456 self._nec_new_acc_not_connected)
3457 gajim.ged.register_event_handler('account-created', ged.GUI1,
3458 self._nec_acc_is_ok)
3459 gajim.ged.register_event_handler('account-not-created', ged.GUI1,
3460 self._nec_acc_is_not_ok)
3462 def on_wizard_window_destroy(self, widget):
3463 page = self.notebook.get_current_page()
3464 if page in (4, 5) and self.account in gajim.connections:
3465 # connection instance is saved in gajim.connections and we canceled
3466 # the addition of the account
3467 del gajim.connections[self.account]
3468 if self.account in gajim.config.get_per('accounts'):
3469 gajim.config.del_per('accounts', self.account)
3470 gajim.ged.remove_event_handler('new-account-connected', ged.GUI1,
3471 self._nec_new_acc_connected)
3472 gajim.ged.remove_event_handler('new-account-not-connected', ged.GUI1,
3473 self._nec_new_acc_not_connected)
3474 gajim.ged.remove_event_handler('account-created', ged.GUI1,
3475 self._nec_acc_is_ok)
3476 gajim.ged.remove_event_handler('account-not-created', ged.GUI1,
3477 self._nec_acc_is_not_ok)
3478 del gajim.interface.instances['account_creation_wizard']
3480 def on_register_server_features_button_clicked(self, widget):
3481 helpers.launch_browser_mailer('url',
3482 'http://www.jabber.org/network/oldnetwork.shtml')
3484 def on_save_password_checkbutton_toggled(self, widget):
3485 self.xml.get_object('password_entry').grab_focus()
3487 def on_cancel_button_clicked(self, widget):
3488 self.window.destroy()
3490 def on_back_button_clicked(self, widget):
3491 cur_page = self.notebook.get_current_page()
3492 if cur_page in (1, 2):
3493 self.notebook.set_current_page(0)
3494 self.back_button.set_sensitive(False)
3495 elif cur_page == 3:
3496 self.xml.get_object('form_vbox').remove(self.data_form_widget)
3497 self.notebook.set_current_page(2) # show server page
3498 elif cur_page == 4:
3499 if self.account in gajim.connections:
3500 del gajim.connections[self.account]
3501 self.notebook.set_current_page(2)
3502 self.xml.get_object('form_vbox').remove(self.data_form_widget)
3503 elif cur_page == 6: # finish page
3504 self.forward_button.show()
3505 if self.modify:
3506 self.notebook.set_current_page(1) # Go to parameters page
3507 else:
3508 self.notebook.set_current_page(2) # Go to server page
3510 def on_anonymous_checkbutton1_toggled(self, widget):
3511 active = widget.get_active()
3512 self.xml.get_object('username_entry').set_sensitive(not active)
3513 self.xml.get_object('password_entry').set_sensitive(not active)
3514 self.xml.get_object('save_password_checkbutton').set_sensitive(
3515 not active)
3517 def show_finish_page(self):
3518 self.cancel_button.hide()
3519 self.back_button.hide()
3520 self.forward_button.hide()
3521 if self.modify:
3522 finish_text = '<big><b>%s</b></big>\n\n%s' % (
3523 _('Account has been added successfully'),
3524 _('You can set advanced account options by pressing the '
3525 'Advanced button, or later by choosing the Accounts menu item '
3526 'under the Edit menu from the main window.'))
3527 else:
3528 finish_text = '<big><b>%s</b></big>\n\n%s' % (
3529 _('Your new account has been created successfully'),
3530 _('You can set advanced account options by pressing the '
3531 'Advanced button, or later by choosing the Accounts menu item '
3532 'under the Edit menu from the main window.'))
3533 self.finish_label.set_markup(finish_text)
3534 self.finish_button.show()
3535 self.finish_button.set_property('has-default', True)
3536 self.advanced_button.show()
3537 self.go_online_checkbutton.show()
3538 img = self.xml.get_object('finish_image')
3539 if self.modify:
3540 img.set_from_stock(gtk.STOCK_APPLY, gtk.ICON_SIZE_DIALOG)
3541 else:
3542 path_to_file = gtkgui_helpers.get_icon_path('gajim', 48)
3543 img.set_from_file(path_to_file)
3544 self.show_vcard_checkbutton.set_active(not self.modify)
3545 self.notebook.set_current_page(6) # show finish page
3547 def on_forward_button_clicked(self, widget):
3548 cur_page = self.notebook.get_current_page()
3550 if cur_page == 0:
3551 widget = self.xml.get_object('use_existing_account_radiobutton')
3552 if widget.get_active():
3553 self.modify = True
3554 self.notebook.set_current_page(1)
3555 else:
3556 self.modify = False
3557 self.notebook.set_current_page(2)
3558 self.back_button.set_sensitive(True)
3559 return
3561 elif cur_page == 1:
3562 # We are adding an existing account
3563 anonymous = self.xml.get_object('anonymous_checkbutton1').\
3564 get_active()
3565 username = self.xml.get_object('username_entry').get_text().decode(
3566 'utf-8').strip()
3567 if not username and not anonymous:
3568 pritext = _('Invalid username')
3569 sectext = _(
3570 'You must provide a username to configure this account.')
3571 dialogs.ErrorDialog(pritext, sectext)
3572 return
3573 server = self.xml.get_object('server_comboboxentry').child.\
3574 get_text().decode('utf-8').strip()
3575 savepass = self.xml.get_object('save_password_checkbutton').\
3576 get_active()
3577 password = self.xml.get_object('password_entry').get_text().decode(
3578 'utf-8')
3580 jid = username + '@' + server
3581 # check if jid is conform to RFC and stringprep it
3582 try:
3583 jid = helpers.parse_jid(jid)
3584 except helpers.InvalidFormat, s:
3585 pritext = _('Invalid Jabber ID')
3586 dialogs.ErrorDialog(pritext, str(s))
3587 return
3589 self.account = server
3590 i = 1
3591 while self.account in gajim.connections:
3592 self.account = server + str(i)
3593 i += 1
3595 username, server = gajim.get_name_and_server_from_jid(jid)
3596 if self.xml.get_object('anonymous_checkbutton1').get_active():
3597 self.save_account('', server, False, '', anonymous=True)
3598 else:
3599 self.save_account(username, server, savepass, password)
3600 self.show_finish_page()
3601 elif cur_page == 2:
3602 # We are creating a new account
3603 server = self.xml.get_object('server_comboboxentry1').child.\
3604 get_text().decode('utf-8')
3606 if not server:
3607 dialogs.ErrorDialog(_('Invalid server'),
3608 _('Please provide a server on which you want to register.'))
3609 return
3610 self.account = server
3611 i = 1
3612 while self.account in gajim.connections:
3613 self.account = server + str(i)
3614 i += 1
3616 config = self.get_config('', server, '', '')
3617 # Get advanced options
3618 proxies_combobox = self.xml.get_object('proxies_combobox')
3619 active = proxies_combobox.get_active()
3620 proxy = proxies_combobox.get_model()[active][0].decode('utf-8')
3621 if proxy == _('None'):
3622 proxy = ''
3623 config['proxy'] = proxy
3625 config['use_custom_host'] = self.xml.get_object(
3626 'custom_host_port_checkbutton').get_active()
3627 custom_port = self.xml.get_object('custom_port_entry').get_text()
3628 try:
3629 custom_port = int(custom_port)
3630 except Exception:
3631 dialogs.ErrorDialog(_('Invalid entry'),
3632 _('Custom port must be a port number.'))
3633 return
3634 config['custom_port'] = custom_port
3635 config['custom_host'] = self.xml.get_object(
3636 'custom_host_entry').get_text().decode('utf-8')
3638 if self.xml.get_object('anonymous_checkbutton2').get_active():
3639 self.modify = True
3640 self.save_account('', server, False, '', anonymous=True)
3641 self.show_finish_page()
3642 else:
3643 self.notebook.set_current_page(5) # show creating page
3644 self.back_button.hide()
3645 self.forward_button.hide()
3646 self.update_progressbar_timeout_id = gobject.timeout_add(100,
3647 self.update_progressbar)
3648 # Get form from serveur
3649 con = connection.Connection(self.account)
3650 gajim.connections[self.account] = con
3651 con.new_account(self.account, config)
3652 elif cur_page == 3:
3653 checked = self.xml.get_object('ssl_checkbutton').get_active()
3654 if checked:
3655 hostname = gajim.connections[self.account].new_account_info[
3656 'hostname']
3657 # Check if cert is already in file
3658 certs = ''
3659 if os.path.isfile(gajim.MY_CACERTS):
3660 f = open(gajim.MY_CACERTS)
3661 certs = f.read()
3662 f.close()
3663 if self.ssl_cert in certs:
3664 dialogs.ErrorDialog(_('Certificate Already in File'),
3665 _('This certificate is already in file %s, so it\'s '
3666 'not added again.') % gajim.MY_CACERTS)
3667 else:
3668 f = open(gajim.MY_CACERTS, 'a')
3669 f.write(hostname + '\n')
3670 f.write(self.ssl_cert + '\n\n')
3671 f.close()
3672 gajim.connections[self.account].new_account_info[
3673 'ssl_fingerprint_sha1'] = self.ssl_fingerprint
3674 self.notebook.set_current_page(4) # show fom page
3675 elif cur_page == 4:
3676 if self.is_form:
3677 form = self.data_form_widget.data_form
3678 else:
3679 form = self.data_form_widget.get_infos()
3680 gajim.connections[self.account].send_new_account_infos(form,
3681 self.is_form)
3682 self.xml.get_object('form_vbox').remove(self.data_form_widget)
3683 self.xml.get_object('progressbar_label').set_markup(
3684 '<b>Account is being created</b>\n\nPlease wait...')
3685 self.notebook.set_current_page(5) # show creating page
3686 self.back_button.hide()
3687 self.forward_button.hide()
3688 self.update_progressbar_timeout_id = gobject.timeout_add(100,
3689 self.update_progressbar)
3691 def update_proxy_list(self):
3692 proxies_combobox = self.xml.get_object('proxies_combobox')
3693 model = gtk.ListStore(str)
3694 proxies_combobox.set_model(model)
3695 l = gajim.config.get_per('proxies')
3696 l.insert(0, _('None'))
3697 for i in xrange(len(l)):
3698 model.append([l[i]])
3699 proxies_combobox.set_active(0)
3701 def on_manage_proxies_button_clicked(self, widget):
3702 if 'manage_proxies' in gajim.interface.instances:
3703 gajim.interface.instances['manage_proxies'].window.present()
3704 else:
3705 gajim.interface.instances['manage_proxies'] = \
3706 ManageProxiesWindow()
3708 def on_custom_host_port_checkbutton_toggled(self, widget):
3709 self.xml.get_object('custom_host_hbox').set_sensitive(widget.\
3710 get_active())
3712 def update_progressbar(self):
3713 self.progressbar.pulse()
3714 return True # loop forever
3716 def _nec_new_acc_connected(self, obj):
3718 Connection to server succeded, present the form to the user
3720 # We receive events from all accounts from GED
3721 if obj.conn.name != self.account:
3722 return
3723 if self.update_progressbar_timeout_id is not None:
3724 gobject.source_remove(self.update_progressbar_timeout_id)
3725 self.back_button.show()
3726 self.forward_button.show()
3727 self.is_form = obj.is_form
3728 if obj.is_form:
3729 dataform = dataforms.ExtendForm(node=obj.config)
3730 self.data_form_widget = dataforms_widget.DataFormWidget(dataform)
3731 else:
3732 self.data_form_widget = FakeDataForm(obj.config)
3733 self.data_form_widget.show_all()
3734 self.xml.get_object('form_vbox').pack_start(self.data_form_widget)
3735 self.ssl_fingerprint = obj.ssl_fingerprint
3736 self.ssl_cert = obj.ssl_cert
3737 if obj.ssl_msg:
3738 # An SSL warning occured, show it
3739 hostname = gajim.connections[self.account].new_account_info[
3740 'hostname']
3741 self.xml.get_object('ssl_label').set_markup(_(
3742 '<b>Security Warning</b>'
3743 '\n\nThe authenticity of the %(hostname)s SSL certificate could'
3744 ' be invalid.\nSSL Error: %(error)s\n'
3745 'Do you still want to connect to this server?') % {
3746 'hostname': hostname, 'error': obj.ssl_msg})
3747 if obj.ssl_err in (18, 27):
3748 text = _('Add this certificate to the list of trusted '
3749 'certificates.\nSHA1 fingerprint of the certificate:\n%s') \
3750 % obj.ssl_fingerprint
3751 self.xml.get_object('ssl_checkbutton').set_label(text)
3752 else:
3753 self.xml.get_object('ssl_checkbutton').set_no_show_all(True)
3754 self.xml.get_object('ssl_checkbutton').hide()
3755 self.notebook.set_current_page(3) # show SSL page
3756 else:
3757 self.notebook.set_current_page(4) # show form page
3759 def _nec_new_acc_not_connected(self, obj):
3761 Account creation failed: connection to server failed
3763 # We receive events from all accounts from GED
3764 if obj.conn.name != self.account:
3765 return
3766 if self.account not in gajim.connections:
3767 return
3768 if self.update_progressbar_timeout_id is not None:
3769 gobject.source_remove(self.update_progressbar_timeout_id)
3770 del gajim.connections[self.account]
3771 if self.account in gajim.config.get_per('accounts'):
3772 gajim.config.del_per('accounts', self.account)
3773 self.back_button.show()
3774 self.cancel_button.show()
3775 self.go_online_checkbutton.hide()
3776 self.show_vcard_checkbutton.hide()
3777 img = self.xml.get_object('finish_image')
3778 img.set_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_DIALOG)
3779 finish_text = '<big><b>%s</b></big>\n\n%s' % (
3780 _('An error occurred during account creation'), obj.reason)
3781 self.finish_label.set_markup(finish_text)
3782 self.notebook.set_current_page(6) # show finish page
3784 def _nec_acc_is_ok(self, obj):
3786 Account creation succeeded
3788 # We receive events from all accounts from GED
3789 if obj.conn.name != self.account:
3790 return
3791 self.create_vars(obj.account_info)
3792 self.show_finish_page()
3794 if self.update_progressbar_timeout_id is not None:
3795 gobject.source_remove(self.update_progressbar_timeout_id)
3797 def _nec_acc_is_not_ok(self, obj):
3799 Account creation failed
3801 # We receive events from all accounts from GED
3802 if obj.conn.name != self.account:
3803 return
3804 self.back_button.show()
3805 self.cancel_button.show()
3806 self.go_online_checkbutton.hide()
3807 self.show_vcard_checkbutton.hide()
3808 del gajim.connections[self.account]
3809 if self.account in gajim.config.get_per('accounts'):
3810 gajim.config.del_per('accounts', self.account)
3811 img = self.xml.get_object('finish_image')
3812 img.set_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_DIALOG)
3813 finish_text = '<big><b>%s</b></big>\n\n%s' % (_(
3814 'An error occurred during account creation'), obj.reason)
3815 self.finish_label.set_markup(finish_text)
3816 self.notebook.set_current_page(6) # show finish page
3818 if self.update_progressbar_timeout_id is not None:
3819 gobject.source_remove(self.update_progressbar_timeout_id)
3821 def on_advanced_button_clicked(self, widget):
3822 if 'accounts' in gajim.interface.instances:
3823 gajim.interface.instances['accounts'].window.present()
3824 else:
3825 gajim.interface.instances['accounts'] = AccountsWindow()
3826 gajim.interface.instances['accounts'].select_account(self.account)
3827 self.window.destroy()
3829 def on_finish_button_clicked(self, widget):
3830 go_online = self.xml.get_object('go_online_checkbutton').get_active()
3831 show_vcard = self.xml.get_object('show_vcard_checkbutton').get_active()
3832 self.window.destroy()
3833 if show_vcard:
3834 gajim.interface.show_vcard_when_connect.append(self.account)
3835 if go_online:
3836 gajim.interface.roster.send_status(self.account, 'online', '')
3838 def on_username_entry_key_press_event(self, widget, event):
3839 # Check for pressed @ and jump to combobox if found
3840 if event.keyval == gtk.keysyms.at:
3841 combobox = self.xml.get_object('server_comboboxentry')
3842 combobox.grab_focus()
3843 combobox.child.set_position(-1)
3844 return True
3846 def on_server_comboboxentry_key_press_event(self, widget, event, combobox):
3847 # If backspace is pressed in empty field, return to the nick entry field
3848 backspace = event.keyval == gtk.keysyms.BackSpace
3849 empty = len(combobox.get_active_text()) == 0
3850 if backspace and empty and self.modify:
3851 username_entry = self.xml.get_object('username_entry')
3852 username_entry.grab_focus()
3853 username_entry.set_position(-1)
3854 return True
3856 def get_config(self, login, server, savepass, password, anonymous=False):
3857 config = {}
3858 config['name'] = login
3859 config['hostname'] = server
3860 config['savepass'] = savepass
3861 config['password'] = password
3862 config['resource'] = 'Gajim'
3863 config['anonymous_auth'] = anonymous
3864 config['priority'] = 5
3865 config['autoconnect'] = True
3866 config['no_log_for'] = ''
3867 config['sync_with_global_status'] = True
3868 config['proxy'] = ''
3869 config['usessl'] = False
3870 config['use_custom_host'] = False
3871 config['custom_port'] = 0
3872 config['custom_host'] = ''
3873 config['keyname'] = ''
3874 config['keyid'] = ''
3875 return config
3877 def save_account(self, login, server, savepass, password, anonymous=False):
3878 if self.account in gajim.connections:
3879 dialogs.ErrorDialog(_('Account name is in use'),
3880 _('You already have an account using this name.'))
3881 return
3882 con = connection.Connection(self.account)
3883 con.password = password
3885 config = self.get_config(login, server, savepass, password, anonymous)
3887 if not self.modify:
3888 con.new_account(self.account, config)
3889 return
3890 gajim.connections[self.account] = con
3891 self.create_vars(config)
3893 def create_vars(self, config):
3894 gajim.config.add_per('accounts', self.account)
3896 if not config['savepass']:
3897 config['password'] = ''
3899 for opt in config:
3900 gajim.config.set_per('accounts', self.account, opt, config[opt])
3902 # update variables
3903 gajim.interface.instances[self.account] = {'infos': {}, 'disco': {},
3904 'gc_config': {}, 'search': {}, 'online_dialog': {}}
3905 gajim.interface.minimized_controls[self.account] = {}
3906 gajim.connections[self.account].connected = 0
3907 gajim.connections[self.account].keepalives = gajim.config.get_per(
3908 'accounts', self.account, 'keep_alive_every_foo_secs')
3909 gajim.groups[self.account] = {}
3910 gajim.contacts.add_account(self.account)
3911 gajim.gc_connected[self.account] = {}
3912 gajim.automatic_rooms[self.account] = {}
3913 gajim.newly_added[self.account] = []
3914 gajim.to_be_removed[self.account] = []
3915 gajim.nicks[self.account] = config['name']
3916 gajim.block_signed_in_notifications[self.account] = True
3917 gajim.sleeper_state[self.account] = 'off'
3918 gajim.encrypted_chats[self.account] = []
3919 gajim.last_message_time[self.account] = {}
3920 gajim.status_before_autoaway[self.account] = ''
3921 gajim.transport_avatar[self.account] = {}
3922 gajim.gajim_optional_features[self.account] = []
3923 gajim.caps_hash[self.account] = ''
3924 # refresh accounts window
3925 if 'accounts' in gajim.interface.instances:
3926 gajim.interface.instances['accounts'].init_accounts()
3927 # refresh roster
3928 if len(gajim.connections) >= 2:
3929 # Do not merge accounts if only one exists
3930 gajim.interface.roster.regroup = gajim.config.get('mergeaccounts')
3931 else:
3932 gajim.interface.roster.regroup = False
3933 gajim.interface.roster.setup_and_draw_roster()
3934 gajim.interface.roster.set_actions_menu_needs_rebuild()
3935 gajim.interface.save_config()
3937 class ManagePEPServicesWindow:
3938 def __init__(self, account):
3939 self.xml = gtkgui_helpers.get_gtk_builder('manage_pep_services_window.ui')
3940 self.window = self.xml.get_object('manage_pep_services_window')
3941 self.window.set_transient_for(gajim.interface.roster.window)
3942 self.xml.get_object('configure_button').set_sensitive(False)
3943 self.xml.get_object('delete_button').set_sensitive(False)
3944 self.xml.connect_signals(self)
3945 self.account = account
3947 self.init_services()
3948 self.xml.get_object('services_treeview').get_selection().connect(
3949 'changed', self.on_services_selection_changed)
3951 gajim.ged.register_event_handler('pep-config-received', ged.GUI1,
3952 self._nec_pep_config_received)
3953 gajim.ged.register_event_handler('agent-items-received', ged.GUI1,
3954 self._nec_agent_items_received)
3956 self.window.show_all()
3958 def on_manage_pep_services_window_destroy(self, widget):
3959 '''close window'''
3960 del gajim.interface.instances[self.account]['pep_services']
3961 gajim.ged.remove_event_handler('pep-config-received', ged.GUI1,
3962 self._nec_pep_config_received)
3963 gajim.ged.remove_event_handler('agent-items-received', ged.GUI1,
3964 self._nec_agent_items_received)
3966 def on_close_button_clicked(self, widget):
3967 self.window.destroy()
3969 def on_services_selection_changed(self, sel):
3970 self.xml.get_object('configure_button').set_sensitive(True)
3971 self.xml.get_object('delete_button').set_sensitive(True)
3973 def init_services(self):
3974 self.treeview = self.xml.get_object('services_treeview')
3975 # service, access_model, group
3976 self.treestore = gtk.ListStore(str)
3977 self.treeview.set_model(self.treestore)
3979 col = gtk.TreeViewColumn('Service')
3980 self.treeview.append_column(col)
3982 cellrenderer_text = gtk.CellRendererText()
3983 col.pack_start(cellrenderer_text)
3984 col.add_attribute(cellrenderer_text, 'text', 0)
3986 our_jid = gajim.get_jid_from_account(self.account)
3987 gajim.connections[self.account].discoverItems(our_jid)
3989 def _nec_agent_items_received(self, obj):
3990 our_jid = gajim.get_jid_from_account(self.account)
3991 for item in obj.items:
3992 if 'jid' in item and item['jid'] == our_jid and 'node' in item:
3993 self.treestore.append([item['node']])
3995 def node_removed(self, jid, node):
3996 if jid != gajim.get_jid_from_account(self.account):
3997 return
3998 model = self.treeview.get_model()
3999 iter_ = model.get_iter_root()
4000 while iter_:
4001 if model[iter_][0] == node:
4002 model.remove(iter_)
4003 break
4004 iter_ = model.iter_next(iter_)
4006 def node_not_removed(self, jid, node, msg):
4007 if jid != gajim.get_jid_from_account(self.account):
4008 return
4009 dialogs.WarningDialog(_('PEP node was not removed'),
4010 _('PEP node %(node)s was not removed: %(message)s') % {'node': node,
4011 'message': msg})
4013 def on_delete_button_clicked(self, widget):
4014 selection = self.treeview.get_selection()
4015 if not selection:
4016 return
4017 model, iter_ = selection.get_selected()
4018 node = model[iter_][0]
4019 our_jid = gajim.get_jid_from_account(self.account)
4020 gajim.connections[self.account].send_pb_delete(our_jid, node,
4021 on_ok=self.node_removed, on_fail=self.node_not_removed)
4023 def on_configure_button_clicked(self, widget):
4024 selection = self.treeview.get_selection()
4025 if not selection:
4026 return
4027 model, iter_ = selection.get_selected()
4028 node = model[iter_][0]
4029 our_jid = gajim.get_jid_from_account(self.account)
4030 gajim.connections[self.account].request_pb_configuration(our_jid, node)
4032 def _nec_pep_config_received(self, obj):
4033 def on_ok(form, node):
4034 form.type = 'submit'
4035 our_jid = gajim.get_jid_from_account(self.account)
4036 gajim.connections[self.account].send_pb_configure(our_jid, node, form)
4037 window = dialogs.DataFormWindow(obj.form, (on_ok, obj.node))
4038 title = _('Configure %s') % obj.node
4039 window.set_title(title)
4040 window.show_all()
4042 class ManageSoundsWindow:
4043 def __init__(self):
4044 self.xml = gtkgui_helpers.get_gtk_builder('manage_sounds_window.ui')
4045 self.window = self.xml.get_object('manage_sounds_window')
4047 # sounds treeview
4048 self.sound_tree = self.xml.get_object('sounds_treeview')
4050 # active, event ui name, path to sound file, event_config_name
4051 model = gtk.ListStore(bool, str, str, str)
4052 self.sound_tree.set_model(model)
4054 col = gtk.TreeViewColumn(_('Active'))
4055 self.sound_tree.append_column(col)
4056 renderer = gtk.CellRendererToggle()
4057 renderer.set_property('activatable', True)
4058 renderer.connect('toggled', self.sound_toggled_cb)
4059 col.pack_start(renderer)
4060 col.set_attributes(renderer, active = 0)
4062 col = gtk.TreeViewColumn(_('Event'))
4063 self.sound_tree.append_column(col)
4064 renderer = gtk.CellRendererText()
4065 col.pack_start(renderer)
4066 col.set_attributes(renderer, text = 1)
4068 self.fill_sound_treeview()
4070 self.xml.connect_signals(self)
4072 self.sound_tree.get_model().connect('row-changed',
4073 self.on_sounds_treemodel_row_changed)
4075 self.window.show_all()
4077 def on_sounds_treemodel_row_changed(self, model, path, iter_):
4078 sound_event = model[iter_][3].decode('utf-8')
4079 gajim.config.set_per('soundevents', sound_event, 'enabled',
4080 bool(model[path][0]))
4081 gajim.config.set_per('soundevents', sound_event, 'path',
4082 model[iter_][2].decode('utf-8'))
4083 gajim.interface.save_config()
4085 def sound_toggled_cb(self, cell, path):
4086 model = self.sound_tree.get_model()
4087 model[path][0] = not model[path][0]
4089 def fill_sound_treeview(self):
4090 model = self.sound_tree.get_model()
4091 model.clear()
4092 model.set_sort_column_id(1, gtk.SORT_ASCENDING)
4094 # NOTE: sounds_ui_names MUST have all items of
4095 # sounds = gajim.config.get_per('soundevents') as keys
4096 sounds_dict = {
4097 'first_message_received': _('First Message Received'),
4098 'next_message_received_focused': _('Next Message Received Focused'),
4099 'next_message_received_unfocused':
4100 _('Next Message Received Unfocused'),
4101 'contact_connected': _('Contact Connected'),
4102 'contact_disconnected': _('Contact Disconnected'),
4103 'message_sent': _('Message Sent'),
4104 'muc_message_highlight': _('Group Chat Message Highlight'),
4105 'muc_message_received': _('Group Chat Message Received'),
4106 'gmail_received': _('GMail Email Received')
4109 for sound_event_config_name, sound_ui_name in sounds_dict.items():
4110 enabled = gajim.config.get_per('soundevents',
4111 sound_event_config_name, 'enabled')
4112 path = gajim.config.get_per('soundevents',
4113 sound_event_config_name, 'path')
4114 model.append((enabled, sound_ui_name, path, sound_event_config_name))
4116 def on_treeview_sounds_cursor_changed(self, widget, data = None):
4117 (model, iter_) = self.sound_tree.get_selection().get_selected()
4118 sounds_entry = self.xml.get_object('sounds_entry')
4119 if not iter_:
4120 sounds_entry.set_text('')
4121 return
4122 path_to_snd_file = model[iter_][2]
4123 sounds_entry.set_text(path_to_snd_file)
4125 def on_browse_for_sounds_button_clicked(self, widget, data = None):
4126 (model, iter_) = self.sound_tree.get_selection().get_selected()
4127 if not iter_:
4128 return
4129 def on_ok(widget, path_to_snd_file):
4130 self.dialog.destroy()
4131 model, iter_ = self.sound_tree.get_selection().get_selected()
4132 if not path_to_snd_file:
4133 model[iter_][2] = ''
4134 self.xml.get_object('sounds_entry').set_text('')
4135 model[iter_][0] = False
4136 return
4137 directory = os.path.dirname(path_to_snd_file)
4138 gajim.config.set('last_sounds_dir', directory)
4139 path_to_snd_file = helpers.strip_soundfile_path(path_to_snd_file)
4140 self.xml.get_object('sounds_entry').set_text(path_to_snd_file)
4142 model[iter_][2] = path_to_snd_file # set new path to sounds_model
4143 model[iter_][0] = True # set the sound to enabled
4145 def on_cancel(widget):
4146 self.dialog.destroy()
4148 path_to_snd_file = model[iter_][2].decode('utf-8')
4149 self.dialog = dialogs.SoundChooserDialog(path_to_snd_file, on_ok,
4150 on_cancel)
4152 def on_sounds_entry_changed(self, widget):
4153 path_to_snd_file = widget.get_text()
4154 model, iter_ = self.sound_tree.get_selection().get_selected()
4155 model[iter_][2] = path_to_snd_file # set new path to sounds_model
4157 def on_play_button_clicked(self, widget):
4158 model, iter_ = self.sound_tree.get_selection().get_selected()
4159 if not iter_:
4160 return
4161 snd_event_config_name = model[iter_][3]
4162 helpers.play_sound(snd_event_config_name)
4164 def on_close_button_clicked(self, widget):
4165 self.window.hide()
4167 def on_manage_sounds_window_delete_event(self, widget, event):
4168 self.window.hide()
4169 return True # do NOT destroy the window