Added OTR support.
Work done by Kjell Braden <fnord@pentabarf.de>. Some fixes done by me.
This commit is contained in:
parent
b04250cf9f
commit
435042968e
|
@ -71,6 +71,50 @@
|
|||
<signal name="activate" handler="_on_toggle_e2e_menuitem_activate"/>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="otr_submenu">
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="label" translatable="yes">Off-the-Record Encryption</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child>
|
||||
<widget class="GtkMenu" id="otr_submenu_menu">
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="otr_settings_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">OTR settings / fingerprint</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="_on_otr_settings_menuitem_activate"/>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="smp_otr_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Authenticate contact</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="_on_smp_otr_menuitem_activate"/>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="start_otr_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Start / Refresh OTR</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="_on_start_otr_menuitem_activate"/>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="end_otr_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="label" translatable="yes">End OTR </property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="_on_end_otr_menuitem_activate"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
|
||||
<property name="visible">True</property>
|
||||
|
|
|
@ -0,0 +1,322 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--Generated with glade3 3.4.2 on Wed Mar 26 13:56:40 2008 -->
|
||||
<glade-interface>
|
||||
<widget class="GtkWindow" id="otr_settings_window">
|
||||
<property name="resizable">False</property>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<widget class="GtkNotebook" id="notebook1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="otr_fp_vbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="our_fp_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Your fingerprint:
|
||||
<span weight="bold" face="monospace">01234567 89ABCDEF 01234567 89ABCDEF 01234567</span></property>
|
||||
<property name="use_markup">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="their_fp_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Purported fingerprint for asdfasdf@xyzxyzxyz.de:
|
||||
<span weight="bold" face="monospace">01234567 89ABCDEF 01234567 89ABCDEF 01234567</span></property>
|
||||
<property name="use_markup">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox1">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<widget class="GtkComboBox" id="verified_combobox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="active">1</property>
|
||||
<property name="items">I have NOT
|
||||
I have</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label5">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0.20000000298023224</property>
|
||||
<property name="label" translatable="yes">verified that the purported fingerprint is in fact the correct fingerprint for that contact.</property>
|
||||
<property name="wrap">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Authentication</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="type">tab</property>
|
||||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkFrame" id="frame2">
|
||||
<property name="visible">True</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">GTK_SHADOW_NONE</property>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="otr_settings_vbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="otr_policy_allow_v1_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">OTR version 1 allowed</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="otr_policy_allow_v2_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">OTR version 2 allowed</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="otr_policy_require_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Encryption required</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="otr_policy_send_tag_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Show others we understand OTR</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="otr_policy_start_on_tag_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Automatically initiate encryption if partner understands OTR</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="otr_policy_start_on_error_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Automatically start OTR when an OTR error occured</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="otr_default_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Use the default settings</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="type">label_item</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">OTR Settings</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="type">tab</property>
|
||||
<property name="position">1</property>
|
||||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHButtonBox" id="hbuttonbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="settings_cancel_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="label" translatable="yes">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="settings_ok_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="has_default">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="label" translatable="yes">gtk-ok</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<widget class="GtkWindow" id="otr_smp_window">
|
||||
<property name="resizable">False</property>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox3">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox4">
|
||||
<property name="visible">True</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="desc_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">label</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="wrap">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="secret_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox3">
|
||||
<property name="visible">True</property>
|
||||
<property name="border_width">5</property>
|
||||
<child>
|
||||
<widget class="GtkProgressBar" id="progressbar">
|
||||
<property name="visible">True</property>
|
||||
<property name="text" translatable="yes"></property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHButtonBox" id="hbuttonbox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="smp_cancel_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="label" translatable="yes">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="smp_ok_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="label" translatable="yes">gtk-ok</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</glade-interface>
|
|
@ -1176,9 +1176,37 @@ class ChatControl(ChatControlBase):
|
|||
self.check_for_possible_inactive_chatstate, None)
|
||||
|
||||
def update_ui(self):
|
||||
if gajim.otr_module:
|
||||
self.update_otr(True)
|
||||
# The name banner is drawn here
|
||||
ChatControlBase.update_ui(self)
|
||||
|
||||
def update_otr(self, print_status=False):
|
||||
# retrieve the OTR context from the chat's contact data
|
||||
ctx = gajim.otr_module.otrl_context_find(gajim.otr_userstates[self.account],
|
||||
self.contact.get_full_jid().encode(),
|
||||
gajim.get_jid_from_account(self.account).encode(), gajim.OTR_PROTO, 1,
|
||||
(gajim.otr_add_appdata, self.account))[0]
|
||||
|
||||
enc_status = False
|
||||
otr_status_text = ""
|
||||
if ctx.msgstate == gajim.otr_module.OTRL_MSGSTATE_ENCRYPTED:
|
||||
enc_status = True
|
||||
if ctx.active_fingerprint.trust:
|
||||
otr_status_text = u"authenticated secure OTR connection"
|
||||
else:
|
||||
otr_status_text = u'*unauthenticated* secure OTR connection'
|
||||
elif ctx.msgstate == gajim.otr_module.OTRL_MSGSTATE_FINISHED:
|
||||
enc_status = True
|
||||
otr_status_text = u"finished OTR connection"
|
||||
else:
|
||||
# nothing to print
|
||||
print_status = False
|
||||
self._show_lock_image(enc_status, u'OTR', enc_status, True)
|
||||
if print_status:
|
||||
self.print_conversation_line(u" [OTR] %s"%otr_status_text, 'status',
|
||||
'', None)
|
||||
|
||||
def _update_banner_state_image(self):
|
||||
contact = gajim.contacts.get_contact_with_highest_priority(self.account,
|
||||
self.contact.jid)
|
||||
|
@ -1696,6 +1724,11 @@ class ChatControl(ChatControlBase):
|
|||
history_menuitem = xml.get_widget('history_menuitem')
|
||||
toggle_gpg_menuitem = xml.get_widget('toggle_gpg_menuitem')
|
||||
toggle_e2e_menuitem = xml.get_widget('toggle_e2e_menuitem')
|
||||
otr_submenu = xml.get_widget('otr_submenu')
|
||||
otr_settings_menuitem = xml.get_widget('otr_settings_menuitem')
|
||||
smp_otr_menuitem = xml.get_widget('smp_otr_menuitem')
|
||||
start_otr_menuitem = xml.get_widget('start_otr_menuitem')
|
||||
end_otr_menuitem = xml.get_widget('end_otr_menuitem')
|
||||
add_to_roster_menuitem = xml.get_widget('add_to_roster_menuitem')
|
||||
send_file_menuitem = xml.get_widget('send_file_menuitem')
|
||||
information_menuitem = xml.get_widget('information_menuitem')
|
||||
|
@ -1781,6 +1814,33 @@ class ChatControl(ChatControlBase):
|
|||
id = convert_to_gc_menuitem.connect('activate',
|
||||
self._on_convert_to_gc_menuitem_activate)
|
||||
self.handlers[id] = convert_to_gc_menuitem
|
||||
|
||||
if gajim.otr_module:
|
||||
otr_submenu.show()
|
||||
id = otr_settings_menuitem.connect('activate',
|
||||
self._on_otr_settings_menuitem_activate)
|
||||
self.handlers[id] = otr_settings_menuitem
|
||||
id = start_otr_menuitem.connect('activate',
|
||||
self._on_start_otr_menuitem_activate)
|
||||
self.handlers[id] = start_otr_menuitem
|
||||
id = end_otr_menuitem.connect('activate',
|
||||
self._on_end_otr_menuitem_activate)
|
||||
self.handlers[id] = end_otr_menuitem
|
||||
id = smp_otr_menuitem.connect('activate',
|
||||
self._on_smp_otr_menuitem_activate)
|
||||
self.handlers[id] = smp_otr_menuitem
|
||||
|
||||
ctx = gajim.otr_module.otrl_context_find(gajim.otr_userstates[self.account],
|
||||
self.contact.get_full_jid().encode(),
|
||||
gajim.get_jid_from_account(self.account).encode(), gajim.OTR_PROTO, 1,
|
||||
(gajim.otr_add_appdata, self.account))[0]
|
||||
# can end only when PLAINTEXT
|
||||
end_otr_menuitem.set_sensitive(ctx.msgstate !=
|
||||
gajim.otr_module.OTRL_MSGSTATE_PLAINTEXT)
|
||||
# can SMP only when ENCRYPTED
|
||||
smp_otr_menuitem.set_sensitive(ctx.msgstate ==
|
||||
gajim.otr_module.OTRL_MSGSTATE_ENCRYPTED)
|
||||
|
||||
menu.connect('selection-done', self.destroy_menu, history_menuitem,
|
||||
information_menuitem)
|
||||
return menu
|
||||
|
@ -2259,6 +2319,27 @@ class ChatControl(ChatControlBase):
|
|||
# XXX decide whether to use 4 or 3 message negotiation
|
||||
self.session.negotiate_e2e(False)
|
||||
|
||||
def _on_start_otr_menuitem_activate(self, widget):
|
||||
# ?OTR? gets replaced with a better message internally in otrl_message_sending
|
||||
MessageControl.send_message(self, u"?OTR?", type="chat")
|
||||
def _on_end_otr_menuitem_activate(self, widget):
|
||||
fjid = self.contact.get_full_jid()
|
||||
gajim.otr_module.otrl_message_disconnect(gajim.otr_userstates[self.account],
|
||||
(gajim.otr_ui_ops, {'account':self.account,'urgent':True}),
|
||||
gajim.get_jid_from_account(self.account).encode(), gajim.OTR_PROTO,
|
||||
fjid.encode())
|
||||
gajim.otr_ui_ops.gajim_log("Private conversation with %s lost."%fjid,
|
||||
self.account, fjid.encode())
|
||||
self.update_ui()
|
||||
def _on_otr_settings_menuitem_activate(self, widget):
|
||||
gajim.otr_windows.ContactOtrWindow(self.contact, self.account, self)
|
||||
def _on_smp_otr_menuitem_activate(self, widget):
|
||||
ctx = gajim.otr_module.otrl_context_find(gajim.otr_userstates[self.account],
|
||||
self.contact.get_full_jid().encode(),
|
||||
gajim.get_jid_from_account(self.account).encode(), gajim.OTR_PROTO, 1,
|
||||
(gajim.otr_add_appdata, self.account))[0]
|
||||
ctx.app_data.show(False)
|
||||
|
||||
def got_connected(self):
|
||||
ChatControlBase.got_connected(self)
|
||||
# Refreshing contact
|
||||
|
|
|
@ -319,6 +319,7 @@ class Config:
|
|||
'zeroconf_jabber_id': [ opt_str, '', '', True ],
|
||||
'zeroconf_email': [ opt_str, '', '', True ],
|
||||
'use_env_http_proxy' : [opt_bool, False],
|
||||
'otr_flags': [opt_int, 59 ],
|
||||
}, {}),
|
||||
'statusmsg': ({
|
||||
'message': [ opt_str, '' ],
|
||||
|
@ -369,6 +370,7 @@ class Config:
|
|||
'contacts': ({
|
||||
'gpg_enabled': [ opt_bool, False, _('Is OpenPGP enabled for this contact?')],
|
||||
'speller_language': [ opt_str, '', _('Language for which we want to check misspelled words')],
|
||||
'otr_flags': [opt_int, -1 ],
|
||||
}, {}),
|
||||
'rooms': ({
|
||||
'speller_language': [ opt_str, '', _('Language for which we want to check misspelled words')],
|
||||
|
|
|
@ -1024,7 +1024,7 @@ class Connection(ConnectionHandlers):
|
|||
|
||||
def send_message(self, jid, msg, keyID, type='chat', subject='',
|
||||
chatstate=None, msg_id=None, composing_xep=None, resource=None,
|
||||
user_nick=None, xhtml=None, session=None, forward_from=None, form_node=None):
|
||||
user_nick=None, xhtml=None, session=None, forward_from=None, form_node=None, original_message=None):
|
||||
if not self.connection:
|
||||
return 1
|
||||
if msg and not xhtml and gajim.config.get('rst_formatting_outgoing_messages'):
|
||||
|
@ -1116,13 +1116,16 @@ class Connection(ConnectionHandlers):
|
|||
if session.enable_encryption:
|
||||
msg_iq = session.encrypt_stanza(msg_iq)
|
||||
|
||||
|
||||
self.connection.send(msg_iq)
|
||||
if not forward_from and session.is_loggable():
|
||||
if not forward_from and session and session.is_loggable():
|
||||
no_log_for = gajim.config.get_per('accounts', self.name, 'no_log_for')\
|
||||
.split()
|
||||
ji = gajim.get_jid_without_resource(jid)
|
||||
if self.name not in no_log_for and ji not in no_log_for:
|
||||
log_msg = msg
|
||||
if original_message != None:
|
||||
log_msg = original_message
|
||||
if subject:
|
||||
log_msg = _('Subject: %s\n%s') % (subject, msg)
|
||||
if log_msg:
|
||||
|
|
|
@ -1677,6 +1677,34 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
self.dispatch('ERROR', (_('Disk Write Error'), str(e)))
|
||||
return
|
||||
elif mtype == 'chat': # it's type 'chat'
|
||||
|
||||
if gajim.otr_module and isinstance(msgtxt, unicode):
|
||||
otr_msg_tuple = gajim.otr_module.otrl_message_receiving(
|
||||
gajim.otr_userstates[self.name],
|
||||
(gajim.otr_ui_ops, {'account':self.name}),
|
||||
gajim.get_jid_from_account(self.name).encode(),
|
||||
gajim.OTR_PROTO, frm.encode(), msgtxt.encode(),
|
||||
(gajim.otr_add_appdata, self.name))
|
||||
msgtxt = unicode(otr_msg_tuple[1])
|
||||
# OTR messages are unformatted, or rather contain the same
|
||||
# text in <body> and <html>
|
||||
msghtml = msgtxt
|
||||
|
||||
if gajim.otr_module.otrl_tlv_find(otr_msg_tuple[2],
|
||||
gajim.otr_module.OTRL_TLV_DISCONNECTED) != None:
|
||||
gajim.otr_ui_ops.gajim_log("%s has ended his/her private conversation"
|
||||
" with you; you should do the same."%frm, self.name,
|
||||
frm)
|
||||
ctrl = gajim.interface.msg_win_mgr.get_control(frm, self.name)
|
||||
if ctrl:
|
||||
ctrl.update_ui()
|
||||
|
||||
ctx = gajim.otr_module.otrl_context_find(gajim.otr_userstates[self.name], frm.encode(),
|
||||
gajim.get_jid_from_account(self.name).encode(), gajim.OTR_PROTO, 1,
|
||||
(gajim.otr_add_appdata, self.name))[0]
|
||||
tlvs = otr_msg_tuple[2]
|
||||
ctx.app_data.handle_tlv(tlvs)
|
||||
|
||||
if not msg.getTag('body') and chatstate is None: #no <body>
|
||||
return
|
||||
if msg.getTag('body') and session.is_loggable() and msgtxt:
|
||||
|
|
|
@ -165,6 +165,10 @@ else:
|
|||
if system('gpg -h >/dev/null 2>&1'):
|
||||
HAVE_GPG = False
|
||||
|
||||
OTR_PROTO = "xmpp"
|
||||
otr_userstates = {}
|
||||
otr_policy = {}
|
||||
|
||||
gajim_identity = {'type': 'pc', 'category': 'client', 'name': 'Gajim'}
|
||||
gajim_common_features = [xmpp.NS_BYTESTREAM, xmpp.NS_SI,
|
||||
xmpp.NS_FILE, xmpp.NS_MUC, xmpp.NS_MUC_USER,
|
||||
|
|
185
src/gajim.py
185
src/gajim.py
|
@ -253,6 +253,172 @@ from common import helpers
|
|||
from common import optparser
|
||||
from common import dataforms
|
||||
|
||||
from common.xmpp import Message as XmppMessage
|
||||
|
||||
try:
|
||||
import otr, otr_windows
|
||||
|
||||
gajim.otr_module = otr
|
||||
gajim.otr_windows = otr_windows
|
||||
except ImportError:
|
||||
gajim.otr_module = None
|
||||
gajim.otr_windows = None
|
||||
|
||||
def add_appdata(data=None, context=None):
|
||||
account = data
|
||||
context.app_data = otr_windows.ContactOtrSMPWindow(unicode(context.username),
|
||||
account)
|
||||
|
||||
gajim.otr_add_appdata = add_appdata
|
||||
|
||||
|
||||
def otr_dialog_destroy(widget, *args, **kwargs):
|
||||
widget.destroy()
|
||||
|
||||
class OtrlMessageAppOps:
|
||||
|
||||
def gajim_log(self, msg, account, fjid, no_print=False):
|
||||
if not isinstance(fjid, unicode):
|
||||
fjid = unicode(fjid)
|
||||
if not isinstance(account, unicode):
|
||||
account = unicode(account)
|
||||
resource=gajim.get_resource_from_jid(fjid)
|
||||
tim = time.localtime()
|
||||
|
||||
if not no_print:
|
||||
ctrl = gajim.interface.msg_win_mgr.get_control(
|
||||
gajim.get_jid_without_resource(fjid), account)
|
||||
if ctrl:
|
||||
ctrl.print_conversation_line(u" [OTR] %s"%msg, 'status', '', None)
|
||||
id = gajim.logger.write('chat_msg_recv', fjid, message=msg, tim=tim)
|
||||
gajim.logger.set_read_messages([id])
|
||||
|
||||
def policy(self, opdata=None, context=None):
|
||||
policy = gajim.config.get_per("contacts",
|
||||
gajim.get_jid_without_resource(context.username), "otr_flags")
|
||||
if policy <= 0:
|
||||
policy = gajim.config.get_per("accounts", opdata['account'], "otr_flags")
|
||||
return policy
|
||||
|
||||
def create_privkey(self, opdata="", accountname="", protocol=""):
|
||||
dialog = gtk.Dialog(title=_("Generating..."), parent=gajim.interface.roster.window,
|
||||
flags=gtk.DIALOG_MODAL, buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
|
||||
permlabel = gtk.Label("Generating a private key for %s..."%accountname)
|
||||
permlabel.set_padding(20,20)
|
||||
dialog.set_response_sensitive(gtk.RESPONSE_CLOSE, False)
|
||||
dialog.connect("destroy", otr_dialog_destroy)
|
||||
dialog.connect("response", otr_dialog_destroy)
|
||||
dialog.vbox.pack_start(permlabel)
|
||||
dialog.get_root_window().raise_()
|
||||
dialog.show_all()
|
||||
dialog.map()
|
||||
for c in dialog.get_children():
|
||||
c.show_now()
|
||||
c.map()
|
||||
|
||||
while gtk.events_pending():
|
||||
gtk.main_iteration(block=False)
|
||||
|
||||
otr.otrl_privkey_generate(gajim.otr_userstates[opdata['account']],
|
||||
os.path.join(gajimpaths.root, "%s.key"%opdata['account']).encode(),
|
||||
accountname, gajim.OTR_PROTO)
|
||||
permlabel.set_text("Generating a private key for %s...\ndone."%accountname)
|
||||
dialog.set_response_sensitive(gtk.RESPONSE_CLOSE, True)
|
||||
|
||||
def is_logged_in(self, opdata={}, accountname="", protocol="", recipient=""):
|
||||
return gajim.contacts.get_contact_from_full_jid(opdata['account'], recipient).show \
|
||||
in ['dnd', 'xa', 'chat', 'online', 'away', 'invisible']
|
||||
|
||||
def inject_message(self, opdata=None, accountname="", protocol="", recipient="",
|
||||
message=""):
|
||||
msg_type = otr.otrl_proto_message_type(message)
|
||||
|
||||
if 'kwargs' not in opdata or 'urgent' in opdata:
|
||||
# don't use send_message here to have the message sent immediatly.
|
||||
# this results in being able to disconnect from OTR sessions before
|
||||
# quitting
|
||||
stanza = XmppMessage(to=recipient, body=message, typ="chat")
|
||||
gajim.connections[opdata['account']].connection.send(stanza, now=True)
|
||||
return
|
||||
|
||||
if msg_type == otr.OTRL_MSGTYPE_QUERY:
|
||||
# split away XHTML-contaminated explanatory message
|
||||
message = unicode(message.splitlines()[0])
|
||||
message += u"\n%s has requested an Off-the-Record private " \
|
||||
"conversation. However, you do not have a plugin to " \
|
||||
"support that.\nSee http://otr.cypherpunks.ca/ for more "\
|
||||
"information."%gajim.get_jid_from_account(opdata['account'])
|
||||
|
||||
gajim.connections[opdata['account']].send_message(recipient, message,
|
||||
**opdata['kwargs'])
|
||||
|
||||
def notify(sef, opdata=None, username="", **kwargs):
|
||||
self.gajim_log("Notify: "+str(kwargs), opdata['account'], username)
|
||||
|
||||
def display_otr_message(self, opdata=None, username="", msg="", **kwargs):
|
||||
self.gajim_log("OTR Message: "+msg, opdata['account'], username)
|
||||
return 0
|
||||
|
||||
def update_context_list(self, **kwargs):
|
||||
# FIXME stub FIXME #
|
||||
pass
|
||||
|
||||
def protocol_name(self, opdata=None, protocol=""):
|
||||
return "XMPP"
|
||||
|
||||
def new_fingerprint(self, opdata=None, username="", fingerprint="", **kwargs):
|
||||
self.gajim_log("New fingerprint for %s: %s"%(username,
|
||||
otr.otrl_privkey_hash_to_human(fingerprint)), opdata['account'], username)
|
||||
|
||||
def write_fingerprints(self, opdata=""):
|
||||
otr.otrl_privkey_write_fingerprints(gajim.otr_userstates[opdata['account']],
|
||||
os.path.join(gajimpaths.root, "%s.fpr"%opdata['account']).encode())
|
||||
|
||||
def gone_secure(self, opdata="", context=None):
|
||||
trust = context.active_fingerprint.trust
|
||||
if trust:
|
||||
trust = "verified"
|
||||
else:
|
||||
trust = "unverified"
|
||||
self.gajim_log("%s secured OTR connection started"%trust,
|
||||
opdata['account'], context.username, no_print=True)
|
||||
|
||||
ctrl = gajim.interface.msg_win_mgr.get_control(
|
||||
gajim.get_jid_without_resource(unicode(context.username)),
|
||||
opdata['account'])
|
||||
if ctrl:
|
||||
ctrl.update_otr(True)
|
||||
|
||||
def gone_insecure(self, opdata="", context=None):
|
||||
self.gajim_log("Private conversation with %s lost.", opdata['account'], context.username)
|
||||
|
||||
ctrl = gajim.interface.msg_win_mgr.get_control(
|
||||
gajim.get_jid_without_resource(unicode(context.username)),
|
||||
opdata['account'])
|
||||
if ctrl:
|
||||
ctrl.update_otr()
|
||||
|
||||
def still_secure(self, opdata=None, context=None, is_reply=0):
|
||||
ctrl = gajim.interface.msg_win_mgr.get_control(
|
||||
gajim.get_jid_without_resource(unicode(context.username)),
|
||||
opdata['account'])
|
||||
if ctrl:
|
||||
ctrl.update_otr(True)
|
||||
|
||||
self.gajim_log("OTR connection was refreshed", opdata['account'],
|
||||
context.username)
|
||||
|
||||
def log_message(self, opdata=None, message=""):
|
||||
gajim.log.debug(message)
|
||||
|
||||
def max_message_size(self, **kwargs):
|
||||
return 0
|
||||
|
||||
def account_name(self, opdata=None, account="",protocol=""):
|
||||
return gajim.get_name_from_jid(opdata['account'], unicode(account))
|
||||
|
||||
gajim.otr_ui_ops = OtrlMessageAppOps()
|
||||
|
||||
if verbose: gajim.verbose = True
|
||||
del verbose
|
||||
|
||||
|
@ -3160,6 +3326,25 @@ class Interface:
|
|||
gajim.status_before_autoaway[a] = ''
|
||||
gajim.transport_avatar[a] = {}
|
||||
|
||||
if gajim.otr_module:
|
||||
gajim.otr_userstates[a] = otr.otrl_userstate_create()
|
||||
try:
|
||||
otr.otrl_privkey_read(gajim.otr_userstates[a],
|
||||
os.path.join(gajimpaths.root, "%s.key"%a).encode())
|
||||
except Exception, e:
|
||||
if hasattr(e,"os_errno") and e.os_errno == 2:
|
||||
print "didn't find otr keyfile "+ \
|
||||
(os.path.join(gajimpaths.root, "%s.key"%a).encode())
|
||||
pass
|
||||
try:
|
||||
otr.otrl_privkey_read_fingerprints(gajim.otr_userstates[a],
|
||||
os.path.join(gajimpaths.root, "%s.fpr"%a).encode(), (add_appdata, a))
|
||||
except Exception, e:
|
||||
if hasattr(e,"os_errno") and e.os_errno == 2:
|
||||
print "didn't find otr fingerprint file "+ \
|
||||
(os.path.join(gajimpaths.root, "%s.fpr"%a).encode())
|
||||
pass
|
||||
|
||||
if gajim.config.get('remote_control'):
|
||||
try:
|
||||
import remote_control
|
||||
|
|
|
@ -143,6 +143,7 @@ class MessageControl:
|
|||
'''Send the given message to the active tab. Doesn't return None if error
|
||||
'''
|
||||
jid = self.contact.jid
|
||||
original_message = message
|
||||
|
||||
if not self.session:
|
||||
fjid = self.contact.get_full_jid()
|
||||
|
@ -150,8 +151,36 @@ class MessageControl:
|
|||
|
||||
self.set_session(new_session)
|
||||
|
||||
if gajim.otr_module:
|
||||
if type == 'chat' and isinstance(message, unicode):
|
||||
d = {'kwargs':{'keyID':keyID, 'type':type,
|
||||
'chatstate':chatstate, 'msg_id':msg_id,
|
||||
'composing_xep':composing_xep, 'resource':self.resource,
|
||||
'user_nick':user_nick, 'session':self.session,
|
||||
'original_message':original_message}, 'account':self.account}
|
||||
|
||||
new_msg = gajim.otr_module.otrl_message_sending(
|
||||
gajim.otr_userstates[self.account],
|
||||
(gajim.otr_ui_ops, d),
|
||||
gajim.get_jid_from_account(self.account).encode(), gajim.OTR_PROTO,
|
||||
self.contact.get_full_jid().encode(), message.encode(), None)
|
||||
|
||||
context = gajim.otr_module.otrl_context_find(
|
||||
gajim.otr_userstates[self.account],
|
||||
self.contact.get_full_jid().encode(),
|
||||
gajim.get_jid_from_account(self.account).encode(),
|
||||
gajim.OTR_PROTO, 1)[0]
|
||||
|
||||
print repr(context.accountname), repr(context.username)
|
||||
|
||||
# we send all because inject_message can filter on HTML stuff then
|
||||
gajim.otr_module.otrl_message_fragment_and_send(
|
||||
(gajim.otr_ui_ops, d),
|
||||
context, new_msg, gajim.otr_module.OTRL_FRAGMENT_SEND_ALL)
|
||||
return
|
||||
|
||||
# Send and update history
|
||||
return gajim.connections[self.account].send_message(jid, message, keyID,
|
||||
type = type, chatstate = chatstate, msg_id = msg_id,
|
||||
composing_xep = composing_xep, resource = self.resource,
|
||||
user_nick = user_nick, session = self.session)
|
||||
user_nick = user_nick, session = self.session, original_message = original_message)
|
||||
|
|
|
@ -0,0 +1,301 @@
|
|||
#!/usr/bin/env python
|
||||
## otr_windows.py
|
||||
##
|
||||
##
|
||||
## Copyright (C) 2008 Kjell Braden <fnord@pentabarf.de>
|
||||
##
|
||||
## This file is part of Gajim.
|
||||
##
|
||||
## Gajim is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published
|
||||
## by the Free Software Foundation; version 3 only.
|
||||
##
|
||||
## Gajim is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
##
|
||||
|
||||
import gtkgui_helpers
|
||||
from common import gajim
|
||||
|
||||
our_fp_text = """Your fingerprint:
|
||||
<span weight="bold" face="monospace">%s</span>"""
|
||||
|
||||
their_fp_text = """Purported fingerprint for %s:
|
||||
<span weight="bold" face="monospace">%s</span>"""
|
||||
|
||||
class ContactOtrSMPWindow:
|
||||
|
||||
def gw(self, n):
|
||||
""" shorthand for self.xml.get_widget(n)"""
|
||||
return self.xml.get_widget(n)
|
||||
|
||||
def __init__(self, fjid, account):
|
||||
self.fjid = fjid
|
||||
self.account = account
|
||||
|
||||
self.xml = gtkgui_helpers.get_glade("contact_otr_window.glade")
|
||||
self.window = self.xml.get_widget("otr_smp_window")
|
||||
|
||||
|
||||
# the contact may be unknown to gajim if ContactOtrSMPWindow is created very early
|
||||
self.contact = gajim.contacts.get_contact_from_full_jid(account, fjid)
|
||||
if self.contact:
|
||||
self.window.set_title("OTR settings for %s"%
|
||||
self.contact.get_full_jid())
|
||||
|
||||
self.ctx = gajim.otr_module.otrl_context_find(
|
||||
gajim.otr_userstates[self.account],
|
||||
self.fjid.encode(), gajim.get_jid_from_account(self.account).encode(),
|
||||
gajim.OTR_PROTO, 1, (gajim.otr_add_appdata, self.account))[0]
|
||||
|
||||
self.gw("smp_cancel_button").connect("clicked", self._on_destroy)
|
||||
self.gw("smp_ok_button").connect("clicked", self._apply)
|
||||
|
||||
def show(self, response):
|
||||
# re-initialize if contact was unknown when we initially initialized
|
||||
if not self.contact:
|
||||
self.__init__(self.fjid, self.account)
|
||||
assert(self.contact) # the contact MUST be known when showing the dialog
|
||||
|
||||
self.smp_running = False
|
||||
self.finished = False
|
||||
|
||||
self.response = response
|
||||
if response:
|
||||
self.gw("desc_label").set_markup("<b>%s is trying to authenticate you "
|
||||
"using a secret only known to him/her and you.</b> Please enter your secret "
|
||||
"below."% self.contact.get_full_jid())
|
||||
else:
|
||||
self.gw("desc_label").set_markup("<b>You are trying to authenticate %s "
|
||||
"using a secret only known to him/her and yourself.</b> Please enter your "
|
||||
"secret below."% self.contact.get_full_jid())
|
||||
|
||||
self.window.show_all()
|
||||
|
||||
def _abort(self, text=None):
|
||||
self.smp_running = False
|
||||
gajim.otr_module.otrl_message_abort_smp(gajim.otr_userstates[self.account],
|
||||
(gajim.otr_ui_ops, {'account':self.account}), self.ctx)
|
||||
if text:
|
||||
gajim.otr_ui_ops.gajim_log(text, self.account, self.contact.get_full_jid())
|
||||
|
||||
def _finish(self, text):
|
||||
self.smp_running = False
|
||||
self.finished = True
|
||||
self.gw("smp_cancel_button").set_sensitive(False)
|
||||
self.gw("smp_ok_button").set_sensitive(True)
|
||||
self.gw("progressbar").set_fraction(1)
|
||||
gajim.otr_ui_ops.gajim_log(text, self.account, self.contact.get_full_jid())
|
||||
self.gw("desc_label").set_markup(text)
|
||||
ctrl = gajim.interface.msg_win_mgr.get_control(self.contact.jid, self.account)
|
||||
if ctrl:
|
||||
ctrl.update_ui()
|
||||
gajim.otr_ui_ops.write_fingerprints({'account':self.account})
|
||||
|
||||
def handle_tlv(self, tlvs):
|
||||
if not self.contact:
|
||||
self.__init__(self.fjid, self.account)
|
||||
|
||||
if tlvs:
|
||||
nextTLV = self.ctx.smstate.nextExpected;
|
||||
tlv = gajim.otr_module.otrl_tlv_find(tlvs, gajim.otr_module.OTRL_TLV_SMP1)
|
||||
if tlv:
|
||||
if nextTLV != gajim.otr_module.OTRL_SMP_EXPECT1:
|
||||
self._abort()
|
||||
else:
|
||||
self.show(True)
|
||||
self.gw("progressbar").set_fraction(0.3)
|
||||
tlv = gajim.otr_module.otrl_tlv_find(tlvs, gajim.otr_module.OTRL_TLV_SMP2)
|
||||
if tlv:
|
||||
if nextTLV != gajim.otr_module.OTRL_SMP_EXPECT2:
|
||||
self._abort()
|
||||
else:
|
||||
self.ctx.smstate.nextExpected = gajim.otr_module.OTRL_SMP_EXPECT4;
|
||||
self.gw("progressbar").set_fraction(0.6)
|
||||
tlv = gajim.otr_module.otrl_tlv_find(tlvs, gajim.otr_module.OTRL_TLV_SMP3)
|
||||
if tlv:
|
||||
if nextTLV != gajim.otr_module.OTRL_SMP_EXPECT3:
|
||||
self._abort()
|
||||
else:
|
||||
self.ctx.smstate.nextExpected = gajim.otr_module.OTRL_SMP_EXPECT1;
|
||||
if self.ctx.active_fingerprint.trust:
|
||||
self._finish("SMP verifying succeeded")
|
||||
else:
|
||||
self._finish("SMP verifying failed")
|
||||
tlv = gajim.otr_module.otrl_tlv_find(tlvs, gajim.otr_module.OTRL_TLV_SMP4)
|
||||
if tlv:
|
||||
if nextTLV != gajim.otr_module.OTRL_SMP_EXPECT4:
|
||||
self._abort()
|
||||
else:
|
||||
self.ctx.smstate.nextExpected = gajim.otr_module.OTRL_SMP_EXPECT1;
|
||||
if self.ctx.active_fingerprint.trust:
|
||||
self._finish("SMP verifying succeeded")
|
||||
else:
|
||||
self._finish("SMP verifying failed")
|
||||
tlv = gajim.otr_module.otrl_tlv_find(tlvs, gajim.otr_module.OTRL_TLV_SMP_ABORT)
|
||||
if tlv:
|
||||
self._finish("SMP verifying aborted")
|
||||
|
||||
def _on_destroy(self, widget):
|
||||
if self.smp_running:
|
||||
self._abort("user aborted SMP authentication")
|
||||
self.window.hide_all()
|
||||
|
||||
def _apply(self, widget):
|
||||
if self.finished:
|
||||
self.window.hide_all()
|
||||
return
|
||||
secret = self.gw("secret_entry").get_text()
|
||||
if self.response:
|
||||
gajim.otr_module.otrl_message_respond_smp(gajim.otr_userstates[self.account],
|
||||
(gajim.otr_ui_ops, {'account':self.account}), self.ctx, secret)
|
||||
else:
|
||||
gajim.otr_module.otrl_message_initiate_smp(gajim.otr_userstates[self.account],
|
||||
(gajim.otr_ui_ops, {'account':self.account}), self.ctx, secret)
|
||||
self.gw("progressbar").set_fraction(0.3)
|
||||
self.smp_running = True
|
||||
widget.set_sensitive(False)
|
||||
|
||||
|
||||
class ContactOtrWindow:
|
||||
|
||||
def gw(self, n):
|
||||
""" shorthand for self.xml.get_widget(n)"""
|
||||
return self.xml.get_widget(n)
|
||||
|
||||
def __init__(self, contact, account, ctrl=None):
|
||||
self.contact = contact
|
||||
self.account = account
|
||||
self.ctrl = ctrl
|
||||
|
||||
self.ctx = gajim.otr_module.otrl_context_find(
|
||||
gajim.otr_userstates[self.account],
|
||||
self.contact.get_full_jid().encode(),
|
||||
gajim.get_jid_from_account(self.account).encode(),
|
||||
gajim.OTR_PROTO, 1, (gajim.otr_add_appdata, self.account))[0]
|
||||
|
||||
self.xml = gtkgui_helpers.get_glade("contact_otr_window.glade")
|
||||
self.window = self.xml.get_widget("otr_settings_window")
|
||||
|
||||
self.gw("settings_cancel_button").connect("clicked", self._on_destroy)
|
||||
self.gw("settings_ok_button").connect("clicked", self._apply)
|
||||
self.gw("otr_default_checkbutton").connect("toggled",
|
||||
self._otr_default_checkbutton_toggled)
|
||||
|
||||
self.window.set_title("OTR settings for %s"%
|
||||
self.contact.get_full_jid())
|
||||
|
||||
# always set the label containing our fingerprint
|
||||
self.gw("our_fp_label").set_markup(our_fp_text%
|
||||
gajim.otr_module.otrl_privkey_fingerprint(
|
||||
gajim.otr_userstates[self.account],
|
||||
gajim.get_jid_from_account(self.account).encode(),
|
||||
gajim.OTR_PROTO))
|
||||
|
||||
if self.ctx.msgstate != gajim.otr_module.OTRL_MSGSTATE_ENCRYPTED:
|
||||
# make the fingerprint widgets insensitive when not encrypted
|
||||
for widget in self.gw("otr_fp_vbox").get_children():
|
||||
widget.set_sensitive(False)
|
||||
# show that the fingerprint is unknown
|
||||
self.gw("their_fp_label").set_markup(
|
||||
their_fp_text%(self.contact.get_full_jid(),
|
||||
"unknown"))
|
||||
self.gw("verified_combobox").set_active(-1)
|
||||
else:
|
||||
# make the fingerprint widgets sensitive when encrypted
|
||||
for widget in self.gw("otr_fp_vbox").get_children():
|
||||
widget.set_sensitive(True)
|
||||
# show their fingerprint
|
||||
self.gw("their_fp_label").set_markup(
|
||||
their_fp_text%(self.contact.get_full_jid(),
|
||||
gajim.otr_module.otrl_privkey_hash_to_human(
|
||||
self.ctx.active_fingerprint.fingerprint)))
|
||||
# set the trust combobox
|
||||
if self.ctx.active_fingerprint.trust:
|
||||
self.gw("verified_combobox").set_active(1)
|
||||
else:
|
||||
self.gw("verified_combobox").set_active(0)
|
||||
|
||||
otr_flags = gajim.config.get_per("contacts", self.contact.jid,
|
||||
"otr_flags")
|
||||
|
||||
if otr_flags > 0:
|
||||
self.gw("otr_default_checkbutton").set_active(0)
|
||||
for w in self.gw("otr_settings_vbox").get_children():
|
||||
w.set_sensitive(True)
|
||||
else:
|
||||
# per-user settings not available, using default settings
|
||||
otr_flags = gajim.config.get_per("accounts", self.account,
|
||||
"otr_flags")
|
||||
self.gw("otr_default_checkbutton").set_active(1)
|
||||
for w in self.gw("otr_settings_vbox").get_children():
|
||||
w.set_sensitive(False)
|
||||
|
||||
self.gw("otr_policy_allow_v1_checkbutton").set_active(
|
||||
otr_flags & gajim.otr_module.OTRL_POLICY_ALLOW_V1)
|
||||
self.gw("otr_policy_allow_v2_checkbutton").set_active(
|
||||
otr_flags & gajim.otr_module.OTRL_POLICY_ALLOW_V2)
|
||||
self.gw("otr_policy_require_checkbutton").set_active(
|
||||
otr_flags & gajim.otr_module.OTRL_POLICY_REQUIRE_ENCRYPTION)
|
||||
self.gw("otr_policy_send_tag_checkbutton").set_active(
|
||||
otr_flags & gajim.otr_module.OTRL_POLICY_SEND_WHITESPACE_TAG)
|
||||
self.gw("otr_policy_start_on_tag_checkbutton").set_active(
|
||||
otr_flags & gajim.otr_module.OTRL_POLICY_WHITESPACE_START_AKE)
|
||||
self.gw("otr_policy_start_on_error_checkbutton").set_active(
|
||||
otr_flags & gajim.otr_module.OTRL_POLICY_ERROR_START_AKE)
|
||||
|
||||
self.window.show_all()
|
||||
|
||||
def _on_destroy(self, widget):
|
||||
self.window.destroy()
|
||||
|
||||
def _apply(self, widget):
|
||||
# -1 when nothing is selected (ie. the connection is not encrypted)
|
||||
trust_state = self.gw("verified_combobox").get_active()
|
||||
if trust_state == 1 and not self.ctx.active_fingerprint.trust:
|
||||
gajim.otr_module.otrl_context_set_trust(
|
||||
self.ctx.active_fingerprint, "verified")
|
||||
gajim.otr_ui_ops.write_fingerprints({'account':self.account})
|
||||
elif trust_state == 0:
|
||||
gajim.otr_module.otrl_context_set_trust(
|
||||
self.ctx.active_fingerprint, "")
|
||||
gajim.otr_ui_ops.write_fingerprints({'account':self.account})
|
||||
|
||||
if not self.ctrl:
|
||||
self.ctrl = gajim.interface.msg_win_mgr.get_control(
|
||||
self.contact.jid, self.account)
|
||||
if self.ctrl:
|
||||
self.ctrl.update_ui()
|
||||
|
||||
if self.gw("otr_default_checkbutton").get_active():
|
||||
# default is enabled, so remove any user-specific settings if available
|
||||
gajim.config.set_per("contacts", self.contact.jid, "otr_flags", -1)
|
||||
else:
|
||||
# build the flags using the checkboxes
|
||||
flags = 0
|
||||
flags += self.gw("otr_policy_allow_v1_checkbutton").get_active() \
|
||||
and gajim.otr_module.OTRL_POLICY_ALLOW_V1
|
||||
flags += self.gw("otr_policy_allow_v2_checkbutton").get_active() \
|
||||
and gajim.otr_module.OTRL_POLICY_ALLOW_V2
|
||||
flags += self.gw("otr_policy_require_checkbutton").get_active() \
|
||||
and gajim.otr_module.OTRL_POLICY_REQUIRE_ENCRYPTION
|
||||
flags += self.gw("otr_policy_send_tag_checkbutton").get_active() \
|
||||
and gajim.otr_module.OTRL_POLICY_SEND_WHITESPACE_TAG
|
||||
flags += self.gw("otr_policy_start_on_tag_checkbutton").get_active() \
|
||||
and gajim.otr_module.OTRL_POLICY_WHITESPACE_START_AKE
|
||||
flags += self.gw("otr_policy_start_on_error_checkbutton").get_active() \
|
||||
and gajim.otr_module.OTRL_POLICY_ERROR_START_AKE
|
||||
|
||||
gajim.config.add_per("contacts", self.contact.jid)
|
||||
gajim.config.set_per("contacts", self.contact.jid, "otr_flags", flags)
|
||||
|
||||
self._on_destroy(widget)
|
||||
|
||||
def _otr_default_checkbutton_toggled(self, widget):
|
||||
for w in self.gw("otr_settings_vbox").get_children():
|
||||
w.set_sensitive(not widget.get_active())
|
|
@ -1771,6 +1771,20 @@ class RosterWindow:
|
|||
gajim.sleeper_state[account] = 'online'
|
||||
elif gajim.sleeper_state[account] not in ('autoaway', 'autoxa'):
|
||||
gajim.sleeper_state[account] = 'off'
|
||||
|
||||
if gajim.otr_module:
|
||||
# disconnect from ENCRYPTED OTR contexts when going
|
||||
# offline/invisible
|
||||
if status == 'offline' or status == 'invisible':
|
||||
ctx = gajim.otr_userstates[account].context_root
|
||||
while ctx is not None:
|
||||
if ctx.msgstate == gajim.otr_module.OTRL_MSGSTATE_ENCRYPTED:
|
||||
disconnected = True
|
||||
gajim.otr_module.otrl_message_disconnect(gajim.otr_userstates[account],
|
||||
(gajim.otr_ui_ops,
|
||||
{'account':account,'urgent':True}), ctx.accountname,
|
||||
ctx.protocol, ctx.username)
|
||||
ctx = ctx.next
|
||||
if to:
|
||||
gajim.connections[account].send_custom_status(status, txt, to)
|
||||
else:
|
||||
|
|
Loading…
Reference in New Issue