added gajim-otr plugin. needs python-potr > 1.0.0beta1 (which I will release soon)
This commit is contained in:
1
gotr/__init__.py
Normal file
1
gotr/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from otrmodule import OtrPlugin
|
||||
367
gotr/config_dialog.ui
Normal file
367
gotr/config_dialog.ui
Normal file
@@ -0,0 +1,367 @@
|
||||
<?xml version="1.0"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="2.16"/>
|
||||
<!-- interface-naming-policy toplevel-contextual -->
|
||||
<object class="GtkListStore" id="account_store">
|
||||
<columns>
|
||||
<!-- column-name accountname -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkListStore" id="fingerprint_store">
|
||||
<columns>
|
||||
<!-- column-name screenname -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name status -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name verified -->
|
||||
<column type="gboolean"/>
|
||||
<!-- column-name fingerprint -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name account -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name tooltip -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkNotebook" id="notebook1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkFrame" id="frame1">
|
||||
<property name="visible">True</property>
|
||||
<property name="border_width">12</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">none</property>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment1">
|
||||
<property name="visible">True</property>
|
||||
<property name="left_padding">12</property>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="fingerprint_label_desc">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Fingerprint:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="fingerprint_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"><tt>-------- -------- -------- -------- -------- </tt></property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="selectable">True</property>
|
||||
<property name="ellipsize">end</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="regenerate_button">
|
||||
<property name="label" translatable="yes">(Re-)generate</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<signal name="clicked" handler="regenerate_button_clicked_cb"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame" id="frame2">
|
||||
<property name="visible">True</property>
|
||||
<property name="border_width">12</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">none</property>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment2">
|
||||
<property name="visible">True</property>
|
||||
<property name="left_padding">12</property>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox3">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="enable_check">
|
||||
<property name="label" translatable="yes">Enable private (Off-the-Record) messaging</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="flags_toggled_cb" after="yes"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="advertise_check">
|
||||
<property name="label" translatable="yes">Advertise Off-the-Record messaging support</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="flags_toggled_cb" after="yes"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="autoinitiate_check">
|
||||
<property name="label" translatable="yes">Automatically start private messaging</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="flags_toggled_cb" after="yes"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="require_check">
|
||||
<property name="label" translatable="yes">Require private messaging</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="flags_toggled_cb" after="yes"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel" id="label3">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"><b>Default OTR Settings</b></property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkHBox" id="hbox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label4">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"><b>Off-the-Record settings for:</b></property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBox" id="account_combobox">
|
||||
<property name="visible">True</property>
|
||||
<property name="model">account_store</property>
|
||||
<signal name="changed" handler="account_combobox_changed_cb"/>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="cellrenderertext1"/>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">OTR Settings</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox4">
|
||||
<property name="visible">True</property>
|
||||
<property name="border_width">12</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolledwindow1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hscrollbar_policy">automatic</property>
|
||||
<property name="vscrollbar_policy">automatic</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="fingerprint_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="model">fingerprint_store</property>
|
||||
<property name="search_column">0</property>
|
||||
<property name="tooltip_column">5</property>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="name_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Name</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="cellrenderertext2"/>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="status_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Status</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="cellrenderertext3"/>
|
||||
<attributes>
|
||||
<attribute name="text">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="validated_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Validated</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererToggle" id="cellrenderertoggle1"/>
|
||||
<attributes>
|
||||
<attribute name="active">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="fingerprint_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Fingerprint</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="cellrenderertext4"/>
|
||||
<attributes>
|
||||
<attribute name="markup">3</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="account_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title">Account</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="cellrenderertext5"/>
|
||||
<attributes>
|
||||
<attribute name="text">4</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox3">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">5</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="verify_button">
|
||||
<property name="label" translatable="yes">Verify Fingerprint</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<signal name="clicked" handler="verify_button_clicked_cb"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="forget_button">
|
||||
<property name="label" translatable="yes">Forget Fingerprint</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<signal name="clicked" handler="forget_button_clicked_cb"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Known Fingerprints</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
376
gotr/contact_otr_window.ui
Normal file
376
gotr/contact_otr_window.ui
Normal file
@@ -0,0 +1,376 @@
|
||||
<?xml version="1.0"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="2.16"/>
|
||||
<!-- interface-naming-policy toplevel-contextual -->
|
||||
<object class="GtkNotebook" id="otr_settings_notebook">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<child>
|
||||
<object class="GtkVBox" id="otr_fp_vbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">5</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<child>
|
||||
<object 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>
|
||||
<property name="selectable">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object 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>
|
||||
<property name="selectable">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox1">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkComboBox" id="verified_combobox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="model">verifiedmodel</property>
|
||||
<property name="active">0</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="cellrenderertext1"/>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object 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>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Authentication</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame" id="frame2">
|
||||
<property name="visible">True</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">none</property>
|
||||
<child>
|
||||
<object class="GtkVBox" id="otr_settings_vbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">5</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="otr_policy_allow_v2_checkbutton">
|
||||
<property name="label" translatable="yes">OTR version 2 allowed</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="otr_policy_require_checkbutton">
|
||||
<property name="label" translatable="yes">Encryption required</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="otr_policy_send_tag_checkbutton">
|
||||
<property name="label" translatable="yes">Show others we understand OTR</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="otr_policy_start_on_tag_checkbutton">
|
||||
<property name="label" translatable="yes">Automatically initiate encryption if partner understands OTR</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkCheckButton" id="otr_default_checkbutton">
|
||||
<property name="label" translatable="yes">Use the default settings</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">OTR Settings</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkListStore" id="verifiedmodel">
|
||||
<columns>
|
||||
<!-- column-name verified -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
<data>
|
||||
<row>
|
||||
<col id="0" translatable="yes">I have NOT</col>
|
||||
</row>
|
||||
<row>
|
||||
<col id="0" translatable="yes">I have</col>
|
||||
</row>
|
||||
</data>
|
||||
</object>
|
||||
<object class="GtkWindow" id="otr_smp_window">
|
||||
<property name="resizable">False</property>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox3">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox4">
|
||||
<property name="visible">True</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="desclabel1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">label</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="wrap">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox2">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="qcheckbutton">
|
||||
<property name="label" translatable="yes">Use question: </property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="qentry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="desclabel2">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">label</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="secret_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox3">
|
||||
<property name="visible">True</property>
|
||||
<property name="border_width">5</property>
|
||||
<child>
|
||||
<object class="GtkProgressBar" id="progressbar">
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHButtonBox" id="hbuttonbox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="smp_cancel_button">
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="smp_ok_button">
|
||||
<property name="label">gtk-ok</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkMenuItem" id="otr_submenu">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="label" translatable="yes">Off-the-Record Encryption</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child type="submenu">
|
||||
<object class="GtkMenu" id="otr_submenu_menu">
|
||||
<child>
|
||||
<object 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"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object 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"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object 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"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object 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"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
7
gotr/manifest.ini
Normal file
7
gotr/manifest.ini
Normal file
@@ -0,0 +1,7 @@
|
||||
[info]
|
||||
name: Off-The-Record Encryption
|
||||
short_name: gotr
|
||||
version: 1
|
||||
description: See http://www.cypherpunks.ca/otr/
|
||||
authors: Kjell Braden <afflux.gajim@pentabarf.de>
|
||||
homepage: http://gajim-otr.pentabarf.de
|
||||
516
gotr/otrmodule.py
Normal file
516
gotr/otrmodule.py
Normal file
@@ -0,0 +1,516 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
## otrmodule.py
|
||||
##
|
||||
## Copyright (C) 2008-2010 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/>.
|
||||
##
|
||||
|
||||
|
||||
'''
|
||||
Off-The-Record encryption plugin.
|
||||
|
||||
:author: Kjell self.Braden <kb.otr@pentabarf.de>
|
||||
:since: 20 May 2011
|
||||
:copyright: Copyright (2011) Kjell Braden <kb.otr@pentabarf.de>
|
||||
:license: GPL
|
||||
'''
|
||||
|
||||
MINVERSION = (1,0,0,'beta1') # 1.0-alpha1
|
||||
IGNORE = True
|
||||
PASS = False
|
||||
|
||||
DEFAULTFLAGS = {
|
||||
'ALLOW_V1':False,
|
||||
'ALLOW_V2':True,
|
||||
'REQUIRE_ENCRYPTION':False,
|
||||
'SEND_TAG':True,
|
||||
'WHITESPACE_START_AKE':True,
|
||||
'ERROR_START_AKE':True,
|
||||
}
|
||||
|
||||
MMS = 1024
|
||||
PROTOCOL = 'xmpp'
|
||||
|
||||
enc_tip = 'A private chat session <i>is established</i> to this contact ' \
|
||||
'with this fingerprint'
|
||||
unused_tip = 'A private chat session is established to this contact using ' \
|
||||
'<i>another</i> fingerprint'
|
||||
ended_tip = 'The private chat session to this contact has <i>ended</i>'
|
||||
inactive_tip = 'Communication to this contact is currently ' \
|
||||
'<i>unencrypted</i>'
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
import common.xmpp
|
||||
from common import gajim
|
||||
from common import ged
|
||||
from common.connection_handlers_events import MessageOutgoingEvent
|
||||
from plugins import GajimPlugin
|
||||
from message_control import TYPE_CHAT, MessageControl
|
||||
from plugins.helpers import log_calls, log
|
||||
|
||||
import ui
|
||||
|
||||
|
||||
import pickle
|
||||
import potr
|
||||
if not hasattr(potr, 'VERSION') or potr.VERSION < MINVERSION:
|
||||
raise ImportError('old / unsupported python-otr version')
|
||||
|
||||
class GajimContext(potr.context.Context):
|
||||
__slots__ = ['smpWindow']
|
||||
|
||||
def __init__(self, account, peer):
|
||||
super(GajimContext, self).__init__(account, peer)
|
||||
self.smpWindow = ui.ContactOtrSmpWindow(self)
|
||||
|
||||
def inject(self, msg, appdata=None):
|
||||
log.warning('inject(appdata=%s)', appdata)
|
||||
msg = unicode(msg)
|
||||
account = self.user.accountname
|
||||
|
||||
stanza = common.xmpp.Message(to=self.peer, body=msg, typ='chat')
|
||||
if appdata and 'session' in appdata:
|
||||
session = appdata['session']
|
||||
stanza.setThread(session.thread_id)
|
||||
gajim.connections[account].connection.send(stanza, now=True)
|
||||
return
|
||||
|
||||
def setState(self, newstate):
|
||||
if self.state == potr.context.STATE_ENCRYPTED:
|
||||
# we were encrypted
|
||||
if newstate == potr.context.STATE_ENCRYPTED:
|
||||
# and are still -> it's just a refresh
|
||||
OtrPlugin.gajim_log(
|
||||
_('Private conversation with %s refreshed.') % self.peer,
|
||||
self.user.accountname, self.peer)
|
||||
elif newstate == potr.context.STATE_FINISHED:
|
||||
# and aren't anymore -> other side disconnected
|
||||
OtrPlugin.gajim_log(_('%s has ended his/her private '
|
||||
'conversation with you. You should do the same.')
|
||||
% self.peer, self.user.accountname, self.peer)
|
||||
else:
|
||||
if newstate == potr.context.STATE_ENCRYPTED:
|
||||
# we are now encrypted
|
||||
trust = self.getCurrentTrust()
|
||||
if trust is None:
|
||||
fpr = str(self.getCurrentKey())
|
||||
OtrPlugin.gajim_log(_('New fingerprint for %s: %s')
|
||||
% (self.peer, fpr), self.user.accountname, self.peer)
|
||||
self.setCurrentTrust('')
|
||||
trustStr = 'authenticated' if bool(trust) else '*unauthenticated*'
|
||||
OtrPlugin.gajim_log(
|
||||
_('%s secured OTR conversation with %s started')
|
||||
% (trustStr, self.peer), self.user.accountname, self.peer)
|
||||
|
||||
if self.state != potr.context.STATE_PLAINTEXT and \
|
||||
newstate == potr.context.STATE_PLAINTEXT:
|
||||
# we are now plaintext
|
||||
OtrPlugin.gajim_log(
|
||||
_('Private conversation with %s lost.') % self.peer,
|
||||
self.user.accountname, self.peer)
|
||||
|
||||
super(GajimContext, self).setState(newstate)
|
||||
OtrPlugin.update_otr(self.peer, self.user.accountname)
|
||||
self.user.plugin.update_context_list()
|
||||
|
||||
def getPolicy(self, key):
|
||||
jid = gajim.get_room_and_nick_from_fjid(self.peer)[0]
|
||||
ret = self.user.plugin.get_flags(self.user.accountname, jid)[key]
|
||||
log.warning('getPolicy(key=%s) = %s', key, ret)
|
||||
return ret
|
||||
|
||||
class GajimOtrAccount(potr.context.Account):
|
||||
contextclass = GajimContext
|
||||
def __init__(self, plugin, accountname):
|
||||
global PROTOCOL, MMS
|
||||
self.plugin = plugin
|
||||
self.accountname = accountname
|
||||
name = gajim.get_jid_from_account(accountname)
|
||||
super(GajimOtrAccount, self).__init__(name, PROTOCOL, MMS)
|
||||
self.keyFilePath = os.path.join(gajim.gajimpaths.data_root, accountname)
|
||||
|
||||
def loadPrivkey(self):
|
||||
try:
|
||||
with open(self.keyFilePath + '.key2', 'r') as keyFile:
|
||||
return pickle.load(keyFile)
|
||||
except IOError, e:
|
||||
log.exception('IOError occurred when loading key file for %s',
|
||||
self.name)
|
||||
return None
|
||||
|
||||
def savePrivkey(self):
|
||||
try:
|
||||
with open(self.keyFilePath + '.key2', 'w') as keyFile:
|
||||
pickle.dump(self.getPrivkey(), keyFile)
|
||||
except IOError, e:
|
||||
log.exception('IOError occurred when loading key file for %s',
|
||||
self.name)
|
||||
|
||||
def loadTrusts(self, newCtxCb=None):
|
||||
''' load the fingerprint trustdb '''
|
||||
# it has the same format as libotr, therefore the
|
||||
# redundant account / proto field
|
||||
try:
|
||||
with open(self.keyFilePath + '.fpr', 'r') as fprFile:
|
||||
for line in fprFile:
|
||||
ctx, acc, proto, fpr, trust = line[:-1].split('\t')
|
||||
|
||||
if acc != self.name or proto != PROTOCOL:
|
||||
continue
|
||||
|
||||
self.getContext(ctx, newCtxCb).setTrust(fpr, trust)
|
||||
except IOError, e:
|
||||
log.exception('IOError occurred when loading fpr file for %s',
|
||||
self.name)
|
||||
|
||||
def saveTrusts(self):
|
||||
try:
|
||||
with open(self.keyFilePath + '.fpr', 'w') as fprFile:
|
||||
for uid, ctx in self.ctxs.iteritems():
|
||||
for fpr, trust in ctx.trust.iteritems():
|
||||
fprFile.write('\t'.join(
|
||||
(uid, self.name, PROTOCOL, fpr, trust)))
|
||||
fprFile.write('\n')
|
||||
except IOError, e:
|
||||
log.exception('IOError occurred when loading fpr file for %s',
|
||||
self.name)
|
||||
|
||||
|
||||
def otr_dialog_destroy(widget, *args, **kwargs):
|
||||
widget.destroy()
|
||||
|
||||
class OtrPlugin(GajimPlugin):
|
||||
otr = None
|
||||
def init(self):
|
||||
|
||||
self.us = {}
|
||||
self.config_dialog = ui.OtrPluginConfigDialog(self)
|
||||
self.events_handlers = {}
|
||||
self.events_handlers['message-received'] = (ged.PRECORE,
|
||||
self.handle_incoming_msg)
|
||||
self.events_handlers['message-outgoing'] = (ged.OUT_PRECORE,
|
||||
self.handle_outgoing_msg)
|
||||
|
||||
self.gui_extension_points = {
|
||||
'chat_control' : (self.cc_connect, self.cc_disconnect)
|
||||
}
|
||||
|
||||
for acc in gajim.contacts.get_accounts():
|
||||
self.us[acc] = GajimOtrAccount(self, acc)
|
||||
self.us[acc].loadTrusts()
|
||||
|
||||
acc = str(acc)
|
||||
if acc not in self.config or None not in self.config[acc]:
|
||||
self.config[acc] = {None:DEFAULTFLAGS.copy()}
|
||||
|
||||
def get_otr_status(self, account, contact):
|
||||
ctx = self.us[account].getContext(contact.get_full_jid())
|
||||
|
||||
finished = ctx.state == potr.context.STATE_FINISHED
|
||||
encrypted = finished or ctx.state == potr.context.STATE_ENCRYPTED
|
||||
trusted = encrypted and bool(ctx.getCurrentTrust())
|
||||
return (encrypted, trusted, finished)
|
||||
|
||||
def cc_connect(self, cc):
|
||||
def update_otr(print_status=False):
|
||||
enc_status, authenticated, finished = \
|
||||
self.get_otr_status(cc.account, cc.contact)
|
||||
otr_status_text = ''
|
||||
|
||||
if finished:
|
||||
otr_status_text = u'finished OTR connection'
|
||||
elif authenticated:
|
||||
otr_status_text = u'authenticated secure OTR connection'
|
||||
elif enc_status:
|
||||
otr_status_text = u'*unauthenticated* secure OTR connection'
|
||||
|
||||
cc._show_lock_image(enc_status, u'OTR', enc_status, True,
|
||||
authenticated)
|
||||
if print_status and otr_status_text:
|
||||
cc.print_conversation_line(u'[OTR] %s' % otr_status_text,
|
||||
'status', '', None)
|
||||
cc.update_otr = update_otr
|
||||
cc.update_otr(True)
|
||||
|
||||
# hijack authentication button with our submenu
|
||||
def authbutton_cb(widget):
|
||||
if not cc.gpg_is_active and not (cc.session and
|
||||
cc.session.enable_encryption):
|
||||
ui.get_otr_submenu(self, cc).get_submenu().popup(None,
|
||||
None, None, 0, 0)
|
||||
else:
|
||||
cc._on_authentication_button_clicked(cc, widget)
|
||||
self.overwrite_handler(cc, cc.authentication_button, authbutton_cb)
|
||||
|
||||
# hijack context menu
|
||||
cc.orig_prepare_context_menu = cc.prepare_context_menu
|
||||
def inject_menu(hide_buttonbar_items=False):
|
||||
menu = cc.orig_prepare_context_menu(hide_buttonbar_items)
|
||||
menu.insert(ui.get_otr_submenu(self, cc), 8)
|
||||
return menu
|
||||
cc.prepare_context_menu = inject_menu
|
||||
|
||||
def cc_disconnect(self, cc):
|
||||
try:
|
||||
self.overwrite_handler(cc, cc.authentication_button,
|
||||
cc._on_authentication_button_clicked)
|
||||
cc.prepare_context_menu = cc.orig_prepare_context_menu
|
||||
del cc.update_otr
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def menu_settings_cb(self, item, control):
|
||||
ctx = self.us[control.account].getContext(control.contact.get_full_jid())
|
||||
dlg = ui.ContactOtrWindow(self, ctx)
|
||||
dlg.run()
|
||||
dlg.destroy()
|
||||
|
||||
def menu_start_cb(self, item, control):
|
||||
gajim.nec.push_outgoing_event(MessageOutgoingEvent(None,
|
||||
account=control.account, jid=control.contact.jid,
|
||||
message=u'?OTRv?', type_='chat',
|
||||
resource=control.contact.resource, is_loggable=False))
|
||||
|
||||
def menu_end_cb(self, item, control):
|
||||
fjid = control.contact.get_full_jid()
|
||||
thread_id = control.session.thread_id if control.session else None
|
||||
|
||||
self.us[control.account].getContext(fjid).disconnect(
|
||||
appdata={'session':control.session})
|
||||
|
||||
def menu_smp_cb(self, item, control):
|
||||
ctx = self.us[control.account].getContext(control.contact.get_full_jid())
|
||||
ctx.smpWindow.show(False)
|
||||
|
||||
@staticmethod
|
||||
def overwrite_handler(window, control, handler):
|
||||
for id_, v in window.handlers.iteritems():
|
||||
if v == control:
|
||||
break
|
||||
else:
|
||||
raise LookupError
|
||||
|
||||
del window.handlers[id_]
|
||||
control.disconnect(id_)
|
||||
id_ = control.connect('clicked', handler)
|
||||
window.handlers[id_] = control
|
||||
|
||||
def set_flags(self, value, account=None, contact=None):
|
||||
if isinstance(account, unicode):
|
||||
account = account.encode()
|
||||
|
||||
if account not in self.config:
|
||||
self.config[account] = {None:DEFAULTFLAGS.copy()}
|
||||
|
||||
if account is None and contact is not None:
|
||||
# don't set per-contact options without account
|
||||
raise Exception("can't set contact flags without account")
|
||||
|
||||
config = self.config[account]
|
||||
config[contact] = value
|
||||
|
||||
self.config[account] = config
|
||||
|
||||
def get_flags(self, account=None, contact=None, fallback=True):
|
||||
if isinstance(account, unicode):
|
||||
account = account.encode()
|
||||
|
||||
setting = DEFAULTFLAGS.copy()
|
||||
if account in self.config:
|
||||
setting.update(self.config[account][None])
|
||||
if contact in self.config[account] \
|
||||
and self.config[account][contact] is not None:
|
||||
setting.update(self.config[account][contact])
|
||||
elif not fallback:
|
||||
return None
|
||||
return setting
|
||||
|
||||
def update_context_list(self):
|
||||
self.config_dialog.fpr_model.clear()
|
||||
for us in self.us.itervalues():
|
||||
for uid, ctx in us.ctxs.iteritems():
|
||||
for fpr, trust in ctx.trust.iteritems():
|
||||
trust = False
|
||||
if ctx.state == potr.context.STATE_ENCRYPTED:
|
||||
if ctx.getCurrentKey().cfingerprint() == fpr:
|
||||
state = "encrypted"
|
||||
tip = enc_tip
|
||||
trust = bool(ctx.getCurrentTrust())
|
||||
else:
|
||||
state = "unused"
|
||||
tip = unused_tip
|
||||
elif ctx.state == potr.context.STATE_FINISHED:
|
||||
state = "finished"
|
||||
tip = ended_tip
|
||||
else:
|
||||
state = 'inactive'
|
||||
tip = inactive_tip
|
||||
|
||||
human_hash = potr.human_hash(fpr)
|
||||
|
||||
self.config_dialog.fpr_model.append((uid, state, trust,
|
||||
'<tt>%s</tt>' % human_hash, us.name, tip, fpr))
|
||||
|
||||
@classmethod
|
||||
def gajim_log(cls, msg, account, fjid, no_print=False,
|
||||
is_status_message=True, thread_id=None):
|
||||
if not isinstance(fjid, unicode):
|
||||
fjid = unicode(fjid)
|
||||
if not isinstance(account, unicode):
|
||||
account = unicode(account)
|
||||
|
||||
resource = gajim.get_resource_from_jid(fjid)
|
||||
jid = gajim.get_jid_without_resource(fjid)
|
||||
tim = time.localtime()
|
||||
|
||||
if is_status_message is True:
|
||||
if not no_print:
|
||||
ctrl = cls.get_control(fjid, account)
|
||||
if ctrl:
|
||||
ctrl.print_conversation_line(u'[OTR] %s' % msg, 'status',
|
||||
'', None)
|
||||
id = gajim.logger.write('chat_msg_recv', fjid,
|
||||
message=u'[OTR: %s]' % msg, tim=tim)
|
||||
# gajim.logger.write() only marks a message as unread (and so
|
||||
# only returns an id) when fjid is a real contact (NOT if it's a
|
||||
# GC private chat)
|
||||
if id:
|
||||
gajim.logger.set_read_messages([id])
|
||||
else:
|
||||
session = gajim.connections[account].get_or_create_session(fjid,
|
||||
thread_id)
|
||||
session.received_thread_id |= bool(thread_id)
|
||||
session.last_receive = time.time()
|
||||
|
||||
if not session.control:
|
||||
# look for an existing chat control without a session
|
||||
ctrl = cls.get_control(fjid, account)
|
||||
if ctrl:
|
||||
session.control = ctrl
|
||||
session.control.set_session(session)
|
||||
|
||||
msg_id = gajim.logger.write('chat_msg_recv', fjid,
|
||||
message=u'[OTR: %s]' % msg, tim=tim)
|
||||
session.roster_message(jid, msg, tim=tim, msg_id=msg_id,
|
||||
msg_type='chat', resource=resource)
|
||||
|
||||
@classmethod
|
||||
def update_otr(cls, user, acc, print_status=False):
|
||||
ctrl = cls.get_control(user, acc)
|
||||
if ctrl:
|
||||
ctrl.update_otr(print_status)
|
||||
|
||||
@staticmethod
|
||||
def get_control(fjid, account):
|
||||
# first try to get the window with the full jid
|
||||
ctrl = gajim.interface.msg_win_mgr.get_control(fjid, account)
|
||||
if ctrl:
|
||||
# got one, be happy
|
||||
return ctrl
|
||||
|
||||
# otherwise try without the resource
|
||||
ctrl = gajim.interface.msg_win_mgr.get_control(
|
||||
gajim.get_jid_without_resource(fjid), account)
|
||||
# but only use it when it's not a GC window
|
||||
if ctrl and ctrl.TYPE_ID == TYPE_CHAT:
|
||||
return ctrl
|
||||
|
||||
def handle_incoming_msg(self, event):
|
||||
ctx = None
|
||||
account = event.conn.name
|
||||
accjid = gajim.get_jid_from_account(account)
|
||||
|
||||
if event.encrypted is not False or not event.stanza.getTag('body') \
|
||||
or not isinstance(event.stanza.getBody(), unicode):
|
||||
return PASS
|
||||
|
||||
try:
|
||||
ctx = self.us[account].getContext(event.fjid)
|
||||
msgtxt, tlvs = ctx.receiveMessage(event.msgtxt,
|
||||
appdata={'session':event.session})
|
||||
except potr.context.UnencryptedMessage, e:
|
||||
tlvs = []
|
||||
msgtxt = _('The following message received from %s was '
|
||||
'*not encrypted*: [%s]') % (event.fjid, e.args[0])
|
||||
except potr.context.NotEncryptedError, e:
|
||||
self.gajim_log(_('The encrypted message received from %s is '
|
||||
'unreadable, as you are not currently communicating '
|
||||
'privately') % event.fjid, account, event.fjid)
|
||||
return IGNORE
|
||||
except potr.context.ErrorReceived, e:
|
||||
self.gajim_log(_('We received the following OTR error '
|
||||
'message from %s: [%s]') % (event.fjid, e.args[0].error),
|
||||
account, event.fjid)
|
||||
return IGNORE
|
||||
except RuntimeError, e:
|
||||
self.gajim_log(_('The following error occurred when trying to '
|
||||
'decrypt a message from %s: [%s]') % (event.fjid, e),
|
||||
account, event.fjid)
|
||||
return IGNORE
|
||||
event.msgtxt = unicode(msgtxt)
|
||||
event.stanza.setBody(event.msgtxt)
|
||||
|
||||
html_node = event.stanza.getTag('html')
|
||||
if html_node:
|
||||
event.stanza.delChild(html_node)
|
||||
|
||||
if ctx is not None:
|
||||
ctx.smpWindow.handle_tlv(tlvs)
|
||||
|
||||
if not msgtxt:
|
||||
return IGNORE
|
||||
|
||||
return PASS
|
||||
|
||||
def handle_outgoing_msg(self, event):
|
||||
if hasattr(event, 'otrmessage'):
|
||||
return PASS
|
||||
|
||||
xep_200 = bool(event.session) and event.session.enable_encryption
|
||||
if xep_200 or not event.message:
|
||||
return PASS
|
||||
|
||||
print event
|
||||
|
||||
if event.session:
|
||||
fjid = event.session.get_to()
|
||||
else:
|
||||
fjid = event.jid
|
||||
if event.resource:
|
||||
fjid += '/' + event.resource
|
||||
print (fjid, event.session, event.jid, event.resource)
|
||||
|
||||
try:
|
||||
newmsg = self.us[event.account].getContext(fjid).sendMessage(
|
||||
potr.context.FRAGMENT_SEND_ALL_BUT_LAST, event.message,
|
||||
appdata={'session':event.session})
|
||||
except potr.context.NotEncryptedError, e:
|
||||
if e.args[0] == potr.context.EXC_FINISHED:
|
||||
self.gajim_log(_('Your message was not send. Either end '
|
||||
'your private conversation, or restart it'), event.account,
|
||||
fjid)
|
||||
return IGNORE
|
||||
else:
|
||||
raise e
|
||||
event.message = newmsg
|
||||
|
||||
return PASS
|
||||
|
||||
## TODO:
|
||||
## - disconnect ctxs on disconnect
|
||||
544
gotr/ui.py
Normal file
544
gotr/ui.py
Normal file
@@ -0,0 +1,544 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
## ui.py
|
||||
##
|
||||
## Copyright (C) 2008-2010 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 gobject
|
||||
import gtk
|
||||
from common import i18n
|
||||
from common import gajim
|
||||
from plugins.gui import GajimPluginConfigDialog
|
||||
|
||||
import otrmodule
|
||||
import potr
|
||||
|
||||
|
||||
class OtrPluginConfigDialog(GajimPluginConfigDialog):
|
||||
def init(self):
|
||||
self.GTK_BUILDER_FILE_PATH = \
|
||||
self.plugin.local_file_path('config_dialog.ui')
|
||||
self.B = gtk.Builder()
|
||||
self.B.set_translation_domain(i18n.APP)
|
||||
self.B.add_from_file(self.GTK_BUILDER_FILE_PATH)
|
||||
|
||||
self.fpr_model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING,
|
||||
gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_STRING,
|
||||
gobject.TYPE_STRING, gobject.TYPE_STRING)
|
||||
|
||||
self.otr_account_store = self.B.get_object('account_store')
|
||||
|
||||
for account in sorted(gajim.contacts.get_accounts()):
|
||||
self.otr_account_store.append(row=(account,))
|
||||
|
||||
fpr_view = self.B.get_object('fingerprint_view')
|
||||
fpr_view.set_model(self.fpr_model)
|
||||
fpr_view.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
|
||||
|
||||
if len(self.otr_account_store) > 0:
|
||||
self.B.get_object('account_combobox').set_active(0)
|
||||
|
||||
self.child.pack_start(self.B.get_object('notebook1'))
|
||||
|
||||
self.flags = dict()
|
||||
flagList = (
|
||||
('ALLOW_V2', 'enable_check'),
|
||||
('SEND_TAG', 'advertise_check'),
|
||||
('WHITESPACE_START_AKE', 'autoinitiate_check'),
|
||||
('REQUIRE_ENCRYPTION', 'require_check')
|
||||
)
|
||||
for flagName, checkBoxName in flagList:
|
||||
self.flags[flagName] = self.B.get_object(checkBoxName)
|
||||
|
||||
self.B.connect_signals(self)
|
||||
self.account_combobox_changed_cb(self.B.get_object('account_combobox'))
|
||||
|
||||
def on_run(self):
|
||||
self.plugin.update_context_list()
|
||||
|
||||
def flags_toggled_cb(self, button):
|
||||
if button == self.B.get_object('enable_check'):
|
||||
new_status = button.get_active()
|
||||
self.B.get_object('advertise_check').set_sensitive(new_status)
|
||||
self.B.get_object('autoinitiate_check').set_sensitive(new_status)
|
||||
self.B.get_object('require_check').set_sensitive(new_status)
|
||||
|
||||
if new_status is False:
|
||||
self.B.get_object('advertise_check').set_active(False)
|
||||
self.B.get_object('autoinitiate_check').set_active(False)
|
||||
self.B.get_object('require_check').set_active(False)
|
||||
|
||||
box = self.B.get_object('account_combobox')
|
||||
active = box.get_active()
|
||||
if active > -1:
|
||||
account = self.otr_account_store[active][0]
|
||||
|
||||
flagValues = {}
|
||||
for key, box in self.flags.iteritems():
|
||||
flagValues[key] = box.get_active()
|
||||
self.plugin.set_flags(flagValues, account)
|
||||
|
||||
def account_combobox_changed_cb(self, box, *args):
|
||||
fpr_label = self.B.get_object('fingerprint_label')
|
||||
regen_button = self.B.get_object('regenerate_button')
|
||||
|
||||
active = box.get_active()
|
||||
fpr = '-------- -------- -------- -------- --------'
|
||||
try:
|
||||
if active > -1:
|
||||
regen_button.set_sensitive(True)
|
||||
account = self.otr_account_store[active][0]
|
||||
|
||||
otr_flags = self.plugin.get_flags(account)
|
||||
for key, box in self.flags.iteritems():
|
||||
box.set_active(otr_flags[key])
|
||||
|
||||
fpr = str(self.plugin.us[account].getPrivkey())
|
||||
regen_button.set_label('Regenerate')
|
||||
else:
|
||||
regen_button.set_sensitive(False)
|
||||
except LookupError, e:
|
||||
# Account not found, no private key available - display the
|
||||
# empty one
|
||||
regen_button.set_label('Generate')
|
||||
finally:
|
||||
self.B.get_object('fingerprint_label').set_markup('<tt>%s</tt>'%fpr)
|
||||
|
||||
def forget_button_clicked_cb(self, button, *args):
|
||||
accounts = {}
|
||||
for acc in gajim.connections.iterkeys():
|
||||
accounts[gajim.get_jid_from_account(acc)] = acc
|
||||
|
||||
tw = self.B.get_object('fingerprint_view')
|
||||
|
||||
mod, paths = tw.get_selection().get_selected_rows()
|
||||
|
||||
for path in paths:
|
||||
it = mod.get_iter(path)
|
||||
user, human_fpr, a, fpr = mod.get(it, 0, 3, 4, 6)
|
||||
|
||||
dlg = gtk.Dialog('Confirm removal of fingerprint', self,
|
||||
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
(gtk.STOCK_YES, gtk.RESPONSE_YES,
|
||||
gtk.STOCK_NO, gtk.RESPONSE_NO)
|
||||
)
|
||||
l = gtk.Label()
|
||||
l.set_markup('Are you sure you want remove the following '
|
||||
'fingerprint for the contact %s on the account %s?'
|
||||
'\n\n%s' % (user, a, human_fpr))
|
||||
l.set_line_wrap(True)
|
||||
dlg.vbox.pack_start(l)
|
||||
dlg.show_all()
|
||||
|
||||
if dlg.run() == gtk.RESPONSE_YES:
|
||||
ctx = self.plugin.us[accounts[a]].getContext(user)
|
||||
ctx.removeFingerprint(fpr)
|
||||
dlg.destroy()
|
||||
self.plugin.us[accounts[a]].saveTrusts()
|
||||
|
||||
self.plugin.update_context_list()
|
||||
|
||||
def verify_button_clicked_cb(self, button, *args):
|
||||
accounts = {}
|
||||
for acc in gajim.connections.iterkeys():
|
||||
accounts[gajim.get_jid_from_account(acc)] = acc
|
||||
|
||||
tw = self.B.get_object('fingerprint_view')
|
||||
|
||||
mod, paths = tw.get_selection().get_selected_rows()
|
||||
|
||||
# open the window for the first selected row
|
||||
for path in paths[0:1]:
|
||||
it = mod.get_iter(path)
|
||||
fjid, fpr, a = mod.get(it, 0, 6, 4)
|
||||
|
||||
ctx = self.plugin.us[accounts[a]].getContext(fjid)
|
||||
|
||||
dlg = ContactOtrWindow(self.plugin, ctx, fpr=fpr, parent=self)
|
||||
dlg.run()
|
||||
dlg.destroy()
|
||||
break
|
||||
|
||||
def regenerate_button_clicked_cb(self, button, *args):
|
||||
box = self.B.get_object('account_combobox')
|
||||
active = box.get_active()
|
||||
if active > -1:
|
||||
account = self.otr_account_store[active][0]
|
||||
button.set_sensitive(False)
|
||||
self.plugin.us[account].privkey = None
|
||||
self.account_combobox_changed_cb(box, *args)
|
||||
button.set_sensitive(True)
|
||||
|
||||
|
||||
import gtkgui_helpers
|
||||
from common import gajim
|
||||
|
||||
our_fp_text = _('Your fingerprint:\n' \
|
||||
'<span weight="bold" face="monospace">%s</span>')
|
||||
their_fp_text = _('Purported fingerprint for %s:\n' \
|
||||
'<span weight="bold" face="monospace">%s</span>')
|
||||
|
||||
another_q = _('You may want to authenticate your buddy as well by asking'\
|
||||
'your own question.')
|
||||
smp_query = _('<b>%s is trying to authenticate you using a secret only known '\
|
||||
'to him/her and you.</b>')
|
||||
smp_q_query = _('<b>%s has chosen a question for you to answer to '\
|
||||
'authenticate yourself:</b>')
|
||||
enter_secret = _('Please enter your secret below.')
|
||||
|
||||
smp_init = _('<b>You are trying to authenticate %s using a secret only known ' \
|
||||
'to him/her and yourself.</b>')
|
||||
choose_q = _('You can choose a question as a hint for your buddy below.')
|
||||
|
||||
class ContactOtrSmpWindow:
|
||||
def gw(self, n):
|
||||
return self.xml.get_object(n)
|
||||
|
||||
def __init__(self, ctx):
|
||||
self.question = None
|
||||
self.ctx = ctx
|
||||
self.account = ctx.user.accountname
|
||||
|
||||
self.plugin = ctx.user.plugin
|
||||
|
||||
self.GTK_BUILDER_FILE_PATH = \
|
||||
self.plugin.local_file_path('contact_otr_window.ui')
|
||||
self.xml = gtk.Builder()
|
||||
self.xml.set_translation_domain(i18n.APP)
|
||||
self.xml.add_from_file(self.GTK_BUILDER_FILE_PATH)
|
||||
|
||||
self.window = self.gw('otr_smp_window')
|
||||
self.window.set_title(_('OTR settings for %s') % ctx.peer)
|
||||
|
||||
# the lambda thing is an anonymous helper that just discards the
|
||||
# parameters and calls hide_on_delete on clicking the window's
|
||||
# close button
|
||||
self.window.connect('delete-event', lambda d,o:
|
||||
self.window.hide_on_delete())
|
||||
|
||||
self.gw('smp_cancel_button').connect('clicked', self._on_destroy)
|
||||
self.gw('smp_ok_button').connect('clicked', self._apply)
|
||||
self.gw('qcheckbutton').connect('toggled', self._toggle)
|
||||
|
||||
self.gw('qcheckbutton').set_no_show_all(False)
|
||||
self.gw('qentry').set_no_show_all(False)
|
||||
self.gw('desclabel2').set_no_show_all(False)
|
||||
|
||||
def _toggle(self, w, *args):
|
||||
self.gw('qentry').set_sensitive(w.get_active())
|
||||
|
||||
def show(self, response):
|
||||
self.smp_running = False
|
||||
self.finished = False
|
||||
|
||||
self.gw('smp_cancel_button').set_sensitive(True)
|
||||
self.gw('smp_ok_button').set_sensitive(True)
|
||||
self.gw('progressbar').set_fraction(0)
|
||||
self.gw('secret_entry').set_text('')
|
||||
|
||||
self.response = response
|
||||
self.window.show_all()
|
||||
if response:
|
||||
self.gw('qcheckbutton').set_sensitive(False)
|
||||
if self.question is None:
|
||||
self.gw('qcheckbutton').set_active(False)
|
||||
self.gw('qcheckbutton').hide()
|
||||
self.gw('qentry').hide()
|
||||
self.gw('desclabel2').hide()
|
||||
self.gw('qcheckbutton').set_sensitive(False)
|
||||
self.gw('desclabel1').set_markup((smp_query % self.ctx.peer)
|
||||
+ ' ' + enter_secret)
|
||||
else:
|
||||
self.gw('qcheckbutton').set_active(True)
|
||||
self.gw('qcheckbutton').show()
|
||||
self.gw('qentry').show()
|
||||
self.gw('qentry').set_sensitive(True)
|
||||
self.gw('qentry').set_editable(False)
|
||||
self.gw('desclabel2').show()
|
||||
self.gw('qentry').set_text(self.question)
|
||||
|
||||
self.gw('desclabel1').set_markup(smp_q_query % self.ctx.peer)
|
||||
self.gw('desclabel2').set_markup(enter_secret)
|
||||
else:
|
||||
self.gw('qcheckbutton').show()
|
||||
self.gw('qcheckbutton').set_active(True)
|
||||
self.gw('qcheckbutton').set_mode(True)
|
||||
self.gw('qcheckbutton').set_sensitive(True)
|
||||
self.gw('qentry').set_sensitive(True)
|
||||
self.gw('qentry').show()
|
||||
self.gw('qentry').set_text("")
|
||||
|
||||
self.gw('qentry').set_editable(True)
|
||||
self.gw('qentry').set_sensitive(True)
|
||||
|
||||
self.gw('desclabel2').show()
|
||||
self.gw('desclabel1').set_markup((smp_init % self.ctx.peer) + ' '
|
||||
+ choose_q)
|
||||
self.gw('desclabel2').set_markup(enter_secret)
|
||||
|
||||
def _abort(self, text=None, appdata=None):
|
||||
self.smp_running = False
|
||||
|
||||
self.ctx.smpAbort(appdata=appdata)
|
||||
if text:
|
||||
self.plugin.gajim_log(text, self.account, self.ctx.peer)
|
||||
|
||||
def _finish(self, text):
|
||||
self.smp_running = False
|
||||
self.finished = True
|
||||
|
||||
self.gw('qcheckbutton').set_active(False)
|
||||
self.gw('qcheckbutton').hide()
|
||||
self.gw('qentry').hide()
|
||||
self.gw('desclabel2').hide()
|
||||
|
||||
self.gw('qcheckbutton').set_sensitive(False)
|
||||
self.gw('smp_cancel_button').set_sensitive(False)
|
||||
self.gw('smp_ok_button').set_sensitive(True)
|
||||
self.gw('progressbar').set_fraction(1)
|
||||
self.plugin.gajim_log(text, self.account, self.ctx.peer)
|
||||
self.gw('desclabel1').set_markup(text)
|
||||
|
||||
self.plugin.update_otr(self.ctx.peer, self.account, True)
|
||||
self.ctx.user.saveTrusts()
|
||||
self.plugin.update_context_list()
|
||||
|
||||
def get_tlv(self, tlvs, check):
|
||||
print (tlvs, check)
|
||||
for tlv in tlvs:
|
||||
if isinstance(tlv, check):
|
||||
return tlv
|
||||
return None
|
||||
|
||||
def handle_tlv(self, tlvs):
|
||||
if tlvs:
|
||||
is1qtlv = self.get_tlv(tlvs, potr.proto.SMP1QTLV)
|
||||
# check for TLV_SMP_ABORT or state = CHEATED
|
||||
if not self.ctx.smpIsValid():
|
||||
self._abort()
|
||||
self._finish(_('SMP verifying aborted'))
|
||||
|
||||
# check for TLV_SMP1
|
||||
elif self.get_tlv(tlvs, potr.proto.SMP1TLV):
|
||||
self.question = None
|
||||
self.show(True)
|
||||
self.gw('progressbar').set_fraction(0.3)
|
||||
|
||||
# check for TLV_SMP1Q
|
||||
elif is1qtlv:
|
||||
self.question = is1qtlv.msg
|
||||
self.show(True)
|
||||
self.gw('progressbar').set_fraction(0.3)
|
||||
|
||||
# check for TLV_SMP2
|
||||
elif self.get_tlv(tlvs, potr.proto.SMP2TLV):
|
||||
self.gw('progressbar').set_fraction(0.6)
|
||||
|
||||
# check for TLV_SMP3
|
||||
elif self.get_tlv(tlvs, potr.proto.SMP3TLV):
|
||||
if self.ctx.smpIsSuccess():
|
||||
text = _('SMP verifying succeeded')
|
||||
if self.question is not None:
|
||||
text += ' '+another_q
|
||||
self._finish(text)
|
||||
else:
|
||||
self._finish(_('SMP verifying failed'))
|
||||
|
||||
# check for TLV_SMP4
|
||||
elif self.get_tlv(tlvs, potr.proto.SMP4TLV):
|
||||
if self.ctx.smpIsSuccess():
|
||||
text = _('SMP verifying succeeded')
|
||||
if self.question is not None:
|
||||
text += ' '+another_q
|
||||
self._finish(text)
|
||||
else:
|
||||
self._finish(_('SMP verifying failed'))
|
||||
|
||||
def _on_destroy(self, widget):
|
||||
if self.smp_running:
|
||||
self._abort(_('user aborted SMP authentication'))
|
||||
self.window.hide_all()
|
||||
|
||||
def _apply(self, widget, appdata=None):
|
||||
if self.finished:
|
||||
self.window.hide_all()
|
||||
return
|
||||
secret = self.gw('secret_entry').get_text()
|
||||
if self.response:
|
||||
self.ctx.smpGotSecret(secret, appdata=appdata)
|
||||
else:
|
||||
if self.gw('qcheckbutton').get_active():
|
||||
qtext = self.gw('qentry').get_text()
|
||||
self.ctx.smpInit(secret, question=qtext, appdata=appdata)
|
||||
else:
|
||||
self.ctx.smpInit(secret, appdata=appdata)
|
||||
self.gw('progressbar').set_fraction(0.3)
|
||||
self.smp_running = True
|
||||
widget.set_sensitive(False)
|
||||
|
||||
class ContactOtrWindow(gtk.Dialog):
|
||||
def gw(self, n):
|
||||
return self.xml.get_object(n)
|
||||
|
||||
def __init__(self, plugin, ctx, fpr=None, parent=None):
|
||||
fjid = ctx.peer
|
||||
gtk.Dialog.__init__(self, title=_('OTR settings for %s') % fjid,
|
||||
parent=parent,
|
||||
flags=gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
|
||||
gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
|
||||
|
||||
self.ctx = ctx
|
||||
self.fjid = fjid
|
||||
self.jid = gajim.get_room_and_nick_from_fjid(self.fjid)[0]
|
||||
self.account = ctx.user.accountname
|
||||
self.fpr = fpr
|
||||
self.plugin = plugin
|
||||
|
||||
if self.fpr is None:
|
||||
key = self.ctx.getCurrentKey()
|
||||
if key is not None:
|
||||
self.fpr = key.cfingerprint()
|
||||
|
||||
self.GTK_BUILDER_FILE_PATH = \
|
||||
self.plugin.local_file_path('contact_otr_window.ui')
|
||||
self.xml = gtk.Builder()
|
||||
self.xml.set_translation_domain(i18n.APP)
|
||||
self.xml.add_from_file(self.GTK_BUILDER_FILE_PATH)
|
||||
self.notebook = self.gw('otr_settings_notebook')
|
||||
self.child.pack_start(self.notebook)
|
||||
|
||||
self.connect('response', self.on_response)
|
||||
self.gw('otr_default_checkbutton').connect('toggled',
|
||||
self._otr_default_checkbutton_toggled)
|
||||
|
||||
# always set the label containing our fingerprint
|
||||
self.gw('our_fp_label').set_markup(our_fp_text % ctx.user.getPrivkey())
|
||||
|
||||
if self.fpr is None:
|
||||
# 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.fjid,
|
||||
_('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
|
||||
fp = potr.human_hash(self.fpr)
|
||||
self.gw('their_fp_label').set_markup(their_fp_text%(self.fjid, fp))
|
||||
# set the trust combobox
|
||||
if ctx.getCurrentTrust():
|
||||
self.gw('verified_combobox').set_active(1)
|
||||
else:
|
||||
self.gw('verified_combobox').set_active(0)
|
||||
|
||||
otr_flags = self.plugin.get_flags(self.account, self.jid, fallback=False)
|
||||
|
||||
if otr_flags is not None:
|
||||
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 = self.plugin.get_flags(self.account)
|
||||
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_v2_checkbutton').set_active(
|
||||
otr_flags['ALLOW_V2'])
|
||||
self.gw('otr_policy_require_checkbutton').set_active(
|
||||
otr_flags['REQUIRE_ENCRYPTION'])
|
||||
self.gw('otr_policy_send_tag_checkbutton').set_active(
|
||||
otr_flags['SEND_TAG'])
|
||||
self.gw('otr_policy_start_on_tag_checkbutton').set_active(
|
||||
otr_flags['WHITESPACE_START_AKE'])
|
||||
|
||||
self.child.show_all()
|
||||
|
||||
def on_response(self, dlg, response, *args):
|
||||
if response != gtk.RESPONSE_ACCEPT:
|
||||
return
|
||||
|
||||
|
||||
# -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.getTrust(self.fpr):
|
||||
self.ctx.setTrust(self.fpr, 'verified')
|
||||
self.ctx.user.saveTrusts()
|
||||
self.plugin.update_context_list()
|
||||
elif trust_state == 0:
|
||||
self.ctx.setTrust(self.fpr, '')
|
||||
self.ctx.user.saveTrusts()
|
||||
self.plugin.update_context_list()
|
||||
|
||||
self.plugin.update_otr(self.ctx.peer, self.ctx.user.accountname, True)
|
||||
|
||||
if self.gw('otr_default_checkbutton').get_active():
|
||||
# default is enabled, so remove any user-specific
|
||||
# settings if available
|
||||
self.plugin.set_flags(None, self.account, self.jid)
|
||||
else:
|
||||
print "got per-contact settings"
|
||||
# build the flags using the checkboxes
|
||||
flags = {}
|
||||
flags['ALLOW_V2'] = \
|
||||
self.gw('otr_policy_allow_v2_checkbutton').get_active()
|
||||
flags['REQUIRE_ENCRYPTION'] = \
|
||||
self.gw('otr_policy_require_checkbutton').get_active()
|
||||
flags['SEND_TAG'] = \
|
||||
self.gw('otr_policy_send_tag_checkbutton').get_active()
|
||||
flags['WHITESPACE_START_AKE'] = \
|
||||
self.gw('otr_policy_start_on_tag_checkbutton').get_active()
|
||||
|
||||
print "per-contact settings: ", flags
|
||||
self.plugin.set_flags(flags, self.account, self.jid)
|
||||
|
||||
def _otr_default_checkbutton_toggled(self, widget):
|
||||
for w in self.gw('otr_settings_vbox').get_children():
|
||||
w.set_sensitive(not widget.get_active())
|
||||
|
||||
def get_otr_submenu(plugin, control):
|
||||
GTK_BUILDER_FILE_PATH = \
|
||||
plugin.local_file_path('contact_otr_window.ui')
|
||||
xml = gtk.Builder()
|
||||
xml.set_translation_domain(i18n.APP)
|
||||
xml.add_from_file(GTK_BUILDER_FILE_PATH)
|
||||
|
||||
otr_submenu = xml.get_object('otr_submenu')
|
||||
otr_settings_menuitem, smp_otr_menuitem, start_otr_menuitem, \
|
||||
end_otr_menuitem = otr_submenu.get_submenu().get_children()
|
||||
|
||||
otr_submenu.set_sensitive(True)
|
||||
otr_settings_menuitem.connect('activate', plugin.menu_settings_cb, control)
|
||||
start_otr_menuitem.connect('activate', plugin.menu_start_cb, control)
|
||||
end_otr_menuitem.connect('activate', plugin.menu_end_cb, control)
|
||||
smp_otr_menuitem.connect('activate', plugin.menu_smp_cb, control)
|
||||
|
||||
enc, _, fin = plugin.get_otr_status(control.account, control.contact)
|
||||
# can end only when not in PLAINTEXT
|
||||
end_otr_menuitem.set_sensitive(enc)
|
||||
# can SMP only when ENCRYPTED
|
||||
smp_otr_menuitem.set_sensitive(enc and not fin)
|
||||
return otr_submenu
|
||||
Reference in New Issue
Block a user