merge message archiving branch. Fixes #3593
This commit is contained in:
commit
ca43e5441c
|
@ -9,6 +9,13 @@
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkMenuItem" id="archiving_preferences_menuitem">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Edit Archi_ving Preferences</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkMenuItem" id="privacy_lists_menuitem">
|
<object class="GtkMenuItem" id="privacy_lists_menuitem">
|
||||||
<property name="label" translatable="yes">Edit _Privacy Lists...</property>
|
<property name="label" translatable="yes">Edit _Privacy Lists...</property>
|
||||||
|
|
|
@ -0,0 +1,312 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="2.16"/>
|
||||||
|
<!-- interface-naming-policy project-wide -->
|
||||||
|
<object class="GtkListStore" id="liststore1">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name item text -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
<data>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">No</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Yes</col>
|
||||||
|
</row>
|
||||||
|
</data>
|
||||||
|
</object>
|
||||||
|
<object class="GtkListStore" id="liststore2">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name item text -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
<data>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Prefer</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Concede</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Forbid</col>
|
||||||
|
</row>
|
||||||
|
</data>
|
||||||
|
</object>
|
||||||
|
<object class="GtkListStore" id="liststore3">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name item text -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
<data>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Prefer</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Concede</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Forbid</col>
|
||||||
|
</row>
|
||||||
|
</data>
|
||||||
|
</object>
|
||||||
|
<object class="GtkListStore" id="liststore4">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name item text -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
<data>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Prefer</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Concede</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">Forbid</col>
|
||||||
|
</row>
|
||||||
|
</data>
|
||||||
|
</object>
|
||||||
|
<object class="GtkWindow" id="archiving_preferences_window">
|
||||||
|
<property name="border_width">12</property>
|
||||||
|
<signal name="destroy" handler="on_archiving_preferences_window_destroy"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTable" id="table1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="n_rows">4</property>
|
||||||
|
<property name="n_columns">2</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label4">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes"><i>Method Manual</i></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes"><i>Method Local</i></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes"><i>Method Auto</i></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="method_manual_combobox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="model">liststore4</property>
|
||||||
|
<signal name="changed" handler="on_method_foo_combobox_changed"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="cellrenderertext4"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="method_local_combobox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="model">liststore3</property>
|
||||||
|
<signal name="changed" handler="on_method_foo_combobox_changed"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="cellrenderertext3"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="method_auto_combobox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="model">liststore2</property>
|
||||||
|
<signal name="changed" handler="on_method_foo_combobox_changed"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="cellrenderertext2"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label5">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Auto</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="auto_combobox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="model">liststore1</property>
|
||||||
|
<signal name="changed" handler="on_auto_combobox_changed"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="cellrenderertext1"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox2">
|
||||||
|
<property name="visible">True</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="item_treeview">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<signal name="cursor_changed" handler="on_item_treeview_cursor_changed"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHButtonBox" id="hbuttonbox2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="layout_style">spread</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="add_button">
|
||||||
|
<property name="label">gtk-add</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="clicked" handler="on_add_item_button_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="remove_button">
|
||||||
|
<property name="label">gtk-remove</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="clicked" handler="on_remove_item_button_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="edit_button">
|
||||||
|
<property name="label">gtk-edit</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="clicked" handler="on_edit_item_button_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">2</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>
|
||||||
|
<object class="GtkHButtonBox" id="hbuttonbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="layout_style">end</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="close_button">
|
||||||
|
<property name="label">gtk-close</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="can_default">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="clicked" handler="on_close_button_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -0,0 +1,227 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="2.16"/>
|
||||||
|
<!-- interface-naming-policy project-wide -->
|
||||||
|
<object class="GtkWindow" id="item_archiving_preferences_window">
|
||||||
|
<property name="border_width">12</property>
|
||||||
|
<signal name="destroy" handler="on_item_archiving_preferences_window_destroy"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTable" id="table3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="n_rows">4</property>
|
||||||
|
<property name="n_columns">2</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label8">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">expire</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="expire_entry">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">•</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="otr_combobox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="model">liststore2</property>
|
||||||
|
<signal name="changed" handler="on_otr_combobox_changed"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="cellrenderertext2"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="save_combobox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="model">liststore1</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="cellrenderertext1"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label10">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">save</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label9">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">otr</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="label1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">jid</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="jid_entry">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">•</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkProgressBar" id="progressbar"/>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHButtonBox" id="hbuttonbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="layout_style">end</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="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>
|
||||||
|
<signal name="clicked" handler="on_cancel_button_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="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>
|
||||||
|
<signal name="clicked" handler="on_ok_button_clicked"/>
|
||||||
|
</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="GtkListStore" id="liststore1">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name item text -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
<data>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">body</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">false</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">message</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">stream</col>
|
||||||
|
</row>
|
||||||
|
</data>
|
||||||
|
</object>
|
||||||
|
<object class="GtkListStore" id="liststore2">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name item text -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
<data>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">approve</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">concede</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">forbid</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">oppose</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">prefer</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0" translatable="yes">require</col>
|
||||||
|
</row>
|
||||||
|
</data>
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -46,6 +46,7 @@ from common import exceptions
|
||||||
from message_control import MessageControl
|
from message_control import MessageControl
|
||||||
from conversation_textview import ConversationTextview
|
from conversation_textview import ConversationTextview
|
||||||
from message_textview import MessageTextView
|
from message_textview import MessageTextView
|
||||||
|
from common.stanza_session import EncryptedStanzaSession, ArchivingStanzaSession
|
||||||
from common.contacts import GC_Contact
|
from common.contacts import GC_Contact
|
||||||
from common.logger import constants
|
from common.logger import constants
|
||||||
from common.pep import MOODS, ACTIVITIES
|
from common.pep import MOODS, ACTIVITIES
|
||||||
|
@ -2202,6 +2203,18 @@ class ChatControl(ChatControlBase):
|
||||||
msg = _('Session negotiation cancelled')
|
msg = _('Session negotiation cancelled')
|
||||||
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
||||||
|
|
||||||
|
def print_archiving_session_details(self):
|
||||||
|
"""
|
||||||
|
Print esession settings to textview
|
||||||
|
"""
|
||||||
|
archiving = bool(self.session) and isinstance(self.session,
|
||||||
|
ArchivingStanzaSession) and self.session.archiving
|
||||||
|
if archiving:
|
||||||
|
msg = _('This session WILL be archived on server')
|
||||||
|
else:
|
||||||
|
msg = _('This session WILL NOT be archived on server')
|
||||||
|
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
||||||
|
|
||||||
def print_esession_details(self):
|
def print_esession_details(self):
|
||||||
"""
|
"""
|
||||||
Print esession settings to textview
|
Print esession settings to textview
|
||||||
|
@ -2226,6 +2239,12 @@ class ChatControl(ChatControlBase):
|
||||||
self._show_lock_image(e2e_is_active, 'E2E', e2e_is_active, self.session and \
|
self._show_lock_image(e2e_is_active, 'E2E', e2e_is_active, self.session and \
|
||||||
self.session.is_loggable(), self.session and self.session.verified_identity)
|
self.session.is_loggable(), self.session and self.session.verified_identity)
|
||||||
|
|
||||||
|
def print_session_details(self):
|
||||||
|
if isinstance(self.session, EncryptedStanzaSession):
|
||||||
|
self.print_esession_details()
|
||||||
|
elif isinstance(self.session, ArchivingStanzaSession):
|
||||||
|
self.print_archiving_session_details()
|
||||||
|
|
||||||
def print_conversation(self, text, frm='', tim=None, encrypted=False,
|
def print_conversation(self, text, frm='', tim=None, encrypted=False,
|
||||||
subject=None, xhtml=None, simple=False, xep0184_id=None,
|
subject=None, xhtml=None, simple=False, xep0184_id=None,
|
||||||
displaymarking=None):
|
displaymarking=None):
|
||||||
|
@ -2658,6 +2677,8 @@ class ChatControl(ChatControlBase):
|
||||||
if want_e2e and not self.no_autonegotiation \
|
if want_e2e and not self.no_autonegotiation \
|
||||||
and gajim.HAVE_PYCRYPTO and self.contact.supports(NS_ESESSION):
|
and gajim.HAVE_PYCRYPTO and self.contact.supports(NS_ESESSION):
|
||||||
self.begin_e2e_negotiation()
|
self.begin_e2e_negotiation()
|
||||||
|
elif not self.session or not self.session.status:
|
||||||
|
self.begin_archiving_negotiation()
|
||||||
else:
|
else:
|
||||||
self.send_chatstate('active', self.contact)
|
self.send_chatstate('active', self.contact)
|
||||||
|
|
||||||
|
@ -2901,7 +2922,7 @@ class ChatControl(ChatControlBase):
|
||||||
else:
|
else:
|
||||||
self.begin_e2e_negotiation()
|
self.begin_e2e_negotiation()
|
||||||
|
|
||||||
def begin_e2e_negotiation(self):
|
def begin_negotiation(self):
|
||||||
self.no_autonegotiation = True
|
self.no_autonegotiation = True
|
||||||
|
|
||||||
if not self.session:
|
if not self.session:
|
||||||
|
@ -2909,8 +2930,14 @@ class ChatControl(ChatControlBase):
|
||||||
new_sess = gajim.connections[self.account].make_new_session(fjid, type_=self.type_id)
|
new_sess = gajim.connections[self.account].make_new_session(fjid, type_=self.type_id)
|
||||||
self.set_session(new_sess)
|
self.set_session(new_sess)
|
||||||
|
|
||||||
|
def begin_e2e_negotiation(self):
|
||||||
|
self.begin_negotiation()
|
||||||
self.session.negotiate_e2e(False)
|
self.session.negotiate_e2e(False)
|
||||||
|
|
||||||
|
def begin_archiving_negotiation(self):
|
||||||
|
self.begin_negotiation()
|
||||||
|
self.session.negotiate_archiving()
|
||||||
|
|
||||||
def got_connected(self):
|
def got_connected(self):
|
||||||
ChatControlBase.got_connected(self)
|
ChatControlBase.got_connected(self)
|
||||||
# Refreshing contact
|
# Refreshing contact
|
||||||
|
|
|
@ -371,6 +371,7 @@ class Config:
|
||||||
'send_idle_time': [ opt_bool, True ],
|
'send_idle_time': [ opt_bool, True ],
|
||||||
'roster_version': [opt_str, ''],
|
'roster_version': [opt_str, ''],
|
||||||
'subscription_request_msg': [opt_str, '', _('Message that is sent to contacts you want to add')],
|
'subscription_request_msg': [opt_str, '', _('Message that is sent to contacts you want to add')],
|
||||||
|
'last_archiving_time': [opt_str, '1970-01-01T00:00:00Z', _('Last time we syncronized with logs from server.')],
|
||||||
}, {}),
|
}, {}),
|
||||||
'statusmsg': ({
|
'statusmsg': ({
|
||||||
'message': [ opt_str, '' ],
|
'message': [ opt_str, '' ],
|
||||||
|
|
|
@ -153,6 +153,7 @@ class CommonConnection:
|
||||||
self.privacy_rules_supported = False
|
self.privacy_rules_supported = False
|
||||||
self.vcard_supported = False
|
self.vcard_supported = False
|
||||||
self.private_storage_supported = False
|
self.private_storage_supported = False
|
||||||
|
self.archive_pref_supported = False
|
||||||
|
|
||||||
self.muc_jid = {} # jid of muc server for each transport type
|
self.muc_jid = {} # jid of muc server for each transport type
|
||||||
self._stun_servers = [] # STUN servers of our jabber server
|
self._stun_servers = [] # STUN servers of our jabber server
|
||||||
|
@ -1541,6 +1542,9 @@ class Connection(CommonConnection, ConnectionHandlers):
|
||||||
self.connection.set_send_timeout(self.keepalives, self.send_keepalive)
|
self.connection.set_send_timeout(self.keepalives, self.send_keepalive)
|
||||||
self.connection.set_send_timeout2(self.pingalives, self.sendPing)
|
self.connection.set_send_timeout2(self.pingalives, self.sendPing)
|
||||||
self.connection.onreceive(None)
|
self.connection.onreceive(None)
|
||||||
|
|
||||||
|
self.request_message_archiving_preferences()
|
||||||
|
|
||||||
self.discoverInfo(gajim.config.get_per('accounts', self.name, 'hostname'),
|
self.discoverInfo(gajim.config.get_per('accounts', self.name, 'hostname'),
|
||||||
id_prefix='Gajim_')
|
id_prefix='Gajim_')
|
||||||
self.privacy_rules_requested = False
|
self.privacy_rules_requested = False
|
||||||
|
|
|
@ -51,6 +51,11 @@ from common.pubsub import ConnectionPubSub
|
||||||
from common.pep import ConnectionPEP
|
from common.pep import ConnectionPEP
|
||||||
from common.protocol.caps import ConnectionCaps
|
from common.protocol.caps import ConnectionCaps
|
||||||
from common.protocol.bytestream import ConnectionSocks5Bytestream
|
from common.protocol.bytestream import ConnectionSocks5Bytestream
|
||||||
|
from common.message_archiving import ConnectionArchive
|
||||||
|
from common.message_archiving import ARCHIVING_COLLECTIONS_ARRIVED
|
||||||
|
from common.message_archiving import ARCHIVING_COLLECTION_ARRIVED
|
||||||
|
from common.message_archiving import ARCHIVING_MODIFICATIONS_ARRIVED
|
||||||
|
|
||||||
from common import ged
|
from common import ged
|
||||||
from common import nec
|
from common import nec
|
||||||
from common.nec import NetworkEvent
|
from common.nec import NetworkEvent
|
||||||
|
@ -363,6 +368,14 @@ class ConnectionDisco:
|
||||||
our_jid = gajim.get_jid_from_account(self.name)
|
our_jid = gajim.get_jid_from_account(self.name)
|
||||||
self.send_pb_purge(our_jid, 'storage:bookmarks')
|
self.send_pb_purge(our_jid, 'storage:bookmarks')
|
||||||
self.send_pb_delete(our_jid, 'storage:bookmarks')
|
self.send_pb_delete(our_jid, 'storage:bookmarks')
|
||||||
|
if features.__contains__(common.xmpp.NS_ARCHIVE_AUTO):
|
||||||
|
self.archive_auto_supported = True
|
||||||
|
if features.__contains__(common.xmpp.NS_ARCHIVE_MANAGE):
|
||||||
|
self.archive_manage_supported = True
|
||||||
|
if features.__contains__(common.xmpp.NS_ARCHIVE_MANUAL):
|
||||||
|
self.archive_manual_supported = True
|
||||||
|
if features.__contains__(common.xmpp.NS_ARCHIVE_PREF):
|
||||||
|
self.archive_pref_supported = True
|
||||||
if features.__contains__(common.xmpp.NS_BYTESTREAM):
|
if features.__contains__(common.xmpp.NS_BYTESTREAM):
|
||||||
our_jid = helpers.parse_jid(gajim.get_jid_from_account(self.name) +\
|
our_jid = helpers.parse_jid(gajim.get_jid_from_account(self.name) +\
|
||||||
'/' + self.server_resource)
|
'/' + self.server_resource)
|
||||||
|
@ -701,6 +714,71 @@ class ConnectionVcard:
|
||||||
form = common.dataforms.ExtendForm(node=form_tag)
|
form = common.dataforms.ExtendForm(node=form_tag)
|
||||||
self.dispatch('PEP_CONFIG', (node, form))
|
self.dispatch('PEP_CONFIG', (node, form))
|
||||||
|
|
||||||
|
elif self.awaiting_answers[id_][0] == ARCHIVING_COLLECTIONS_ARRIVED:
|
||||||
|
# TODO
|
||||||
|
print 'ARCHIVING_COLLECTIONS_ARRIVED'
|
||||||
|
pass
|
||||||
|
|
||||||
|
elif self.awaiting_answers[id_][0] == ARCHIVING_COLLECTION_ARRIVED:
|
||||||
|
def save_if_not_exists(with_, nick, direction, tim, payload):
|
||||||
|
assert len(payload) == 1, 'got several archiving messages in' +\
|
||||||
|
' the same time %s' % ''.join(payload)
|
||||||
|
if payload[0].getName() == 'body':
|
||||||
|
gajim.logger.save_if_not_exists(with_, direction, tim,
|
||||||
|
msg=payload[0].getData(), nick=nick)
|
||||||
|
elif payload[0].getName() == 'message':
|
||||||
|
print 'Not implemented'
|
||||||
|
chat = iq_obj.getTag('chat')
|
||||||
|
if chat:
|
||||||
|
with_ = chat.getAttr('with')
|
||||||
|
start_ = chat.getAttr('start')
|
||||||
|
tim = helpers.datetime_tuple(start_)
|
||||||
|
tim = timegm(tim)
|
||||||
|
nb = 0
|
||||||
|
for element in chat.getChildren():
|
||||||
|
try:
|
||||||
|
secs = int(element.getAttr('secs'))
|
||||||
|
except TypeError:
|
||||||
|
secs = 0
|
||||||
|
if secs:
|
||||||
|
tim += secs
|
||||||
|
nick = element.getAttr('name')
|
||||||
|
if element.getName() == 'from':
|
||||||
|
save_if_not_exists(with_, nick, 'from', localtime(tim),
|
||||||
|
element.getPayload())
|
||||||
|
nb += 1
|
||||||
|
if element.getName() == 'to':
|
||||||
|
save_if_not_exists(with_, nick, 'to', localtime(tim),
|
||||||
|
element.getPayload())
|
||||||
|
nb += 1
|
||||||
|
set_ = chat.getTag('set')
|
||||||
|
first = set_.getTag('first')
|
||||||
|
if first:
|
||||||
|
try:
|
||||||
|
index = int(first.getAttr('index'))
|
||||||
|
except TypeError:
|
||||||
|
index = 0
|
||||||
|
try:
|
||||||
|
count = int(set_.getTagData('count'))
|
||||||
|
except TypeError:
|
||||||
|
count = 0
|
||||||
|
if count > index + nb:
|
||||||
|
# Request the next page
|
||||||
|
after = element.getTagData('last')
|
||||||
|
self.request_collection_page(with_, start_, after=after)
|
||||||
|
|
||||||
|
elif self.awaiting_answers[id_][0] == ARCHIVING_MODIFICATIONS_ARRIVED:
|
||||||
|
modified = iq_obj.getTag('modified')
|
||||||
|
if modified:
|
||||||
|
for element in modified.getChildren():
|
||||||
|
if element.getName() == 'changed':
|
||||||
|
with_ = element.getAttr('with')
|
||||||
|
start_ = element.getAttr('start')
|
||||||
|
self.request_collection_page(with_, start_)
|
||||||
|
elif element.getName() == 'removed':
|
||||||
|
# do nothing
|
||||||
|
pass
|
||||||
|
|
||||||
del self.awaiting_answers[id_]
|
del self.awaiting_answers[id_]
|
||||||
|
|
||||||
def _vCardCB(self, con, vc):
|
def _vCardCB(self, con, vc):
|
||||||
|
@ -955,11 +1033,13 @@ class ConnectionHandlersBase:
|
||||||
|
|
||||||
return sess
|
return sess
|
||||||
|
|
||||||
class ConnectionHandlers(ConnectionVcard, ConnectionSocks5Bytestream,
|
class ConnectionHandlers(ConnectionArchive, ConnectionVcard,
|
||||||
ConnectionDisco, ConnectionCommands, ConnectionPubSub, ConnectionPEP,
|
ConnectionSocks5Bytestream, ConnectionDisco, ConnectionCommands,
|
||||||
ConnectionCaps, ConnectionHandlersBase, ConnectionJingle):
|
ConnectionPubSub, ConnectionPEP, ConnectionCaps, ConnectionHandlersBase,
|
||||||
|
ConnectionJingle):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
global HAS_IDLE
|
global HAS_IDLE
|
||||||
|
ConnectionArchive.__init__(self)
|
||||||
ConnectionVcard.__init__(self)
|
ConnectionVcard.__init__(self)
|
||||||
ConnectionSocks5Bytestream.__init__(self)
|
ConnectionSocks5Bytestream.__init__(self)
|
||||||
ConnectionCommands.__init__(self)
|
ConnectionCommands.__init__(self)
|
||||||
|
@ -2303,6 +2383,7 @@ ConnectionCaps, ConnectionHandlersBase, ConnectionJingle):
|
||||||
common.xmpp.NS_SEARCH)
|
common.xmpp.NS_SEARCH)
|
||||||
con.RegisterHandler('iq', self._PrivacySetCB, 'set',
|
con.RegisterHandler('iq', self._PrivacySetCB, 'set',
|
||||||
common.xmpp.NS_PRIVACY)
|
common.xmpp.NS_PRIVACY)
|
||||||
|
con.RegisterHandler('iq', self._ArchiveCB, ns=common.xmpp.NS_ARCHIVE)
|
||||||
con.RegisterHandler('iq', self._PubSubCB, 'result')
|
con.RegisterHandler('iq', self._PubSubCB, 'result')
|
||||||
con.RegisterHandler('iq', self._PubSubErrorCB, 'error')
|
con.RegisterHandler('iq', self._PubSubErrorCB, 'error')
|
||||||
con.RegisterHandler('iq', self._JingleCB, 'result')
|
con.RegisterHandler('iq', self._JingleCB, 'result')
|
||||||
|
|
|
@ -45,6 +45,9 @@ LOG_DB_PATH = configpaths.gajimpaths['LOG_DB']
|
||||||
LOG_DB_FOLDER, LOG_DB_FILE = os.path.split(LOG_DB_PATH)
|
LOG_DB_FOLDER, LOG_DB_FILE = os.path.split(LOG_DB_PATH)
|
||||||
CACHE_DB_PATH = configpaths.gajimpaths['CACHE_DB']
|
CACHE_DB_PATH = configpaths.gajimpaths['CACHE_DB']
|
||||||
|
|
||||||
|
import logging
|
||||||
|
log = logging.getLogger('gajim.c.logger')
|
||||||
|
|
||||||
class Constants:
|
class Constants:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
(
|
(
|
||||||
|
@ -142,7 +145,7 @@ class Logger:
|
||||||
try:
|
try:
|
||||||
self.cur.execute("ATTACH DATABASE '%s' AS cache" % CACHE_DB_PATH)
|
self.cur.execute("ATTACH DATABASE '%s' AS cache" % CACHE_DB_PATH)
|
||||||
except sqlite.Error, e:
|
except sqlite.Error, e:
|
||||||
gajim.log.debug("Failed to attach cache database: %s" % str(e))
|
log.debug("Failed to attach cache database: %s" % str(e))
|
||||||
|
|
||||||
def set_synchronous(self, sync):
|
def set_synchronous(self, sync):
|
||||||
try:
|
try:
|
||||||
|
@ -151,7 +154,7 @@ class Logger:
|
||||||
else:
|
else:
|
||||||
self.cur.execute("PRAGMA synchronous = OFF")
|
self.cur.execute("PRAGMA synchronous = OFF")
|
||||||
except sqlite.Error, e:
|
except sqlite.Error, e:
|
||||||
gajim.log.debug("Failed to set_synchronous(%s): %s" % (sync, str(e)))
|
log.debug("Failed to set_synchronous(%s): %s" % (sync, str(e)))
|
||||||
|
|
||||||
def init_vars(self):
|
def init_vars(self):
|
||||||
self.open_db()
|
self.open_db()
|
||||||
|
@ -1053,3 +1056,48 @@ class Logger:
|
||||||
self.cur.execute('DELETE FROM roster_group WHERE account_jid_id=?',
|
self.cur.execute('DELETE FROM roster_group WHERE account_jid_id=?',
|
||||||
(account_jid_id,))
|
(account_jid_id,))
|
||||||
self.con.commit()
|
self.con.commit()
|
||||||
|
|
||||||
|
def save_if_not_exists(self, with_, direction, tim, msg='', nick=None):
|
||||||
|
if tim:
|
||||||
|
time_col = int(float(time.mktime(tim)))
|
||||||
|
else:
|
||||||
|
time_col = int(float(time.time()))
|
||||||
|
if msg:
|
||||||
|
if self.jid_is_from_pm(with_) or nick:
|
||||||
|
# It's a groupchat message
|
||||||
|
if nick:
|
||||||
|
# It's a message from a groupchat occupent
|
||||||
|
type_ = 'gc_msg'
|
||||||
|
with_ = with_ + '/' + nick
|
||||||
|
else:
|
||||||
|
# It's a server message message, we don't log them
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
if direction == 'from':
|
||||||
|
type_ = 'chat_msg_recv'
|
||||||
|
elif direction == 'to':
|
||||||
|
type_ = 'chat_msg_sent'
|
||||||
|
jid_id = self.get_jid_id(with_)
|
||||||
|
where_sql = 'jid_id = %s AND message=?' % jid_id
|
||||||
|
if type_ == 'gc_msg':
|
||||||
|
# We cannot differentiate gc message and pm messages, so look in
|
||||||
|
# both logs
|
||||||
|
with_2 = gajim.get_jid_without_resource(with_)
|
||||||
|
if with_ != with_2:
|
||||||
|
jid_id2 = self.get_jid_id(with_2)
|
||||||
|
where_sql = 'jid_id in (%s, %s) AND message=?' % (jid_id,
|
||||||
|
jid_id2)
|
||||||
|
start_time = time_col - 300 # 5 minutes arrount given time
|
||||||
|
end_time = time_col + 300 # 5 minutes arrount given time
|
||||||
|
self.cur.execute('''
|
||||||
|
SELECT log_line_id FROM logs
|
||||||
|
WHERE (%s)
|
||||||
|
AND time BETWEEN %d AND %d
|
||||||
|
ORDER BY time
|
||||||
|
''' % (where_sql, start_time, end_time), (msg,))
|
||||||
|
results = self.cur.fetchall()
|
||||||
|
if results:
|
||||||
|
log.debug('Log already in DB, ignoring it')
|
||||||
|
return
|
||||||
|
log.debug('New log received from server archives, storing it')
|
||||||
|
self.write(type_, with_, message=msg, tim=tim)
|
||||||
|
|
|
@ -0,0 +1,258 @@
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
## src/common/message_archiving.py
|
||||||
|
##
|
||||||
|
## Copyright (C) 2009 Anaël Verrier <elghinn AT free.fr>
|
||||||
|
##
|
||||||
|
## 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 common.xmpp
|
||||||
|
|
||||||
|
import logging
|
||||||
|
log = logging.getLogger('gajim.c.message_archiving')
|
||||||
|
|
||||||
|
ARCHIVING_COLLECTIONS_ARRIVED = 'archiving_collections_arrived'
|
||||||
|
ARCHIVING_COLLECTION_ARRIVED = 'archiving_collection_arrived'
|
||||||
|
ARCHIVING_MODIFICATIONS_ARRIVED = 'archiving_modifications_arrived'
|
||||||
|
|
||||||
|
class ConnectionArchive:
|
||||||
|
def __init__(self):
|
||||||
|
self.archive_auto_supported = False
|
||||||
|
self.archive_manage_supported = False
|
||||||
|
self.archive_manual_supported = False
|
||||||
|
self.archive_pref_supported = False
|
||||||
|
self.auto = None
|
||||||
|
self.method_auto = None
|
||||||
|
self.method_local = None
|
||||||
|
self.method_manual = None
|
||||||
|
self.default = None
|
||||||
|
self.items = {}
|
||||||
|
|
||||||
|
def request_message_archiving_preferences(self):
|
||||||
|
iq_ = common.xmpp.Iq('get')
|
||||||
|
iq_.setTag('pref', namespace=common.xmpp.NS_ARCHIVE)
|
||||||
|
self.connection.send(iq_)
|
||||||
|
|
||||||
|
def set_pref(self, name, **data):
|
||||||
|
'''
|
||||||
|
data contains names and values of pref name attributes.
|
||||||
|
'''
|
||||||
|
iq_ = common.xmpp.Iq('set')
|
||||||
|
pref = iq_.setTag('pref', namespace=common.xmpp.NS_ARCHIVE)
|
||||||
|
tag = pref.setTag(name)
|
||||||
|
for key, value in data.items():
|
||||||
|
if value is not None:
|
||||||
|
tag.setAttr(key, value)
|
||||||
|
self.connection.send(iq_)
|
||||||
|
|
||||||
|
def set_auto(self, save):
|
||||||
|
self.set_pref('auto', save=save)
|
||||||
|
|
||||||
|
def set_method(self, type, use):
|
||||||
|
self.set_pref('method', type=type, use=use)
|
||||||
|
|
||||||
|
def set_default(self, otr, save, expire=None):
|
||||||
|
self.set_pref('default', otr=otr, save=save, expire=expire)
|
||||||
|
|
||||||
|
def append_or_update_item(self, jid, otr, save, expire):
|
||||||
|
self.set_pref('item', jid=jid, otr=otr, save=save)
|
||||||
|
|
||||||
|
def remove_item(self, jid):
|
||||||
|
iq_ = common.xmpp.Iq('set')
|
||||||
|
itemremove = iq_.setTag('itemremove', namespace=common.xmpp.NS_ARCHIVE)
|
||||||
|
item = itemremove.setTag('item')
|
||||||
|
item.setAttr('jid', jid)
|
||||||
|
self.connection.send(iq_)
|
||||||
|
|
||||||
|
def stop_archiving_session(self, thread_id):
|
||||||
|
iq_ = common.xmpp.Iq('set')
|
||||||
|
pref = iq_.setTag('pref', namespace=common.xmpp.NS_ARCHIVE)
|
||||||
|
session = pref.setTag('session', attrs={'thread': thread_id,
|
||||||
|
'save': 'false', 'otr': 'concede'})
|
||||||
|
self.connection.send(iq_)
|
||||||
|
|
||||||
|
def get_item_pref(self, jid):
|
||||||
|
jid = common.xmpp.JID(jid)
|
||||||
|
if unicode(jid) in self.items:
|
||||||
|
return self.items[jid]
|
||||||
|
|
||||||
|
if jid.getStripped() in self.items:
|
||||||
|
return self.items[jid.getStripped()]
|
||||||
|
|
||||||
|
if jid.getDomain() in self.items:
|
||||||
|
return self.items[jid.getDomain()]
|
||||||
|
|
||||||
|
return self.default
|
||||||
|
|
||||||
|
def logging_preference(self, jid, initiator_options=None):
|
||||||
|
otr = self.get_item_pref(jid)['otr']
|
||||||
|
if initiator_options:
|
||||||
|
if ((initiator_options == ['mustnot'] and otr == 'forbid') or
|
||||||
|
(initiator_options == ['may'] and otr == 'require')):
|
||||||
|
return None
|
||||||
|
|
||||||
|
if (initiator_options == ['mustnot'] or
|
||||||
|
(initiator_options[0] == 'mustnot' and
|
||||||
|
otr not in ('opppose', 'forbid')) or
|
||||||
|
(initiator_options == ['may', 'mustnot'] and
|
||||||
|
otr in ('require', 'prefer'))):
|
||||||
|
return 'mustnot'
|
||||||
|
|
||||||
|
return 'may'
|
||||||
|
|
||||||
|
if otr == 'require':
|
||||||
|
return ['mustnot']
|
||||||
|
|
||||||
|
if otr in ('prefer', 'approve'):
|
||||||
|
return ['mustnot', 'may']
|
||||||
|
|
||||||
|
if otr in ('concede', 'oppose'):
|
||||||
|
return ['may', 'mustnot']
|
||||||
|
|
||||||
|
# otr == 'forbid'
|
||||||
|
return ['may']
|
||||||
|
|
||||||
|
def _ArchiveCB(self, con, iq_obj):
|
||||||
|
log.debug('_ArchiveCB %s' % iq_obj.getType())
|
||||||
|
if iq_obj.getType() == 'error':
|
||||||
|
self.dispatch('ARCHIVING_ERROR', iq_obj.getErrorMsg())
|
||||||
|
return
|
||||||
|
elif iq_obj.getType() not in ('result', 'set'):
|
||||||
|
return
|
||||||
|
|
||||||
|
if iq_obj.getTag('pref'):
|
||||||
|
pref = iq_obj.getTag('pref')
|
||||||
|
|
||||||
|
if pref.getTag('auto'):
|
||||||
|
self.auto = pref.getTagAttr('auto', 'save')
|
||||||
|
log.debug('archiving preference: auto: %s' % self.auto)
|
||||||
|
self.dispatch('ARCHIVING_CHANGED', ('auto',
|
||||||
|
self.auto))
|
||||||
|
|
||||||
|
method_auto = pref.getTag('method', attrs={'type': 'auto'})
|
||||||
|
if method_auto:
|
||||||
|
self.method_auto = method_auto.getAttr('use')
|
||||||
|
self.dispatch('ARCHIVING_CHANGED', ('method_auto',
|
||||||
|
self.method_auto))
|
||||||
|
|
||||||
|
method_local = pref.getTag('method', attrs={'type': 'local'})
|
||||||
|
if method_local:
|
||||||
|
self.method_local = method_local.getAttr('use')
|
||||||
|
self.dispatch('ARCHIVING_CHANGED', ('method_local',
|
||||||
|
self.method_local))
|
||||||
|
|
||||||
|
method_manual = pref.getTag('method', attrs={'type': 'manual'})
|
||||||
|
if method_manual:
|
||||||
|
self.method_manual = method_manual.getAttr('use')
|
||||||
|
self.dispatch('ARCHIVING_CHANGED', ('method_manual',
|
||||||
|
self.method_manual))
|
||||||
|
|
||||||
|
log.debug('archiving preferences: method auto: %s, local: %s, '
|
||||||
|
'manual: %s' % (self.method_auto, self.method_local,
|
||||||
|
self.method_manual))
|
||||||
|
|
||||||
|
if pref.getTag('default'):
|
||||||
|
default = pref.getTag('default')
|
||||||
|
log.debug('archiving preferences: default otr: %s, save: %s, '
|
||||||
|
'expire: %s, unset: %s' % (default.getAttr('otr'),
|
||||||
|
default.getAttr('save'), default.getAttr('expire'),
|
||||||
|
default.getAttr('unset')))
|
||||||
|
self.default = {
|
||||||
|
'expire': default.getAttr('expire'),
|
||||||
|
'otr': default.getAttr('otr'),
|
||||||
|
'save': default.getAttr('save'),
|
||||||
|
'unset': default.getAttr('unset')}
|
||||||
|
self.dispatch('ARCHIVING_CHANGED', ('default',
|
||||||
|
self.default))
|
||||||
|
for item in pref.getTags('item'):
|
||||||
|
log.debug('archiving preferences for jid %s: otr: %s, save: %s, '
|
||||||
|
'expire: %s' % (item.getAttr('jid'), item.getAttr('otr'),
|
||||||
|
item.getAttr('save'), item.getAttr('expire')))
|
||||||
|
self.items[item.getAttr('jid')] = {
|
||||||
|
'expire': item.getAttr('expire'),
|
||||||
|
'otr': item.getAttr('otr'), 'save': item.getAttr('save')}
|
||||||
|
self.dispatch('ARCHIVING_CHANGED', ('item',
|
||||||
|
item.getAttr('jid'), self.items[item.getAttr('jid')]))
|
||||||
|
elif iq_obj.getTag('itemremove'):
|
||||||
|
for item in pref.getTags('item'):
|
||||||
|
del self.items[item.getAttr('jid')]
|
||||||
|
self.dispatch('ARCHIVING_CHANGED', ('itemremove',
|
||||||
|
item.getAttr('jid')))
|
||||||
|
|
||||||
|
raise common.xmpp.NodeProcessed
|
||||||
|
|
||||||
|
def request_collections_list_page(self, with_='', start=None, end=None,
|
||||||
|
after=None, max=30, exact_match=False):
|
||||||
|
iq_ = common.xmpp.Iq('get')
|
||||||
|
list_ = iq_.setTag('list', namespace=common.xmpp.NS_ARCHIVE)
|
||||||
|
if with_:
|
||||||
|
list_.setAttr('with', with_)
|
||||||
|
if exact_match:
|
||||||
|
list_.setAttr('exactmatch', 'true')
|
||||||
|
if start:
|
||||||
|
list_.setAttr('start', start)
|
||||||
|
if end:
|
||||||
|
list_.setAttr('end', end)
|
||||||
|
set_ = list_.setTag('set', namespace=common.xmpp.NS_RSM)
|
||||||
|
set_.setTagData('max', max)
|
||||||
|
if after:
|
||||||
|
set_.setTagData('after', after)
|
||||||
|
id_ = self.connection.getAnID()
|
||||||
|
iq_.setID(id_)
|
||||||
|
self.awaiting_answers[id_] = (ARCHIVING_COLLECTIONS_ARRIVED, )
|
||||||
|
self.connection.send(iq_)
|
||||||
|
|
||||||
|
def request_collection_page(self, with_, start, end=None, after=None,
|
||||||
|
max=30, exact_match=False):
|
||||||
|
iq_ = common.xmpp.Iq('get')
|
||||||
|
retrieve = iq_.setTag('retrieve', namespace=common.xmpp.NS_ARCHIVE,
|
||||||
|
attrs={'with': with_, 'start': start})
|
||||||
|
if exact_match:
|
||||||
|
retrieve.setAttr('exactmatch', 'true')
|
||||||
|
set_ = retrieve.setTag('set', namespace=common.xmpp.NS_RSM)
|
||||||
|
set_.setTagData('max', max)
|
||||||
|
if after:
|
||||||
|
set_.setTagData('after', after)
|
||||||
|
id_ = self.connection.getAnID()
|
||||||
|
iq_.setID(id_)
|
||||||
|
self.awaiting_answers[id_] = (ARCHIVING_COLLECTION_ARRIVED, )
|
||||||
|
self.connection.send(iq_)
|
||||||
|
|
||||||
|
def remove_collection(self, with_='', start=None, end=None,
|
||||||
|
exact_match=False, open=False):
|
||||||
|
iq_ = common.xmpp.Iq('set')
|
||||||
|
remove = iq_.setTag('remove', namespace=common.xmpp.NS_ARCHIVE)
|
||||||
|
if with_:
|
||||||
|
remove.setAttr('with', with_)
|
||||||
|
if exact_match:
|
||||||
|
remove.setAttr('exactmatch', 'true')
|
||||||
|
if start:
|
||||||
|
remove.setAttr('start', start)
|
||||||
|
if end:
|
||||||
|
remove.setAttr('end', end)
|
||||||
|
if open:
|
||||||
|
remove.setAttr('open', 'true')
|
||||||
|
self.connection.send(iq_)
|
||||||
|
|
||||||
|
def request_modifications_page(self, start, max=30):
|
||||||
|
iq_ = common.xmpp.Iq('get')
|
||||||
|
moified = iq_.setTag('modified', namespace=common.xmpp.NS_ARCHIVE,
|
||||||
|
attrs={'start': start})
|
||||||
|
set_ = moified.setTag('set', namespace=common.xmpp.NS_RSM)
|
||||||
|
set_.setTagData('max', max)
|
||||||
|
id_ = self.connection.getAnID()
|
||||||
|
iq_.setID(id_)
|
||||||
|
self.awaiting_answers[id_] = (ARCHIVING_MODIFICATIONS_ARRIVED, )
|
||||||
|
self.connection.send(iq_)
|
|
@ -175,7 +175,123 @@ class StanzaSession(object):
|
||||||
self.status = None
|
self.status = None
|
||||||
|
|
||||||
|
|
||||||
class EncryptedStanzaSession(StanzaSession):
|
class ArchivingStanzaSession(StanzaSession):
|
||||||
|
def __init__(self, conn, jid, thread_id, type_='chat'):
|
||||||
|
StanzaSession.__init__(self, conn, jid, thread_id, type_='chat')
|
||||||
|
self.archiving = False
|
||||||
|
|
||||||
|
def archiving_logging_preference(self, initiator_options=None):
|
||||||
|
return self.conn.logging_preference(self.jid, initiator_options)
|
||||||
|
|
||||||
|
def negotiate_archiving(self):
|
||||||
|
self.negotiated = {}
|
||||||
|
|
||||||
|
request = xmpp.Message()
|
||||||
|
feature = request.NT.feature
|
||||||
|
feature.setNamespace(xmpp.NS_FEATURE)
|
||||||
|
|
||||||
|
x = xmpp.DataForm(typ='form')
|
||||||
|
|
||||||
|
x.addChild(node=xmpp.DataField(name='FORM_TYPE', value='urn:xmpp:ssn',
|
||||||
|
typ='hidden'))
|
||||||
|
x.addChild(node=xmpp.DataField(name='accept', value='1', typ='boolean',
|
||||||
|
required=True))
|
||||||
|
|
||||||
|
x.addChild(node=xmpp.DataField(name='logging', typ='list-single',
|
||||||
|
options=self.archiving_logging_preference(), required=True))
|
||||||
|
|
||||||
|
x.addChild(node=xmpp.DataField(name='disclosure', typ='list-single',
|
||||||
|
options=['never'], required=True))
|
||||||
|
x.addChild(node=xmpp.DataField(name='security', typ='list-single',
|
||||||
|
options=['none'], required=True))
|
||||||
|
|
||||||
|
feature.addChild(node=x)
|
||||||
|
|
||||||
|
self.status = 'requested-archiving'
|
||||||
|
|
||||||
|
self.send(request)
|
||||||
|
|
||||||
|
def respond_archiving(self, form):
|
||||||
|
field = form.getField('logging')
|
||||||
|
options = [x[1] for x in field.getOptions()]
|
||||||
|
values = field.getValues()
|
||||||
|
|
||||||
|
logging = self.archiving_logging_preference(options)
|
||||||
|
self.negotiated['logging'] = logging
|
||||||
|
|
||||||
|
response = xmpp.Message()
|
||||||
|
feature = response.NT.feature
|
||||||
|
feature.setNamespace(xmpp.NS_FEATURE)
|
||||||
|
|
||||||
|
x = xmpp.DataForm(typ='submit')
|
||||||
|
|
||||||
|
x.addChild(node=xmpp.DataField(name='FORM_TYPE', value='urn:xmpp:ssn'))
|
||||||
|
x.addChild(node=xmpp.DataField(name='accept', value='true'))
|
||||||
|
|
||||||
|
x.addChild(node=xmpp.DataField(name='logging', value=logging))
|
||||||
|
|
||||||
|
self.status = 'responded-archiving'
|
||||||
|
|
||||||
|
feature.addChild(node=x)
|
||||||
|
|
||||||
|
if not logging:
|
||||||
|
response = xmpp.Error(response, xmpp.ERR_NOT_ACCEPTABLE)
|
||||||
|
|
||||||
|
feature = xmpp.Node(xmpp.NS_FEATURE + ' feature')
|
||||||
|
|
||||||
|
n = xmpp.Node('field')
|
||||||
|
n['var'] = 'logging'
|
||||||
|
feature.addChild(node=n)
|
||||||
|
|
||||||
|
response.T.error.addChild(node=feature)
|
||||||
|
|
||||||
|
self.send(response)
|
||||||
|
|
||||||
|
def we_accept_archiving(self, form):
|
||||||
|
if self.negotiated['logging'] == 'mustnot':
|
||||||
|
self.loggable = False
|
||||||
|
log.debug('archiving session accepted: %s' % self.loggable)
|
||||||
|
self.status = 'active'
|
||||||
|
self.archiving = True
|
||||||
|
if self.control:
|
||||||
|
self.control.print_archiving_session_details()
|
||||||
|
|
||||||
|
def archiving_accepted(self, form):
|
||||||
|
negotiated = {}
|
||||||
|
ask_user = {}
|
||||||
|
not_acceptable = []
|
||||||
|
|
||||||
|
if form['logging'] not in self.archiving_logging_preference():
|
||||||
|
raise
|
||||||
|
|
||||||
|
self.negotiated['logging'] = form['logging']
|
||||||
|
|
||||||
|
accept = xmpp.Message()
|
||||||
|
feature = accept.NT.feature
|
||||||
|
feature.setNamespace(xmpp.NS_FEATURE)
|
||||||
|
|
||||||
|
result = xmpp.DataForm(typ='result')
|
||||||
|
|
||||||
|
result.addChild(node=xmpp.DataField(name='FORM_TYPE',
|
||||||
|
value='urn:xmpp:ssn'))
|
||||||
|
result.addChild(node=xmpp.DataField(name='accept', value='1'))
|
||||||
|
|
||||||
|
feature.addChild(node=result)
|
||||||
|
|
||||||
|
self.send(accept)
|
||||||
|
if self.negotiated['logging'] == 'mustnot':
|
||||||
|
self.loggable = False
|
||||||
|
log.debug('archiving session accepted: %s' % self.loggable)
|
||||||
|
self.status = 'active'
|
||||||
|
self.archiving = True
|
||||||
|
if self.control:
|
||||||
|
self.control.print_archiving_session_details()
|
||||||
|
|
||||||
|
def stop_archiving_for_session(self):
|
||||||
|
self.conn.stop_archiving_session(self.thread_id)
|
||||||
|
|
||||||
|
|
||||||
|
class EncryptedStanzaSession(ArchivingStanzaSession):
|
||||||
"""
|
"""
|
||||||
An encrypted stanza negotiation has several states. They arerepresented as
|
An encrypted stanza negotiation has several states. They arerepresented as
|
||||||
the following values in the 'status' attribute of the session object:
|
the following values in the 'status' attribute of the session object:
|
||||||
|
@ -202,7 +318,8 @@ class EncryptedStanzaSession(StanzaSession):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, conn, jid, thread_id, type_='chat'):
|
def __init__(self, conn, jid, thread_id, type_='chat'):
|
||||||
StanzaSession.__init__(self, conn, jid, thread_id, type_='chat')
|
ArchivingStanzaSession.__init__(self, conn, jid, thread_id,
|
||||||
|
type_='chat')
|
||||||
|
|
||||||
self.xes = {}
|
self.xes = {}
|
||||||
self.es = {}
|
self.es = {}
|
||||||
|
@ -921,6 +1038,8 @@ class EncryptedStanzaSession(StanzaSession):
|
||||||
if self.control:
|
if self.control:
|
||||||
self.control.print_esession_details()
|
self.control.print_esession_details()
|
||||||
|
|
||||||
|
self.stop_archiving_for_session()
|
||||||
|
|
||||||
def final_steps_alice(self, form):
|
def final_steps_alice(self, form):
|
||||||
srs = ''
|
srs = ''
|
||||||
srses = secrets.secrets().retained_secrets(self.conn.name,
|
srses = secrets.secrets().retained_secrets(self.conn.name,
|
||||||
|
@ -961,6 +1080,8 @@ class EncryptedStanzaSession(StanzaSession):
|
||||||
if self.control:
|
if self.control:
|
||||||
self.control.print_esession_details()
|
self.control.print_esession_details()
|
||||||
|
|
||||||
|
self.stop_archiving_for_session()
|
||||||
|
|
||||||
def do_retained_secret(self, k, old_srs):
|
def do_retained_secret(self, k, old_srs):
|
||||||
"""
|
"""
|
||||||
Calculate the new retained secret. determine if the user needs to check
|
Calculate the new retained secret. determine if the user needs to check
|
||||||
|
|
|
@ -28,6 +28,11 @@ NS_ADDRESS ='http://jabber.org/protocol/address'
|
||||||
NS_AGENTS ='jabber:iq:agents'
|
NS_AGENTS ='jabber:iq:agents'
|
||||||
NS_AMP ='http://jabber.org/protocol/amp'
|
NS_AMP ='http://jabber.org/protocol/amp'
|
||||||
NS_AMP_ERRORS =NS_AMP+'#errors'
|
NS_AMP_ERRORS =NS_AMP+'#errors'
|
||||||
|
NS_ARCHIVE ='urn:xmpp:archive' #XEP-0136
|
||||||
|
NS_ARCHIVE_AUTO =NS_ARCHIVE+':auto' #XEP-0136
|
||||||
|
NS_ARCHIVE_MANAGE =NS_ARCHIVE+':manage' #XEP-0136
|
||||||
|
NS_ARCHIVE_MANUAL =NS_ARCHIVE+':manual' #XEP-0136
|
||||||
|
NS_ARCHIVE_PREF =NS_ARCHIVE+':pref'
|
||||||
NS_ATOM ='http://www.w3.org/2005/Atom'
|
NS_ATOM ='http://www.w3.org/2005/Atom'
|
||||||
NS_AUTH ='jabber:iq:auth'
|
NS_AUTH ='jabber:iq:auth'
|
||||||
NS_AVATAR ='http://www.xmpp.org/extensions/xep-0084.html#ns-metadata'
|
NS_AVATAR ='http://www.xmpp.org/extensions/xep-0084.html#ns-metadata'
|
||||||
|
@ -102,6 +107,7 @@ NS_ROSTER ='jabber:iq:roster'
|
||||||
NS_ROSTERX ='http://jabber.org/protocol/rosterx' # XEP-0144
|
NS_ROSTERX ='http://jabber.org/protocol/rosterx' # XEP-0144
|
||||||
NS_ROSTER_VER ='urn:xmpp:features:rosterver' # XEP-0273
|
NS_ROSTER_VER ='urn:xmpp:features:rosterver' # XEP-0273
|
||||||
NS_RPC ='jabber:iq:rpc' # XEP-0009
|
NS_RPC ='jabber:iq:rpc' # XEP-0009
|
||||||
|
NS_RSM ='http://jabber.org/protocol/rsm'
|
||||||
NS_SASL ='urn:ietf:params:xml:ns:xmpp-sasl'
|
NS_SASL ='urn:ietf:params:xml:ns:xmpp-sasl'
|
||||||
NS_SECLABEL ='urn:xmpp:sec-label:0'
|
NS_SECLABEL ='urn:xmpp:sec-label:0'
|
||||||
NS_SECLABEL_CATALOG ='urn:xmpp:sec-label:catalog:0'
|
NS_SECLABEL_CATALOG ='urn:xmpp:sec-label:catalog:0'
|
||||||
|
|
350
src/dialogs.py
350
src/dialogs.py
|
@ -3381,6 +3381,356 @@ class RosterItemExchangeWindow:
|
||||||
self.window.destroy()
|
self.window.destroy()
|
||||||
|
|
||||||
|
|
||||||
|
class ItemArchivingPreferencesWindow:
|
||||||
|
otr_name = ('approve', 'concede', 'forbid', 'oppose', 'prefer', 'require')
|
||||||
|
otr_index = dict([(j, i) for i, j in enumerate(otr_name)])
|
||||||
|
save_name = ('body', 'false', 'message', 'stream')
|
||||||
|
save_index = dict([(j, i) for i, j in enumerate(save_name)])
|
||||||
|
|
||||||
|
def __init__(self, account, item):
|
||||||
|
self.account = account
|
||||||
|
self.item = item
|
||||||
|
if self.item and self.item != 'Default':
|
||||||
|
self.item_config = gajim.connections[self.account].items[self.item]
|
||||||
|
else:
|
||||||
|
self.item_config = gajim.connections[self.account].default
|
||||||
|
self.waiting = None
|
||||||
|
|
||||||
|
# Connect to gtk builder
|
||||||
|
self.xml = gtkgui_helpers.get_gtk_builder(
|
||||||
|
'item_archiving_preferences_window.ui')
|
||||||
|
self.window = self.xml.get_object('item_archiving_preferences_window')
|
||||||
|
|
||||||
|
# Add Widgets
|
||||||
|
for widget_to_add in ('jid_entry', 'expire_entry', 'otr_combobox',
|
||||||
|
'save_combobox', 'cancel_button', 'ok_button', 'progressbar'):
|
||||||
|
self.__dict__[widget_to_add] = self.xml.get_object(widget_to_add)
|
||||||
|
|
||||||
|
if self.item:
|
||||||
|
self.jid_entry.set_text(self.item)
|
||||||
|
expire_value = self.item_config['expire'] or ''
|
||||||
|
self.otr_combobox.set_active(self.otr_index[self.item_config['otr']])
|
||||||
|
self.save_combobox.set_active(
|
||||||
|
self.save_index[self.item_config['save']])
|
||||||
|
self.expire_entry.set_text(expire_value)
|
||||||
|
|
||||||
|
self.window.set_title(_('Archiving Preferences for %s') % self.account)
|
||||||
|
|
||||||
|
self.window.show_all()
|
||||||
|
self.progressbar.hide()
|
||||||
|
self.xml.connect_signals(self)
|
||||||
|
|
||||||
|
def update_progressbar(self):
|
||||||
|
if self.waiting:
|
||||||
|
self.progressbar.pulse()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def on_otr_combobox_changed(self, widget):
|
||||||
|
otr = self.otr_name[self.otr_combobox.get_active()]
|
||||||
|
if otr == 'require':
|
||||||
|
self.save_combobox.set_active(self.save_index['false'])
|
||||||
|
|
||||||
|
def on_ok_button_clicked(self, widget):
|
||||||
|
# Return directly if operation in progress
|
||||||
|
if self.waiting:
|
||||||
|
return
|
||||||
|
|
||||||
|
item = self.jid_entry.get_text()
|
||||||
|
otr = self.otr_name[self.otr_combobox.get_active()]
|
||||||
|
save = self.save_name[self.save_combobox.get_active()]
|
||||||
|
expire = self.expire_entry.get_text()
|
||||||
|
|
||||||
|
if self.item != 'Default':
|
||||||
|
try:
|
||||||
|
item = helpers.parse_jid(item)
|
||||||
|
except helpers.InvalidFormat, s:
|
||||||
|
pritext = _('Invalid User ID')
|
||||||
|
ErrorDialog(pritext, str(s))
|
||||||
|
return
|
||||||
|
|
||||||
|
if expire:
|
||||||
|
try:
|
||||||
|
if int(expire) < 0 or str(int(expire)) != expire:
|
||||||
|
raise ValueError
|
||||||
|
except ValueError:
|
||||||
|
pritext = _('Invalid expire value')
|
||||||
|
sectext = _('Expire must be a valid positive integer.')
|
||||||
|
ErrorDialog(pritext, sectext)
|
||||||
|
return
|
||||||
|
|
||||||
|
if not (item == self.item and expire == self.item_config['expire'] and
|
||||||
|
otr == self.item_config['otr'] and save == self.item_config['save']):
|
||||||
|
if not self.item or self.item == item:
|
||||||
|
if self.item == 'Default':
|
||||||
|
self.waiting = 'default'
|
||||||
|
gajim.connections[self.account].set_default(
|
||||||
|
otr, save, expire)
|
||||||
|
else:
|
||||||
|
self.waiting = 'item'
|
||||||
|
gajim.connections[self.account].append_or_update_item(
|
||||||
|
item, otr, save, expire)
|
||||||
|
else:
|
||||||
|
self.waiting = 'item'
|
||||||
|
gajim.connections[self.account].append_or_update_item(
|
||||||
|
item, otr, save, expire)
|
||||||
|
gajim.connections[self.account].remove_item(self.item)
|
||||||
|
self.launch_progressbar()
|
||||||
|
#self.window.destroy()
|
||||||
|
|
||||||
|
def on_cancel_button_clicked(self, widget):
|
||||||
|
self.window.destroy()
|
||||||
|
|
||||||
|
def on_item_archiving_preferences_window_destroy(self, widget):
|
||||||
|
if self.item:
|
||||||
|
key_name = 'edit_item_archiving_preferences_%s' % self.item
|
||||||
|
else:
|
||||||
|
key_name = 'new_item_archiving_preferences'
|
||||||
|
if key_name in gajim.interface.instances[self.account]:
|
||||||
|
del gajim.interface.instances[self.account][key_name]
|
||||||
|
|
||||||
|
def launch_progressbar(self):
|
||||||
|
self.progressbar.show()
|
||||||
|
self.update_progressbar_timeout_id = gobject.timeout_add(
|
||||||
|
100, self.update_progressbar)
|
||||||
|
|
||||||
|
def response_arrived(self, data):
|
||||||
|
if self.waiting:
|
||||||
|
self.window.destroy()
|
||||||
|
|
||||||
|
def error_arrived(self, error):
|
||||||
|
if self.waiting:
|
||||||
|
self.waiting = None
|
||||||
|
self.progressbar.hide()
|
||||||
|
pritext = _('There is an error with the form')
|
||||||
|
sectext = error
|
||||||
|
ErrorDialog(pritext, sectext)
|
||||||
|
|
||||||
|
|
||||||
|
class ArchivingPreferencesWindow:
|
||||||
|
auto_name = ('false', 'true')
|
||||||
|
auto_index = dict([(j, i) for i, j in enumerate(auto_name)])
|
||||||
|
method_foo_name = ('prefer', 'concede', 'forbid')
|
||||||
|
method_foo_index = dict([(j, i) for i, j in enumerate(method_foo_name)])
|
||||||
|
|
||||||
|
def __init__(self, account):
|
||||||
|
self.account = account
|
||||||
|
self.waiting = []
|
||||||
|
|
||||||
|
# Connect to glade
|
||||||
|
self.xml = gtkgui_helpers.get_gtk_builder(
|
||||||
|
'archiving_preferences_window.ui')
|
||||||
|
self.window = self.xml.get_object('archiving_preferences_window')
|
||||||
|
|
||||||
|
# Add Widgets
|
||||||
|
for widget_to_add in ('auto_combobox', 'method_auto_combobox',
|
||||||
|
'method_local_combobox', 'method_manual_combobox', 'close_button',
|
||||||
|
'item_treeview', 'item_notebook', 'otr_combobox', 'save_combobox',
|
||||||
|
'expire_entry', 'remove_button', 'edit_button'):
|
||||||
|
self.__dict__[widget_to_add] = self.xml.get_object(widget_to_add)
|
||||||
|
|
||||||
|
self.auto_combobox.set_active(
|
||||||
|
self.auto_index[gajim.connections[self.account].auto])
|
||||||
|
self.method_auto_combobox.set_active(
|
||||||
|
self.method_foo_index[gajim.connections[self.account].method_auto])
|
||||||
|
self.method_local_combobox.set_active(
|
||||||
|
self.method_foo_index[gajim.connections[self.account].method_local])
|
||||||
|
self.method_manual_combobox.set_active(
|
||||||
|
self.method_foo_index[gajim.connections[self.account].\
|
||||||
|
method_manual])
|
||||||
|
|
||||||
|
model = gtk.ListStore(str, str, str, str)
|
||||||
|
self.item_treeview.set_model(model)
|
||||||
|
col = gtk.TreeViewColumn('jid')
|
||||||
|
self.item_treeview.append_column(col)
|
||||||
|
renderer = gtk.CellRendererText()
|
||||||
|
col.pack_start(renderer, True)
|
||||||
|
col.set_attributes(renderer, text=0)
|
||||||
|
|
||||||
|
col = gtk.TreeViewColumn('expire')
|
||||||
|
col.pack_start(renderer, True)
|
||||||
|
col.set_attributes(renderer, text=1)
|
||||||
|
self.item_treeview.append_column(col)
|
||||||
|
|
||||||
|
col = gtk.TreeViewColumn('otr')
|
||||||
|
col.pack_start(renderer, True)
|
||||||
|
col.set_attributes(renderer, text=2)
|
||||||
|
self.item_treeview.append_column(col)
|
||||||
|
|
||||||
|
col = gtk.TreeViewColumn('save')
|
||||||
|
col.pack_start(renderer, True)
|
||||||
|
col.set_attributes(renderer, text=3)
|
||||||
|
self.item_treeview.append_column(col)
|
||||||
|
|
||||||
|
self.fill_items()
|
||||||
|
|
||||||
|
self.current_item = None
|
||||||
|
|
||||||
|
def sort_items(model, iter1, iter2):
|
||||||
|
item1 = model.get_value(iter1, 0)
|
||||||
|
item2 = model.get_value(iter2, 0)
|
||||||
|
if item1 == 'Default':
|
||||||
|
return -1
|
||||||
|
if item2 == 'Default':
|
||||||
|
return 1
|
||||||
|
if '@' in item1:
|
||||||
|
if '@' not in item2:
|
||||||
|
return 1
|
||||||
|
elif '@' in item2:
|
||||||
|
return -1
|
||||||
|
if item1 < item2:
|
||||||
|
return -1
|
||||||
|
if item1 > item2:
|
||||||
|
return 1
|
||||||
|
# item1 == item2 ? WTF?
|
||||||
|
return 0
|
||||||
|
|
||||||
|
model.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||||
|
model.set_sort_func(0, sort_items)
|
||||||
|
|
||||||
|
self.remove_button.set_sensitive(False)
|
||||||
|
self.edit_button.set_sensitive(False)
|
||||||
|
|
||||||
|
self.window.set_title(_('Archiving Preferences for %s') % self.account)
|
||||||
|
|
||||||
|
self.window.show_all()
|
||||||
|
|
||||||
|
self.xml.connect_signals(self)
|
||||||
|
|
||||||
|
def on_add_item_button_clicked(self, widget):
|
||||||
|
key_name = 'new_item_archiving_preferences'
|
||||||
|
if key_name in gajim.interface.instances[self.account]:
|
||||||
|
gajim.interface.instances[self.account][key_name].window.present()
|
||||||
|
else:
|
||||||
|
gajim.interface.instances[self.account][key_name] = \
|
||||||
|
ItemArchivingPreferencesWindow(self.account, '')
|
||||||
|
|
||||||
|
def on_remove_item_button_clicked(self, widget):
|
||||||
|
if not self.current_item:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.waiting.append('itemremove')
|
||||||
|
sel = self.item_treeview.get_selection()
|
||||||
|
(model, iter_) = sel.get_selected()
|
||||||
|
gajim.connections[self.account].remove_item(model[iter_][0])
|
||||||
|
model.remove(iter_)
|
||||||
|
self.remove_button.set_sensitive(False)
|
||||||
|
self.edit_button.set_sensitive(False)
|
||||||
|
|
||||||
|
def on_edit_item_button_clicked(self, widget):
|
||||||
|
if not self.current_item:
|
||||||
|
return
|
||||||
|
|
||||||
|
key_name = 'edit_item_archiving_preferences_%s' % self.current_item
|
||||||
|
if key_name in gajim.interface.instances[self.account]:
|
||||||
|
gajim.interface.instances[self.account][key_name].window.present()
|
||||||
|
else:
|
||||||
|
gajim.interface.instances[self.account][key_name] = \
|
||||||
|
ItemArchivingPreferencesWindow(self.account, self.current_item)
|
||||||
|
|
||||||
|
def on_item_treeview_cursor_changed(self, widget):
|
||||||
|
sel = self.item_treeview.get_selection()
|
||||||
|
(model, iter_) = sel.get_selected()
|
||||||
|
item = None
|
||||||
|
if iter_:
|
||||||
|
item = model[iter_][0]
|
||||||
|
if self.current_item and self.current_item == item:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.current_item = item
|
||||||
|
if self.current_item == 'Default':
|
||||||
|
self.remove_button.set_sensitive(False)
|
||||||
|
self.edit_button.set_sensitive(True)
|
||||||
|
elif self.current_item:
|
||||||
|
self.remove_button.set_sensitive(True)
|
||||||
|
self.edit_button.set_sensitive(True)
|
||||||
|
else:
|
||||||
|
self.remove_button.set_sensitive(False)
|
||||||
|
self.edit_button.set_sensitive(False)
|
||||||
|
|
||||||
|
def on_auto_combobox_changed(self, widget):
|
||||||
|
save = self.auto_name[widget.get_active()]
|
||||||
|
gajim.connections[self.account].set_auto(save)
|
||||||
|
|
||||||
|
def on_method_foo_combobox_changed(self, widget):
|
||||||
|
# We retrieve method type from widget name
|
||||||
|
# ('foo' in 'method_foo_combobox')
|
||||||
|
method_type = widget.name.split('_')[1]
|
||||||
|
use = self.method_foo_name[widget.get_active()]
|
||||||
|
self.waiting.append('method_%s' % method_type)
|
||||||
|
gajim.connections[self.account].set_method(method_type, use)
|
||||||
|
|
||||||
|
def get_child_window(self):
|
||||||
|
edit_key_name = 'edit_item_archiving_preferences_%s' % self.current_item
|
||||||
|
new_key_name = 'new_item_archiving_preferences'
|
||||||
|
|
||||||
|
if edit_key_name in gajim.interface.instances[self.account]:
|
||||||
|
return gajim.interface.instances[self.account][edit_key_name]
|
||||||
|
|
||||||
|
if new_key_name in gajim.interface.instances[self.account]:
|
||||||
|
return gajim.interface.instances[self.account][new_key_name]
|
||||||
|
|
||||||
|
def archiving_changed(self, data):
|
||||||
|
if data[0] in ('auto', 'method_auto', 'method_local', 'method_manual'):
|
||||||
|
if data[0] in self.waiting:
|
||||||
|
self.waiting.remove(data[0])
|
||||||
|
elif data[0] == 'default':
|
||||||
|
key_name = 'edit_item_archiving_preferences_%s' % \
|
||||||
|
self.current_item
|
||||||
|
if key_name in gajim.interface.instances[self.account]:
|
||||||
|
gajim.interface.instances[self.account][key_name].\
|
||||||
|
response_arrived(data[1:])
|
||||||
|
self.fill_items(True)
|
||||||
|
elif data[0] == 'item':
|
||||||
|
child = self.get_child_window()
|
||||||
|
if child:
|
||||||
|
is_new = not child.item
|
||||||
|
child.response_arrived(data[1:])
|
||||||
|
if is_new:
|
||||||
|
model = self.item_treeview.get_model()
|
||||||
|
model.append((data[1], data[2]['expire'], data[2]['otr'],
|
||||||
|
data[2]['save']))
|
||||||
|
return
|
||||||
|
self.fill_items(True)
|
||||||
|
elif data[0] == 'itemremove' == self.waiting:
|
||||||
|
if data[0] in self.waiting:
|
||||||
|
self.waiting.remove(data[0])
|
||||||
|
self.fill_items(True)
|
||||||
|
|
||||||
|
def fill_items(self, clear=False):
|
||||||
|
model = self.item_treeview.get_model()
|
||||||
|
if clear:
|
||||||
|
model.clear()
|
||||||
|
default_config = gajim.connections[self.account].default
|
||||||
|
expire_value = default_config['expire'] or ''
|
||||||
|
model.append(('Default', expire_value,
|
||||||
|
default_config['otr'], default_config['save']))
|
||||||
|
for item, item_config in \
|
||||||
|
gajim.connections[self.account].items.items():
|
||||||
|
expire_value = item_config['expire'] or ''
|
||||||
|
model.append((item, expire_value, item_config['otr'],
|
||||||
|
item_config['save']))
|
||||||
|
|
||||||
|
def archiving_error(self, error):
|
||||||
|
if self.waiting:
|
||||||
|
pritext = _('There is an error')
|
||||||
|
sectext = error
|
||||||
|
ErrorDialog(pritext, sectext)
|
||||||
|
self.waiting.pop()
|
||||||
|
else:
|
||||||
|
child = self.get_child_window()
|
||||||
|
if child:
|
||||||
|
child.error_arrived(error)
|
||||||
|
print error
|
||||||
|
|
||||||
|
def on_close_button_clicked(self, widget):
|
||||||
|
self.window.destroy()
|
||||||
|
|
||||||
|
def on_archiving_preferences_window_destroy(self, widget):
|
||||||
|
if 'archiving_preferences' in gajim.interface.instances[self.account]:
|
||||||
|
del gajim.interface.instances[self.account]['archiving_preferences']
|
||||||
|
|
||||||
|
|
||||||
class PrivacyListWindow:
|
class PrivacyListWindow:
|
||||||
"""
|
"""
|
||||||
Window that is used for creating NEW or EDITING already there privacy lists
|
Window that is used for creating NEW or EDITING already there privacy lists
|
||||||
|
|
|
@ -1573,6 +1573,11 @@ class Interface:
|
||||||
if gajim.connections[account].pep_supported and dbus_support.supported \
|
if gajim.connections[account].pep_supported and dbus_support.supported \
|
||||||
and gajim.config.get_per('accounts', account, 'publish_location'):
|
and gajim.config.get_per('accounts', account, 'publish_location'):
|
||||||
location_listener.enable()
|
location_listener.enable()
|
||||||
|
# Start merging logs from server
|
||||||
|
gajim.connections[account].request_modifications_page(
|
||||||
|
gajim.config.get_per('accounts', account, 'last_archiving_time'))
|
||||||
|
gajim.config.set_per('accounts', account, 'last_archiving_time',
|
||||||
|
time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()))
|
||||||
|
|
||||||
def handle_event_metacontacts(self, account, tags_list):
|
def handle_event_metacontacts(self, account, tags_list):
|
||||||
gajim.contacts.define_metacontacts(account, tags_list)
|
gajim.contacts.define_metacontacts(account, tags_list)
|
||||||
|
@ -2064,6 +2069,18 @@ class Interface:
|
||||||
if pm_ctrl and hasattr(pm_ctrl, "update_contact"):
|
if pm_ctrl and hasattr(pm_ctrl, "update_contact"):
|
||||||
pm_ctrl.update_contact()
|
pm_ctrl.update_contact()
|
||||||
|
|
||||||
|
def handle_event_archiving_changed(self, account, data):
|
||||||
|
# ('ARCHIVING_CHANGED', account, (type, value)
|
||||||
|
if 'archiving_preferences' in self.instances[account]:
|
||||||
|
self.instances[account]['archiving_preferences'].archiving_changed(
|
||||||
|
data)
|
||||||
|
|
||||||
|
def handle_event_archiving_error(self, account, data):
|
||||||
|
# ('ARCHIVING_CHANGED', account, (error_msg,))
|
||||||
|
if 'archiving_preferences' in self.instances[account]:
|
||||||
|
self.instances[account]['archiving_preferences'].archiving_error(
|
||||||
|
data)
|
||||||
|
|
||||||
def create_core_handlers_list(self):
|
def create_core_handlers_list(self):
|
||||||
self.handlers = {
|
self.handlers = {
|
||||||
'ROSTER': [self.handle_event_roster],
|
'ROSTER': [self.handle_event_roster],
|
||||||
|
@ -2147,6 +2164,8 @@ class Interface:
|
||||||
'JINGLE_ERROR': [self.handle_event_jingle_error],
|
'JINGLE_ERROR': [self.handle_event_jingle_error],
|
||||||
'PEP_RECEIVED': [self.handle_event_pep_received],
|
'PEP_RECEIVED': [self.handle_event_pep_received],
|
||||||
'CAPS_RECEIVED': [self.handle_event_caps_received],
|
'CAPS_RECEIVED': [self.handle_event_caps_received],
|
||||||
|
'ARCHIVING_CHANGED': [self.handle_event_archiving_changed],
|
||||||
|
'ARCHIVING_ERROR': [self.handle_event_archiving_error],
|
||||||
'gmail-notify': [self.handle_event_gmail_notify],
|
'gmail-notify': [self.handle_event_gmail_notify],
|
||||||
'http-auth-received': [self.handle_event_http_auth],
|
'http-auth-received': [self.handle_event_http_auth],
|
||||||
'last-result-received': [self.handle_event_last_status_time],
|
'last-result-received': [self.handle_event_last_status_time],
|
||||||
|
|
|
@ -30,6 +30,7 @@ import gtkgui_helpers
|
||||||
|
|
||||||
from common import gajim
|
from common import gajim
|
||||||
from common import helpers
|
from common import helpers
|
||||||
|
from common.stanza_session import EncryptedStanzaSession, ArchivingStanzaSession
|
||||||
|
|
||||||
# Derived types MUST register their type IDs here if custom behavor is required
|
# Derived types MUST register their type IDs here if custom behavor is required
|
||||||
TYPE_CHAT = 'chat'
|
TYPE_CHAT = 'chat'
|
||||||
|
@ -200,11 +201,18 @@ class MessageControl(object):
|
||||||
if self.resource:
|
if self.resource:
|
||||||
jid += '/' + self.resource
|
jid += '/' + self.resource
|
||||||
|
|
||||||
crypto_changed = bool(session and session.enable_encryption) != \
|
crypto_changed = bool(session and isinstance(session,
|
||||||
bool(oldsession and oldsession.enable_encryption)
|
EncryptedStanzaSession) and session.enable_encryption) != \
|
||||||
|
bool(oldsession and isinstance(oldsession,
|
||||||
|
EncryptedStanzaSession) and oldsession.enable_encryption)
|
||||||
|
|
||||||
if crypto_changed:
|
archiving_changed = bool(session and isinstance(session,
|
||||||
self.print_esession_details()
|
ArchivingStanzaSession) and session.archiving) != \
|
||||||
|
bool(oldsession and isinstance(oldsession,
|
||||||
|
ArchivingStanzaSession) and oldsession.archiving)
|
||||||
|
|
||||||
|
if crypto_changed or archiving_changed:
|
||||||
|
self.print_session_details()
|
||||||
|
|
||||||
def send_message(self, message, keyID='', type_='chat', chatstate=None,
|
def send_message(self, message, keyID='', type_='chat', chatstate=None,
|
||||||
msg_id=None, composing_xep=None, resource=None, user_nick=None,
|
msg_id=None, composing_xep=None, resource=None, user_nick=None,
|
||||||
|
|
|
@ -2447,6 +2447,14 @@ class RosterWindow:
|
||||||
gajim.interface.instances[account]['xml_console'] = \
|
gajim.interface.instances[account]['xml_console'] = \
|
||||||
dialogs.XMLConsoleWindow(account)
|
dialogs.XMLConsoleWindow(account)
|
||||||
|
|
||||||
|
def on_archiving_preferences_menuitem_activate(self, widget, account):
|
||||||
|
if 'archiving_preferences' in gajim.interface.instances[account]:
|
||||||
|
gajim.interface.instances[account]['archiving_preferences'].window.\
|
||||||
|
present()
|
||||||
|
else:
|
||||||
|
gajim.interface.instances[account]['archiving_preferences'] = \
|
||||||
|
dialogs.ArchivingPreferencesWindow(account)
|
||||||
|
|
||||||
def on_privacy_lists_menuitem_activate(self, widget, account):
|
def on_privacy_lists_menuitem_activate(self, widget, account):
|
||||||
if 'privacy_lists' in gajim.interface.instances[account]:
|
if 'privacy_lists' in gajim.interface.instances[account]:
|
||||||
gajim.interface.instances[account]['privacy_lists'].window.present()
|
gajim.interface.instances[account]['privacy_lists'].window.present()
|
||||||
|
@ -5710,6 +5718,8 @@ class RosterWindow:
|
||||||
advanced_menuitem_menu = xml.get_object('advanced_menuitem_menu')
|
advanced_menuitem_menu = xml.get_object('advanced_menuitem_menu')
|
||||||
|
|
||||||
xml_console_menuitem = xml.get_object('xml_console_menuitem')
|
xml_console_menuitem = xml.get_object('xml_console_menuitem')
|
||||||
|
archiving_preferences_menuitem = xml.get_object(
|
||||||
|
'archiving_preferences_menuitem')
|
||||||
privacy_lists_menuitem = xml.get_object('privacy_lists_menuitem')
|
privacy_lists_menuitem = xml.get_object('privacy_lists_menuitem')
|
||||||
administrator_menuitem = xml.get_object('administrator_menuitem')
|
administrator_menuitem = xml.get_object('administrator_menuitem')
|
||||||
send_server_message_menuitem = xml.get_object(
|
send_server_message_menuitem = xml.get_object(
|
||||||
|
@ -5721,12 +5731,17 @@ class RosterWindow:
|
||||||
xml_console_menuitem.connect('activate',
|
xml_console_menuitem.connect('activate',
|
||||||
self.on_xml_console_menuitem_activate, account)
|
self.on_xml_console_menuitem_activate, account)
|
||||||
|
|
||||||
if gajim.connections[account] and gajim.connections[account].\
|
if gajim.connections[account]:
|
||||||
privacy_rules_supported:
|
if gajim.connections[account].privacy_rules_supported:
|
||||||
privacy_lists_menuitem.connect('activate',
|
privacy_lists_menuitem.connect('activate',
|
||||||
self.on_privacy_lists_menuitem_activate, account)
|
self.on_privacy_lists_menuitem_activate, account)
|
||||||
else:
|
else:
|
||||||
privacy_lists_menuitem.set_sensitive(False)
|
privacy_lists_menuitem.set_sensitive(False)
|
||||||
|
if gajim.connections[account].archive_pref_supported:
|
||||||
|
archiving_preferences_menuitem.connect('activate',
|
||||||
|
self.on_archiving_preferences_menuitem_activate, account)
|
||||||
|
else:
|
||||||
|
archiving_preferences_menuitem.set_sensitive(False)
|
||||||
|
|
||||||
if gajim.connections[account].is_zeroconf:
|
if gajim.connections[account].is_zeroconf:
|
||||||
administrator_menuitem.set_sensitive(False)
|
administrator_menuitem.set_sensitive(False)
|
||||||
|
|
|
@ -413,31 +413,40 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
|
||||||
# encrypted session states. these are described in stanza_session.py
|
# encrypted session states. these are described in stanza_session.py
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# bob responds
|
|
||||||
if form.getType() == 'form' and 'security' in form.asDict():
|
if form.getType() == 'form' and 'security' in form.asDict():
|
||||||
# we don't support 3-message negotiation as the responder
|
security_options = [x[1] for x in form.getField('security').\
|
||||||
if 'dhkeys' in form.asDict():
|
getOptions()]
|
||||||
self.fail_bad_negotiation('3 message negotiation not supported '
|
if security_options == ['none']:
|
||||||
'when responding', ('dhkeys',))
|
self.respond_archiving(form)
|
||||||
return
|
else:
|
||||||
|
# bob responds
|
||||||
|
|
||||||
negotiated, not_acceptable, ask_user = self.verify_options_bob(form)
|
# we don't support 3-message negotiation as the responder
|
||||||
|
if 'dhkeys' in form.asDict():
|
||||||
|
self.fail_bad_negotiation('3 message negotiation not '
|
||||||
|
'supported when responding', ('dhkeys',))
|
||||||
|
return
|
||||||
|
|
||||||
if ask_user:
|
negotiated, not_acceptable, ask_user = \
|
||||||
def accept_nondefault_options(is_checked):
|
self.verify_options_bob(form)
|
||||||
self.dialog.destroy()
|
|
||||||
negotiated.update(ask_user)
|
|
||||||
self.respond_e2e_bob(form, negotiated, not_acceptable)
|
|
||||||
|
|
||||||
def reject_nondefault_options():
|
if ask_user:
|
||||||
self.dialog.destroy()
|
def accept_nondefault_options(is_checked):
|
||||||
for key in ask_user.keys():
|
self.dialog.destroy()
|
||||||
not_acceptable.append(key)
|
negotiated.update(ask_user)
|
||||||
self.respond_e2e_bob(form, negotiated, not_acceptable)
|
self.respond_e2e_bob(form, negotiated,
|
||||||
|
not_acceptable)
|
||||||
|
|
||||||
self.dialog = dialogs.YesNoDialog(_('Confirm these session '
|
def reject_nondefault_options():
|
||||||
'options'),
|
self.dialog.destroy()
|
||||||
_('''The remote client wants to negotiate a session with these features:
|
for key in ask_user.keys():
|
||||||
|
not_acceptable.append(key)
|
||||||
|
self.respond_e2e_bob(form, negotiated,
|
||||||
|
not_acceptable)
|
||||||
|
|
||||||
|
self.dialog = dialogs.YesNoDialog(_('Confirm these '
|
||||||
|
'session options'), _('''The remote client wants '
|
||||||
|
'to negotiate an session with these features:
|
||||||
|
|
||||||
%s
|
%s
|
||||||
|
|
||||||
|
@ -445,8 +454,17 @@ Are these options acceptable?''') % (negotiation.describe_features(
|
||||||
ask_user)),
|
ask_user)),
|
||||||
on_response_yes=accept_nondefault_options,
|
on_response_yes=accept_nondefault_options,
|
||||||
on_response_no=reject_nondefault_options)
|
on_response_no=reject_nondefault_options)
|
||||||
else:
|
else:
|
||||||
self.respond_e2e_bob(form, negotiated, not_acceptable)
|
self.respond_e2e_bob(form, negotiated, not_acceptable)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
elif self.status == 'requested-archiving' and form.getType() == \
|
||||||
|
'submit':
|
||||||
|
try:
|
||||||
|
self.archiving_accepted(form)
|
||||||
|
except exceptions.NegotiationError, details:
|
||||||
|
self.fail_bad_negotiation(details)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -482,6 +500,14 @@ Are these options acceptable?''') % (negotiation.describe_features(
|
||||||
except exceptions.NegotiationError, details:
|
except exceptions.NegotiationError, details:
|
||||||
self.fail_bad_negotiation(details)
|
self.fail_bad_negotiation(details)
|
||||||
|
|
||||||
|
return
|
||||||
|
elif self.status == 'responded-archiving' and form.getType() == \
|
||||||
|
'result':
|
||||||
|
try:
|
||||||
|
self.we_accept_archiving(form)
|
||||||
|
except exceptions.NegotiationError, details:
|
||||||
|
self.fail_bad_negotiation(details)
|
||||||
|
|
||||||
return
|
return
|
||||||
elif self.status == 'responded-e2e' and form.getType() == 'result':
|
elif self.status == 'responded-e2e' and form.getType() == 'result':
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Reference in New Issue