Merging changes from trunk (6561:6774)
|
@ -12,7 +12,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1241">
|
||||
<widget class="GtkImage" id="image1235">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-network</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -32,7 +32,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1242">
|
||||
<widget class="GtkImage" id="image1236">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-connect</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -45,6 +45,14 @@
|
|||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="open_gmail_inbox_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Open Gmail Inbox</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="new_message_menuitem">
|
||||
<property name="visible">True</property>
|
||||
|
@ -52,7 +60,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1243">
|
||||
<widget class="GtkImage" id="image1237">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-new</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -72,7 +80,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1244">
|
||||
<widget class="GtkImage" id="image1238">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-add</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -92,7 +100,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1245">
|
||||
<widget class="GtkImage" id="image1239">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-find</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -132,7 +140,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1247">
|
||||
<widget class="GtkImage" id="image1240">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-preferences</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<property name="focus_on_map">True</property>
|
||||
<property name="urgency_hint">False</property>
|
||||
<signal name="key_press_event" handler="on_add_new_contact_window_key_press_event" last_modification_time="Thu, 28 Apr 2005 12:59:51 GMT"/>
|
||||
<signal name="destroy" handler="on_add_new_contact_window_destroy" last_modification_time="Thu, 03 Aug 2006 15:49:22 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox8">
|
||||
|
@ -51,185 +53,143 @@
|
|||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTable" id="table21">
|
||||
<widget class="GtkHBox" id="account_hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="account_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">A_ccount:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkComboBox" id="account_combobox">
|
||||
<property name="visible">True</property>
|
||||
<property name="items" translatable="yes"></property>
|
||||
<property name="add_tearoffs">False</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="protocol_hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="protocol_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Protocol:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="mnemonic_widget">uid_entry</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkComboBox" id="protocol_combobox">
|
||||
<property name="visible">True</property>
|
||||
<property name="items" translatable="yes"></property>
|
||||
<property name="add_tearoffs">False</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="changed" handler="on_protocol_combobox_changed" last_modification_time="Wed, 23 Mar 2005 13:13:12 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkComboBox" id="protocol_jid_combobox">
|
||||
<property name="visible">True</property>
|
||||
<property name="items" translatable="yes"></property>
|
||||
<property name="add_tearoffs">False</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTable" id="subscription_table">
|
||||
<property name="border_width">6</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">7</property>
|
||||
<property name="n_rows">4</property>
|
||||
<property name="n_columns">2</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="auto_authorize_checkbutton">
|
||||
<widget class="GtkLabel" id="uid_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">A_llow this contact to view my status</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">True</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">6</property>
|
||||
<property name="bottom_attach">7</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkComboBoxEntry" id="group_comboboxentry">
|
||||
<property name="visible">True</property>
|
||||
<property name="items" translatable="yes"></property>
|
||||
<property name="add_tearoffs">False</property>
|
||||
<property name="has_frame">True</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">5</property>
|
||||
<property name="bottom_attach">6</property>
|
||||
<property name="x_options">fill</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEntry" id="nickname_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="editable">True</property>
|
||||
<property name="visibility">True</property>
|
||||
<property name="max_length">0</property>
|
||||
<property name="text" translatable="yes"></property>
|
||||
<property name="has_frame">True</property>
|
||||
<property name="invisible_char">*</property>
|
||||
<property name="activates_default">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="bottom_attach">5</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEntry" id="jid_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="visibility">True</property>
|
||||
<property name="max_length">0</property>
|
||||
<property name="text" translatable="yes"></property>
|
||||
<property name="has_frame">True</property>
|
||||
<property name="invisible_char">*</property>
|
||||
<property name="activates_default">False</property>
|
||||
</widget>
|
||||
<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>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label223">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Group:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">1</property>
|
||||
<property name="top_attach">5</property>
|
||||
<property name="bottom_attach">6</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label188">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Nickname:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="mnemonic_widget">nickname_entry</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">1</property>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="bottom_attach">5</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label187">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Jabber ID:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">1</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="account_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Account:</property>
|
||||
<property name="label" translatable="yes">_User ID:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
|
@ -239,6 +199,7 @@
|
|||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="mnemonic_widget">uid_entry</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
|
@ -267,139 +228,129 @@
|
|||
<property name="activates_default">True</property>
|
||||
<signal name="changed" handler="on_uid_entry_changed" last_modification_time="Mon, 28 Feb 2005 23:05:24 GMT"/>
|
||||
</widget>
|
||||
<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>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label185">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_User ID:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="mnemonic_widget">uid_entry</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="protocol_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Protocol:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="mnemonic_widget">uid_entry</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="account_hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkComboBox" id="account_combobox">
|
||||
<property name="visible">True</property>
|
||||
<property name="items" translatable="yes"></property>
|
||||
<property name="add_tearoffs">False</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="protocol_hbox">
|
||||
<widget class="GtkLabel" id="label188">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
<property name="label" translatable="yes">_Nickname:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="mnemonic_widget">nickname_entry</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkComboBox" id="protocol_combobox">
|
||||
<property name="visible">True</property>
|
||||
<property name="items" translatable="yes"></property>
|
||||
<property name="add_tearoffs">False</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="changed" handler="on_protocol_combobox_changed" last_modification_time="Wed, 23 Mar 2005 13:13:12 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="nickname_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="editable">True</property>
|
||||
<property name="visibility">True</property>
|
||||
<property name="max_length">0</property>
|
||||
<property name="text" translatable="yes"></property>
|
||||
<property name="has_frame">True</property>
|
||||
<property name="invisible_char">*</property>
|
||||
<property name="activates_default">True</property>
|
||||
</widget>
|
||||
<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>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label223">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Group:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkComboBoxEntry" id="group_comboboxentry">
|
||||
<property name="visible">True</property>
|
||||
<property name="items" translatable="yes"></property>
|
||||
<property name="add_tearoffs">False</property>
|
||||
<property name="has_frame">True</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
</widget>
|
||||
<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>
|
||||
<property name="x_options">fill</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="auto_authorize_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">A_llow this contact to view my status</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">True</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<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>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
|
@ -411,7 +362,7 @@
|
|||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="scrolledwindow6">
|
||||
<widget class="GtkScrolledWindow" id="message_scrolledwindow">
|
||||
<property name="border_width">6</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
|
@ -447,6 +398,91 @@
|
|||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="register_hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label224">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">You have to register to this transport
|
||||
to be able to add a contact from this
|
||||
protocol. Click on register button to
|
||||
proceed.</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">True</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="register_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">_Register</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_register_button_clicked" last_modification_time="Thu, 03 Aug 2006 14:29:57 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="connected_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">You must be connected to the transport to be able
|
||||
to add a contact from this protocol.</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHButtonBox" id="hbuttonbox1">
|
||||
<property name="border_width">5</property>
|
||||
|
@ -468,78 +504,16 @@
|
|||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="subscribe_button">
|
||||
<widget class="GtkButton" id="add_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="has_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-add</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_subscribe_button_clicked" last_modification_time="Mon, 28 Feb 2005 22:46:16 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment39">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xscale">0</property>
|
||||
<property name="yscale">0</property>
|
||||
<property name="top_padding">0</property>
|
||||
<property name="bottom_padding">0</property>
|
||||
<property name="left_padding">0</property>
|
||||
<property name="right_padding">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox2915">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">2</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImage" id="image280">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-ok</property>
|
||||
<property name="icon_size">4</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label192">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Subscribe</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<signal name="clicked" handler="on_add_button_clicked" last_modification_time="Thu, 03 Aug 2006 14:27:55 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="default_height">260</property>
|
||||
<property name="default_height">290</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
|
@ -18,6 +18,7 @@
|
|||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<property name="focus_on_map">True</property>
|
||||
<property name="urgency_hint">False</property>
|
||||
<property name="has_separator">True</property>
|
||||
<signal name="response" handler="on_edit_groups_dialog_response" last_modification_time="Fri, 22 Jul 2005 22:28:44 GMT"/>
|
||||
|
||||
|
@ -159,7 +160,7 @@
|
|||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_NEVER</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="shadow_type">GTK_SHADOW_IN</property>
|
||||
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<property name="focus_on_map">True</property>
|
||||
<property name="urgency_hint">False</property>
|
||||
<signal name="key_press_event" handler="on_preferences_window_key_press_event" last_modification_time="Fri, 08 Apr 2005 01:08:08 GMT"/>
|
||||
<signal name="destroy" handler="on_preferences_window_destroy" last_modification_time="Sun, 05 Mar 2006 11:50:52 GMT"/>
|
||||
|
||||
|
@ -899,6 +900,7 @@ Per type</property>
|
|||
<widget class="GtkFontButton" id="conversation_fontbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="title" translatable="yes">Επιλογή μιας γραμματοσειράς</property>
|
||||
<property name="show_style">True</property>
|
||||
<property name="show_size">True</property>
|
||||
<property name="use_font">False</property>
|
||||
|
@ -950,6 +952,7 @@ Per type</property>
|
|||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="use_alpha">False</property>
|
||||
<property name="title" translatable="yes">Επιλογή χρώματος</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="color_set" handler="on_outgoing_msg_colorbutton_color_set" last_modification_time="Sun, 06 Mar 2005 14:07:56 GMT"/>
|
||||
</widget>
|
||||
|
@ -968,6 +971,7 @@ Per type</property>
|
|||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="use_alpha">False</property>
|
||||
<property name="title" translatable="yes">Επιλογή χρώματος</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="color_set" handler="on_url_msg_colorbutton_color_set" last_modification_time="Sun, 25 Dec 2005 15:22:17 GMT"/>
|
||||
</widget>
|
||||
|
@ -1095,6 +1099,7 @@ Per type</property>
|
|||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="use_alpha">False</property>
|
||||
<property name="title" translatable="yes">Επιλογή χρώματος</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="color_set" handler="on_incoming_msg_colorbutton_color_set" last_modification_time="Sun, 06 Mar 2005 14:07:44 GMT"/>
|
||||
</widget>
|
||||
|
@ -1113,6 +1118,7 @@ Per type</property>
|
|||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="use_alpha">False</property>
|
||||
<property name="title" translatable="yes">Επιλογή χρώματος</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="color_set" handler="on_status_msg_colorbutton_color_set" last_modification_time="Sun, 06 Mar 2005 14:08:04 GMT"/>
|
||||
</widget>
|
||||
|
@ -2537,6 +2543,78 @@ Disabled</property>
|
|||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEventBox" id="eventbox6">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">An example: If you have enabled status message for away, Gajim won't ask you anymore for a status message when you change your status to away; it will use the default one set here</property>
|
||||
<property name="visible_window">True</property>
|
||||
<property name="above_child">False</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkExpander" id="expander1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="expanded">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="scrolledwindow24">
|
||||
<property name="border_width">6</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="shadow_type">GTK_SHADOW_IN</property>
|
||||
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="default_msg_treeview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="headers_visible">True</property>
|
||||
<property name="rules_hint">False</property>
|
||||
<property name="reorderable">False</property>
|
||||
<property name="enable_search">True</property>
|
||||
<property name="fixed_height_mode">False</property>
|
||||
<property name="hover_selection">False</property>
|
||||
<property name="hover_expand">False</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label384">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Default Status Messages</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="type">label_item</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkFrame" id="frame22">
|
||||
<property name="visible">True</property>
|
||||
|
@ -3128,7 +3206,8 @@ Custom</property>
|
|||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="notify_gmail_extra_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">If checked, Gajim will also include information about the sender of the new emails</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Display _extra email details</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
@ -3137,7 +3216,7 @@ Custom</property>
|
|||
<property name="active">False</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_notify_gmail_extra_checkbutton_toggled" last_modification_time="Wed, 06 Apr 2005 14:43:56 GMT"/>
|
||||
<signal name="toggled" handler="on_notify_gmail_extra_checkbutton_toggled" last_modification_time="Wed, 06 Apr 2005 14:43:56 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
|
@ -3179,7 +3258,7 @@ Custom</property>
|
|||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
|
||||
<child>
|
||||
<widget class="GtkFrame" id="frame27">
|
||||
<property name="visible">True</property>
|
||||
|
@ -3245,7 +3324,6 @@ Custom</property>
|
|||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
|
1968
data/glade/profile_window.glade
Normal file
|
@ -12,7 +12,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1447">
|
||||
<widget class="GtkImage" id="image1511">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-jump-to</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -32,7 +32,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1448">
|
||||
<widget class="GtkImage" id="image1512">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-new</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -45,13 +45,33 @@
|
|||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="invite_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">In_vite to</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1513">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-go-back</property>
|
||||
<property name="icon_size">1</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="rename_menuitem">
|
||||
<property name="label" translatable="yes">_Rename</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1449">
|
||||
<widget class="GtkImage" id="image1514">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-refresh</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -84,7 +104,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1450">
|
||||
<widget class="GtkImage" id="image1515">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-file</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -104,7 +124,7 @@
|
|||
<signal name="activate" handler="on_assign_openpgp_key_menuitem_activate" last_modification_time="Thu, 30 Jun 2005 22:57:59 GMT"/>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1451">
|
||||
<widget class="GtkImage" id="image1516">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-dialog-authentication</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -124,7 +144,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1452">
|
||||
<widget class="GtkImage" id="image1517">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-info</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -169,7 +189,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1453">
|
||||
<widget class="GtkImage" id="image1518">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-dialog-question</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -190,7 +210,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1454">
|
||||
<widget class="GtkImage" id="image1519">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-go-up</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -210,7 +230,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1455">
|
||||
<widget class="GtkImage" id="image1520">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-go-down</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -230,7 +250,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1456">
|
||||
<widget class="GtkImage" id="image1521">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-stop</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -253,7 +273,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1457">
|
||||
<widget class="GtkImage" id="image1522">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-add</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -272,7 +292,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1458">
|
||||
<widget class="GtkImage" id="image1523">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-remove</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
@ -304,7 +324,7 @@
|
|||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1459">
|
||||
<widget class="GtkImage" id="image1524">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-justify-fill</property>
|
||||
<property name="icon_size">1</property>
|
||||
|
|
Before Width: | Height: | Size: 919 B After Width: | Height: | Size: 919 B |
Before Width: | Height: | Size: 944 B After Width: | Height: | Size: 944 B |
Before Width: | Height: | Size: 919 B After Width: | Height: | Size: 919 B |
Before Width: | Height: | Size: 944 B After Width: | Height: | Size: 944 B |
Before Width: | Height: | Size: 944 B After Width: | Height: | Size: 944 B |
Before Width: | Height: | Size: 919 B After Width: | Height: | Size: 919 B |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
BIN
data/pixmaps/events/connection_lost.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
data/pixmaps/person.png
Normal file
After Width: | Height: | Size: 594 B |
|
@ -1,3 +1,3 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
cd `dirname $0`/src
|
||||
exec python -t gajim.py $@
|
||||
exec -a gajim python -t gajim.py $@
|
||||
|
|
|
@ -9,6 +9,9 @@ all: $(LANGS_MO)
|
|||
%.mo: %.po
|
||||
msgfmt $< -o $@
|
||||
|
||||
%.glade.h: %.glade
|
||||
intltool-extract --type=gettext/glade $<
|
||||
|
||||
gajim.pot: ../src/*py ../src/common/*py \
|
||||
../data/glade/account_context_menu.glade.h \
|
||||
../data/glade/account_creation_wizard_window.glade.h \
|
||||
|
@ -16,6 +19,7 @@ gajim.pot: ../src/*py ../src/common/*py \
|
|||
../data/glade/accounts_window.glade.h \
|
||||
../data/glade/add_new_contact_window.glade.h \
|
||||
../data/glade/advanced_configuration_window.glade.h \
|
||||
../data/glade/advanced_notifications_window.glade.h \
|
||||
../data/glade/advanced_menuitem_menu.glade.h \
|
||||
../data/glade/change_password_dialog.glade.h \
|
||||
../data/glade/change_status_message_dialog.glade.h \
|
||||
|
|
|
@ -4,50 +4,50 @@
|
|||
|
||||
[encoding: UTF-8]
|
||||
gajim.desktop.in
|
||||
data/glade/account_context_menu.glade
|
||||
data/glade/account_creation_wizard_window.glade
|
||||
data/glade/account_modification_window.glade
|
||||
data/glade/accounts_window.glade
|
||||
data/glade/add_new_contact_window.glade
|
||||
data/glade/advanced_configuration_window.glade
|
||||
data/glade/advanced_menuitem_menu.glade
|
||||
data/glade/advanced_notifications_window.glade
|
||||
data/glade/change_password_dialog.glade
|
||||
data/glade/change_status_message_dialog.glade
|
||||
data/glade/chat_context_menu.glade
|
||||
data/glade/chat_control_popup_menu.glade
|
||||
data/glade/choose_gpg_key_dialog.glade
|
||||
data/glade/data_form_window.glade
|
||||
data/glade/edit_groups_dialog.glade
|
||||
data/glade/filetransfers.glade
|
||||
data/glade/gajim_themes_window.glade
|
||||
data/glade/gc_control_popup_menu.glade
|
||||
data/glade/gc_occupants_menu.glade
|
||||
data/glade/history_manager.glade
|
||||
data/glade/history_window.glade
|
||||
data/glade/input_dialog.glade
|
||||
data/glade/invitation_received_dialog.glade
|
||||
data/glade/join_groupchat_window.glade
|
||||
data/glade/manage_accounts_window.glade
|
||||
data/glade/manage_bookmarks_window.glade
|
||||
data/glade/manage_proxies_window.glade
|
||||
data/glade/message_window.glade
|
||||
data/glade/passphrase_dialog.glade
|
||||
data/glade/popup_notification_window.glade
|
||||
data/glade/preferences_window.glade
|
||||
data/glade/privacy_list_edit_window.glade
|
||||
data/glade/privacy_lists_first_window.glade
|
||||
data/glade/progress_dialog.glade
|
||||
data/glade/remove_account_window.glade
|
||||
data/glade/roster_contact_context_menu.glade
|
||||
data/glade/roster_window.glade
|
||||
data/glade/service_discovery_window.glade
|
||||
data/glade/service_registration_window.glade
|
||||
data/glade/single_message_window.glade
|
||||
data/glade/subscription_request_window.glade
|
||||
data/glade/systray_context_menu.glade
|
||||
data/glade/vcard_information_window.glade
|
||||
data/glade/xml_console_window.glade
|
||||
data/glade/account_context_menu.glade.h
|
||||
data/glade/account_creation_wizard_window.glade.h
|
||||
data/glade/account_modification_window.glade.h
|
||||
data/glade/accounts_window.glade.h
|
||||
data/glade/add_new_contact_window.glade.h
|
||||
data/glade/advanced_configuration_window.glade.h
|
||||
data/glade/advanced_menuitem_menu.glade.h
|
||||
data/glade/advanced_notifications_window.glade.h
|
||||
data/glade/change_password_dialog.glade.h
|
||||
data/glade/change_status_message_dialog.glade.h
|
||||
data/glade/chat_context_menu.glade.h
|
||||
data/glade/chat_control_popup_menu.glade.h
|
||||
data/glade/choose_gpg_key_dialog.glade.h
|
||||
data/glade/data_form_window.glade.h
|
||||
data/glade/edit_groups_dialog.glade.h
|
||||
data/glade/filetransfers.glade.h
|
||||
data/glade/gajim_themes_window.glade.h
|
||||
data/glade/gc_control_popup_menu.glade.h
|
||||
data/glade/gc_occupants_menu.glade.h
|
||||
data/glade/history_manager.glade.h
|
||||
data/glade/history_window.glade.h
|
||||
data/glade/input_dialog.glade.h
|
||||
data/glade/invitation_received_dialog.glade.h
|
||||
data/glade/join_groupchat_window.glade.h
|
||||
data/glade/manage_accounts_window.glade.h
|
||||
data/glade/manage_bookmarks_window.glade.h
|
||||
data/glade/manage_proxies_window.glade.h
|
||||
data/glade/message_window.glade.h
|
||||
data/glade/passphrase_dialog.glade.h
|
||||
data/glade/popup_notification_window.glade.h
|
||||
data/glade/preferences_window.glade.h
|
||||
data/glade/privacy_list_edit_window.glade.h
|
||||
data/glade/privacy_lists_first_window.glade.h
|
||||
data/glade/progress_dialog.glade.h
|
||||
data/glade/remove_account_window.glade.h
|
||||
data/glade/roster_contact_context_menu.glade.h
|
||||
data/glade/roster_window.glade.h
|
||||
data/glade/service_discovery_window.glade.h
|
||||
data/glade/service_registration_window.glade.h
|
||||
data/glade/single_message_window.glade.h
|
||||
data/glade/subscription_request_window.glade.h
|
||||
data/glade/systray_context_menu.glade.h
|
||||
data/glade/vcard_information_window.glade.h
|
||||
data/glade/xml_console_window.glade.h
|
||||
src/advanced.py
|
||||
src/cell_renderer_image.py
|
||||
src/chat_control.py
|
||||
|
|
2
po/eo.po
|
@ -2622,7 +2622,7 @@ msgstr "Fine ne malpli ol aliajn ni dankas ĉiujn pakaĵvartistojn."
|
|||
#. here you write your name in the form Name FamilyName <someone@somewhere>
|
||||
#: ../src/dialogs.py:610
|
||||
msgid "translator-credits"
|
||||
msgstr "tradukistoj"
|
||||
msgstr "Segrio Ĥliutĉin <Sergey.Khlutchin@gmail.com>"
|
||||
|
||||
#: ../src/dialogs.py:873
|
||||
#, python-format
|
||||
|
|
2
po/sk.po
|
@ -1982,7 +1982,7 @@ msgstr "Extra adresa:"
|
|||
#. Family Name
|
||||
#: ../data/glade/vcard_information_window.glade.h:15
|
||||
msgid "Family:"
|
||||
msgstr "Priezvysko:"
|
||||
msgstr "Priezvisko:"
|
||||
|
||||
#: ../data/glade/vcard_information_window.glade.h:16
|
||||
msgid "Format: YYYY-MM-DD"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
## gajim
|
||||
##
|
||||
## Contributors for this file:
|
||||
|
@ -29,4 +29,4 @@ fi
|
|||
|
||||
cd PREFIX/share/gajim/src
|
||||
export PYTHONPATH="$PYTHONPATH:PREFIXLIB/gajim"
|
||||
exec PYTHON_EXEC -OO gajim.py $@
|
||||
exec -a gajim PYTHON_EXEC -OO gajim.py $@
|
||||
|
|
11
src/Makefile
|
@ -1,21 +1,24 @@
|
|||
# Set the C flags to include the GTK+ and Python libraries
|
||||
PYTHON ?= python
|
||||
PYTHONVER = `$(PYTHON) -c 'import sys; print sys.version[:3]'`
|
||||
CFLAGS = `pkg-config --cflags gtk+-2.0 pygtk-2.0` -fPIC -I/usr/include/python$(PYTHONVER) -I.
|
||||
LDFLAGS = `pkg-config --libs gtk+-2.0 pygtk-2.0` -lpython$(PYTHONVER)
|
||||
gtk_CFLAGS = `pkg-config --cflags gtk+-2.0 pygtk-2.0` -fPIC -I/usr/include/python$(PYTHONVER) -I.
|
||||
gtk_LDFLAGS = `pkg-config --libs gtk+-2.0 pygtk-2.0` -lpython$(PYTHONVER)
|
||||
|
||||
all: trayicon.so gtkspell.so
|
||||
|
||||
# Build the shared objects
|
||||
trayicon.so: trayicon.o eggtrayicon.o trayiconmodule.o
|
||||
$(CC) -shared $^ -o $@ $(LDFLAGS)
|
||||
$(CC) -shared $^ -o $@ $(LDFLAGS) $(gtk_LDFLAGS)
|
||||
|
||||
gtkspell.so:
|
||||
$(CC) $(OPTFLAGS) $(CFLAGS) `pkg-config --cflags gtkspell-2.0` -shared gtkspellmodule.c $^ -o $@ $(LDFLAGS) `pkg-config --libs gtkspell-2.0`
|
||||
$(CC) $(OPTFLAGS) $(CFLAGS) $(LDFLAGS) $(gtk_CFLAGS) $(gtk_LDFLAGS) `pkg-config --libs --cflags gtkspell-2.0` -shared gtkspellmodule.c $^ -o $@
|
||||
|
||||
# The path to the GTK+ python types
|
||||
DEFS=`pkg-config --variable=defsdir pygtk-2.0`
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -o $@ -c $< $(CFLAGS) $(gtk_CFLAGS)
|
||||
|
||||
# Generate the C wrapper from the defs and our override file
|
||||
trayicon.c: trayicon.defs trayicon.override
|
||||
pygtk-codegen-2.0 --prefix trayicon \
|
||||
|
|
|
@ -46,6 +46,8 @@ class AdvancedConfigurationWindow:
|
|||
def __init__(self):
|
||||
self.xml = gtkgui_helpers.get_glade('advanced_configuration_window.glade')
|
||||
self.window = self.xml.get_widget('advanced_configuration_window')
|
||||
self.window.set_transient_for(
|
||||
gajim.interface.instances['preferences'].window)
|
||||
self.entry = self.xml.get_widget('advanced_entry')
|
||||
self.desc_label = self.xml.get_widget('advanced_desc_label')
|
||||
self.restart_label = self.xml.get_widget('restart_label')
|
||||
|
|
|
@ -24,6 +24,7 @@ import gtkgui_helpers
|
|||
import message_control
|
||||
import dialogs
|
||||
import history_window
|
||||
import notify
|
||||
|
||||
from common import gajim
|
||||
from common import helpers
|
||||
|
@ -41,6 +42,14 @@ except:
|
|||
HAS_GTK_SPELL = False
|
||||
|
||||
|
||||
# the next script, executed in the "po" directory,
|
||||
# generates the following list.
|
||||
##!/bin/sh
|
||||
#LANG=$(for i in *.po; do j=${i/.po/}; echo -n "_('"$j"')":" '"$j"', " ; done)
|
||||
#echo "{_('en'):'en'",$LANG"}"
|
||||
langs = {_('English'): 'en', _('Bulgarian'): 'bg', _('Briton'): 'br', _('Czech'): 'cs', _('German'): 'de', _('Greek'): 'el', _('Esperanto'): 'eo', _('Spanish'): 'es', _('Basc'): 'eu', _('French'): 'fr', _('Croatian'): 'hr', _('Italian'): 'it', _('Norvegian b'): 'nb', _('Dutch'): 'nl', _('Norvegian'): 'no', _('Polish'): 'pl', _('Portuguese'): 'pt', _('Brazilian Portuguese'): 'pt_BR', _('Russian'): 'ru', _('Slovak'): 'sk', _('Swedish'): 'sv', _('Chinese (Ch)'): 'zh_CN'}
|
||||
|
||||
|
||||
################################################################################
|
||||
class ChatControlBase(MessageControl):
|
||||
'''A base class containing a banner, ConversationTextview, MessageTextView
|
||||
|
@ -50,7 +59,7 @@ class ChatControlBase(MessageControl):
|
|||
theme = gajim.config.get('roster_theme')
|
||||
bannerfont = gajim.config.get_per('themes', theme, 'bannerfont')
|
||||
bannerfontattrs = gajim.config.get_per('themes', theme, 'bannerfontattrs')
|
||||
|
||||
|
||||
if bannerfont:
|
||||
font = pango.FontDescription(bannerfont)
|
||||
else:
|
||||
|
@ -61,16 +70,24 @@ class ChatControlBase(MessageControl):
|
|||
font.set_weight(pango.WEIGHT_HEAVY)
|
||||
if 'I' in bannerfontattrs:
|
||||
font.set_style(pango.STYLE_ITALIC)
|
||||
|
||||
|
||||
font_attrs = 'font_desc="%s"' % font.to_string()
|
||||
|
||||
|
||||
# in case there is no font specified we use x-large font size
|
||||
if font.get_size() == 0:
|
||||
font_attrs = '%s size="x-large"' % font_attrs
|
||||
font.set_weight(pango.WEIGHT_NORMAL)
|
||||
font_attrs_small = 'font_desc="%s" size="small"' % font.to_string()
|
||||
return (font_attrs, font_attrs_small)
|
||||
|
||||
|
||||
def get_nb_unread(self):
|
||||
jid = self.contact.jid
|
||||
if self.resource:
|
||||
jid += '/' + self.resource
|
||||
type_ = self.type_id
|
||||
return len(gajim.events.get_events(self.account, jid, ['printed_' + type_,
|
||||
type_]))
|
||||
|
||||
def draw_banner(self):
|
||||
self._paint_banner()
|
||||
self._update_banner_state_image()
|
||||
|
@ -99,7 +116,7 @@ class ChatControlBase(MessageControl):
|
|||
widget = self.xml.get_widget('emoticons_button')
|
||||
id = widget.connect('clicked', self.on_emoticons_button_clicked)
|
||||
self.handlers[id] = widget
|
||||
|
||||
|
||||
id = self.widget.connect('key_press_event', self._on_keypress_event)
|
||||
self.handlers[id] = self.widget
|
||||
|
||||
|
@ -107,10 +124,10 @@ class ChatControlBase(MessageControl):
|
|||
id = widget.connect('button-press-event',
|
||||
self._on_banner_eventbox_button_press_event)
|
||||
self.handlers[id] = widget
|
||||
|
||||
|
||||
# Create textviews and connect signals
|
||||
self.conv_textview = ConversationTextview(self.account)
|
||||
|
||||
|
||||
self.conv_scrolledwindow = self.xml.get_widget(
|
||||
'conversation_scrolledwindow')
|
||||
self.conv_scrolledwindow.add(self.conv_textview.tv)
|
||||
|
@ -122,20 +139,23 @@ class ChatControlBase(MessageControl):
|
|||
self.msg_scrolledwindow = self.xml.get_widget('message_scrolledwindow')
|
||||
self.msg_textview = MessageTextView()
|
||||
id = self.msg_textview.connect('mykeypress',
|
||||
self._on_message_textview_mykeypress_event)
|
||||
self._on_message_textview_mykeypress_event)
|
||||
self.handlers[id] = self.msg_textview
|
||||
self.msg_scrolledwindow.add(self.msg_textview)
|
||||
id = self.msg_textview.connect('key_press_event',
|
||||
self._on_message_textview_key_press_event)
|
||||
self._on_message_textview_key_press_event)
|
||||
self.handlers[id] = self.msg_textview
|
||||
id = self.msg_textview.connect('size-request', self.size_request)
|
||||
self.handlers[id] = self.msg_textview
|
||||
id = self.msg_textview.connect('populate_popup',
|
||||
self.on_msg_textview_populate_popup)
|
||||
self.handlers[id] = self.msg_textview
|
||||
|
||||
self.update_font()
|
||||
|
||||
# Hook up send button
|
||||
widget = self.xml.get_widget('send_button')
|
||||
id = widget.connect('clicked',
|
||||
self._on_send_button_clicked)
|
||||
id = widget.connect('clicked', self._on_send_button_clicked)
|
||||
self.handlers[id] = widget
|
||||
|
||||
# the following vars are used to keep history of user's messages
|
||||
|
@ -144,8 +164,6 @@ class ChatControlBase(MessageControl):
|
|||
self.typing_new = False
|
||||
self.orig_msg = ''
|
||||
|
||||
self.nb_unread = 0
|
||||
|
||||
# Emoticons menu
|
||||
# set image no matter if user wants at this time emoticons or not
|
||||
# (so toggle works ok)
|
||||
|
@ -157,8 +175,27 @@ class ChatControlBase(MessageControl):
|
|||
# Attach speller
|
||||
if gajim.config.get('use_speller') and HAS_GTK_SPELL:
|
||||
try:
|
||||
gtkspell.Spell(self.msg_textview)
|
||||
except gobject.GError, msg:
|
||||
spell = gtkspell.Spell(self.msg_textview)
|
||||
# loop removing non-existant dictionaries
|
||||
# iterating on a copy
|
||||
for lang in dict(langs):
|
||||
try:
|
||||
spell.set_language(langs[lang])
|
||||
except:
|
||||
del langs[lang]
|
||||
# now set the one the user selected
|
||||
per_type = 'contacts'
|
||||
if self.type_id == message_control.TYPE_GC:
|
||||
per_type = 'rooms'
|
||||
lang = gajim.config.get_per(per_type, self.contact.jid,
|
||||
'speller_language')
|
||||
if not lang:
|
||||
# use the default one
|
||||
lang = gajim.config.get('speller_language')
|
||||
if lang:
|
||||
self.msg_textview.lang = lang
|
||||
spell.set_language(lang)
|
||||
except (gobject.GError, RuntimeError), msg:
|
||||
#FIXME: add a ui for this use spell.set_language()
|
||||
dialogs.ErrorDialog(unicode(msg), _('If that is not your language '
|
||||
'for which you want to highlight misspelled words, then please '
|
||||
|
@ -174,6 +211,44 @@ class ChatControlBase(MessageControl):
|
|||
# For JEP-0172
|
||||
self.user_nick = None
|
||||
|
||||
def on_msg_textview_populate_popup(self, textview, menu):
|
||||
'''we override the default context menu and we prepend an option to switch languages'''
|
||||
def _on_select_dictionary(widget, lang):
|
||||
per_type = 'contacts'
|
||||
if self.type_id == message_control.TYPE_GC:
|
||||
per_type = 'rooms'
|
||||
if not gajim.config.get_per(per_type, self.contact.jid):
|
||||
gajim.config.add_per(per_type, self.contact.jid)
|
||||
gajim.config.set_per(per_type, self.contact.jid, 'speller_language',
|
||||
lang)
|
||||
spell = gtkspell.get_from_text_view(self.msg_textview)
|
||||
self.msg_textview.lang = lang
|
||||
spell.set_language(lang)
|
||||
widget.set_active(True)
|
||||
|
||||
item = gtk.SeparatorMenuItem()
|
||||
menu.prepend(item)
|
||||
|
||||
if gajim.config.get('use_speller') and HAS_GTK_SPELL:
|
||||
item = gtk.MenuItem(_('Spelling language'))
|
||||
menu.prepend(item)
|
||||
submenu = gtk.Menu()
|
||||
item.set_submenu(submenu)
|
||||
for lang in sorted(langs):
|
||||
item = gtk.CheckMenuItem(lang)
|
||||
if langs[lang] == self.msg_textview.lang:
|
||||
item.set_active(True)
|
||||
submenu.append(item)
|
||||
id = item.connect('activate', _on_select_dictionary, langs[lang])
|
||||
self.handlers[id] = item
|
||||
|
||||
item = gtk.ImageMenuItem(gtk.STOCK_CLEAR)
|
||||
menu.prepend(item)
|
||||
id = item.connect('activate', self.msg_textview.clear)
|
||||
self.handlers[id] = item
|
||||
|
||||
menu.show_all()
|
||||
|
||||
# moved from ChatControl
|
||||
def _on_banner_eventbox_button_press_event(self, widget, event):
|
||||
'''If right-clicked, show popup'''
|
||||
|
@ -250,7 +325,7 @@ class ChatControlBase(MessageControl):
|
|||
if event.state & gtk.gdk.CONTROL_MASK:
|
||||
# CTRL + l|L: clear conv_textview
|
||||
if event.keyval == gtk.keysyms.l or event.keyval == gtk.keysyms.L:
|
||||
self.conv_textview.tv.get_buffer().set_text('')
|
||||
self.conv_textview.clear()
|
||||
return True
|
||||
# CTRL + v: Paste into msg_textview
|
||||
elif event.keyval == gtk.keysyms.v:
|
||||
|
@ -477,12 +552,25 @@ class ChatControlBase(MessageControl):
|
|||
gajim.last_message_time[self.account][full_jid] = time.time()
|
||||
urgent = True
|
||||
if (not self.parent_win.get_active_jid() or \
|
||||
full_jid != self.parent_win.get_active_jid() or \
|
||||
not self.parent_win.is_active() or not end) and \
|
||||
kind in ('incoming', 'incoming_queue'):
|
||||
self.nb_unread += 1
|
||||
if gajim.interface.systray_enabled and self.notify_on_new_messages():
|
||||
gajim.interface.systray.add_jid(full_jid, self.account, self.type_id)
|
||||
full_jid != self.parent_win.get_active_jid() or \
|
||||
not self.parent_win.is_active() or not end) and \
|
||||
kind in ('incoming', 'incoming_queue'):
|
||||
if self.notify_on_new_messages():
|
||||
type_ = 'printed_' + self.type_id
|
||||
if self.type_id == message_control.TYPE_GC:
|
||||
type_ = 'printed_gc_msg'
|
||||
show_in_roster = notify.get_show_in_roster('message_received',
|
||||
self.account, self.contact)
|
||||
show_in_systray = notify.get_show_in_systray('message_received',
|
||||
self.account, self.contact)
|
||||
event = gajim.events.create_event(type_, None,
|
||||
show_in_roster = show_in_roster,
|
||||
show_in_systray = show_in_systray)
|
||||
gajim.events.add_event(self.account, full_jid, event)
|
||||
# We need to redraw contact if we show in roster
|
||||
if show_in_roster:
|
||||
gajim.interface.roster.draw_contact(self.contact.jid,
|
||||
self.account)
|
||||
self.parent_win.redraw_tab(self)
|
||||
if not self.parent_win.is_active():
|
||||
ctrl = gajim.interface.msg_win_mgr.get_control(full_jid,
|
||||
|
@ -507,6 +595,7 @@ class ChatControlBase(MessageControl):
|
|||
else: # we are the beginning of buffer
|
||||
buffer.insert_at_cursor('%s ' % str_)
|
||||
self.msg_textview.grab_focus()
|
||||
|
||||
def on_emoticons_button_clicked(self, widget):
|
||||
'''popup emoticons menu'''
|
||||
gajim.interface.emoticon_menuitem_clicked = self.append_emoticon
|
||||
|
@ -551,15 +640,24 @@ class ChatControlBase(MessageControl):
|
|||
if state:
|
||||
jid = self.contact.jid
|
||||
if self.conv_textview.at_the_end():
|
||||
#we are at the end
|
||||
if self.nb_unread > 0:
|
||||
self.nb_unread = self.get_specific_unread()
|
||||
# we are at the end
|
||||
type_ = 'printed_' + self.type_id
|
||||
if self.type_id == message_control.TYPE_GC:
|
||||
type_ = 'printed_gc_msg'
|
||||
if not gajim.events.remove_events(self.account, self.get_full_jid(),
|
||||
types = [type_]):
|
||||
# There were events to remove
|
||||
self.parent_win.redraw_tab(self)
|
||||
self.parent_win.show_title()
|
||||
if gajim.interface.systray_enabled:
|
||||
gajim.interface.systray.remove_jid(self.get_full_jid(),
|
||||
self.account,
|
||||
self.type_id)
|
||||
# redraw roster
|
||||
if self.type_id == message_control.TYPE_PM:
|
||||
room_jid, nick = gajim.get_room_and_nick_from_fjid(jid)
|
||||
groupchat_control = gajim.interface.msg_win_mgr.get_control(
|
||||
room_jid, self.account)
|
||||
groupchat_control.draw_contact(nick)
|
||||
else:
|
||||
gajim.interface.roster.draw_contact(jid, self.account)
|
||||
gajim.interface.roster.show_title()
|
||||
self.msg_textview.grab_focus()
|
||||
# Note, we send None chatstate to preserve current
|
||||
self.parent_win.redraw_tab(self)
|
||||
|
@ -632,22 +730,28 @@ class ChatControlBase(MessageControl):
|
|||
return True
|
||||
|
||||
def on_conversation_vadjustment_value_changed(self, widget):
|
||||
if not self.nb_unread:
|
||||
return
|
||||
if self.resource:
|
||||
jid = self.contact.get_full_jid()
|
||||
else:
|
||||
jid = self.contact.jid
|
||||
type_ = self.type_id
|
||||
if type_ == message_control.TYPE_GC:
|
||||
type_ = 'gc_msg'
|
||||
if not len(gajim.events.get_events(self.account, jid, ['printed_' + type_,
|
||||
type_])):
|
||||
return
|
||||
if self.conv_textview.at_the_end() and \
|
||||
self.parent_win.get_active_control() == self and \
|
||||
self.parent_win.window.is_active():
|
||||
#we are at the end
|
||||
self.nb_unread = self.get_specific_unread()
|
||||
self.parent_win.redraw_tab(self)
|
||||
self.parent_win.show_title()
|
||||
if gajim.interface.systray_enabled:
|
||||
gajim.interface.systray.remove_jid(jid, self.account,
|
||||
self.type_id)
|
||||
# we are at the end
|
||||
type_ = self.type_id
|
||||
if type_ == message_control.TYPE_GC:
|
||||
type_ = 'gc_msg'
|
||||
if not gajim.events.remove_events(self.account, self.get_full_jid(),
|
||||
types = ['printed_' + type_, type_]):
|
||||
# There were events to remove
|
||||
self.parent_win.redraw_tab(self)
|
||||
self.parent_win.show_title()
|
||||
|
||||
def sent_messages_scroll(self, direction, conv_buf):
|
||||
size = len(self.sent_history)
|
||||
|
@ -706,6 +810,7 @@ class ChatControlBase(MessageControl):
|
|||
def got_disconnected(self):
|
||||
self.msg_textview.set_sensitive(False)
|
||||
self.msg_textview.set_editable(False)
|
||||
self.conv_textview.tv.grab_focus()
|
||||
self.xml.get_widget('send_button').set_sensitive(False)
|
||||
|
||||
################################################################################
|
||||
|
@ -776,6 +881,8 @@ class ChatControl(ChatControlBase):
|
|||
self.update_ui()
|
||||
# restore previous conversation
|
||||
self.restore_conversation()
|
||||
# is account displayed after nick in banner ?
|
||||
self.account_displayed= False
|
||||
|
||||
def notify_on_new_messages(self):
|
||||
return gajim.config.get('trayicon_notification_on_new_messages')
|
||||
|
@ -898,17 +1005,27 @@ class ChatControl(ChatControlBase):
|
|||
if self.resource:
|
||||
name += '/' + self.resource
|
||||
avoid_showing_account_too = True
|
||||
if self.TYPE_ID == message_control.TYPE_PM:
|
||||
room_jid = self.contact.jid.split('/')[0]
|
||||
room_ctrl = gajim.interface.msg_win_mgr.get_control(room_jid,
|
||||
self.account)
|
||||
name = _('%s from room %s') % (name, room_ctrl.name)
|
||||
name = gtkgui_helpers.escape_for_pango_markup(name)
|
||||
|
||||
# We know our contacts nick, but if there are any other controls
|
||||
# with the same nick we need to also display the account
|
||||
# except if we are talking to two different resources of the same contact
|
||||
acct_info = ''
|
||||
self.account_displayed = False
|
||||
for ctrl in self.parent_win.controls():
|
||||
if ctrl == self:
|
||||
continue
|
||||
if self.contact.get_shown_name() == ctrl.contact.get_shown_name()\
|
||||
and not avoid_showing_account_too:
|
||||
self.account_displayed = True
|
||||
if not ctrl.account_displayed:
|
||||
# do that after this instance exists
|
||||
gobject.idle_add(ctrl.draw_banner)
|
||||
acct_info = ' (%s)' % \
|
||||
gtkgui_helpers.escape_for_pango_markup(self.account)
|
||||
break
|
||||
|
@ -925,9 +1042,9 @@ class ChatControl(ChatControlBase):
|
|||
if cs and st in ('composing_only', 'all'):
|
||||
if contact.show == 'offline':
|
||||
chatstate = ''
|
||||
elif st == 'all' and contact.composing_jep == 'JEP-0085':
|
||||
elif contact.composing_jep == 'JEP-0085':
|
||||
chatstate = helpers.get_uf_chatstate(cs)
|
||||
elif st == 'composing_only' or contact.composing_jep == 'JEP-0022':
|
||||
elif contact.composing_jep == 'JEP-0022':
|
||||
if cs in ('composing', 'paused'):
|
||||
# only print composing, paused
|
||||
chatstate = helpers.get_uf_chatstate(cs)
|
||||
|
@ -935,16 +1052,16 @@ class ChatControl(ChatControlBase):
|
|||
chatstate = ''
|
||||
elif chatstate is None:
|
||||
chatstate = helpers.get_uf_chatstate(cs)
|
||||
|
||||
|
||||
label_text = '<span %s>%s</span><span %s>%s %s</span>' % \
|
||||
(font_attrs, name, font_attrs_small, acct_info, chatstate)
|
||||
(font_attrs, name, font_attrs_small, acct_info, chatstate)
|
||||
else:
|
||||
# weight="heavy" size="x-large"
|
||||
label_text = '<span %s>%s</span><span %s>%s</span>' % \
|
||||
(font_attrs, name, font_attrs_small, acct_info)
|
||||
(font_attrs, name, font_attrs_small, acct_info)
|
||||
if status_escaped:
|
||||
label_text += '\n<span %s>%s</span>' %\
|
||||
(font_attrs_small, status_escaped)
|
||||
(font_attrs_small, status_escaped)
|
||||
banner_eventbox = self.xml.get_widget('banner_eventbox')
|
||||
self.status_tooltip.set_tip(banner_eventbox, status)
|
||||
self.status_tooltip.enable()
|
||||
|
@ -952,7 +1069,7 @@ class ChatControl(ChatControlBase):
|
|||
self.status_tooltip.disable()
|
||||
# setup the label that holds name and jid
|
||||
banner_name_label.set_markup(label_text)
|
||||
|
||||
|
||||
def on_toggle_gpg_togglebutton(self, widget):
|
||||
gajim.config.set_per('contacts', self.contact.get_full_jid(),
|
||||
'gpg_enabled', widget.get_active())
|
||||
|
@ -967,12 +1084,12 @@ class ChatControl(ChatControlBase):
|
|||
tt = _('OpenPGP Encryption')
|
||||
|
||||
# restore gpg pref
|
||||
gpg_pref = gajim.config.get_per('contacts',
|
||||
self.contact.get_full_jid(), 'gpg_enabled')
|
||||
gpg_pref = gajim.config.get_per('contacts', self.contact.jid,
|
||||
'gpg_enabled')
|
||||
if gpg_pref == None:
|
||||
gajim.config.add_per('contacts', self.contact.get_full_jid())
|
||||
gpg_pref = gajim.config.get_per('contacts',
|
||||
self.contact.get_full_jid(), 'gpg_enabled')
|
||||
gajim.config.add_per('contacts', self.contact.jid)
|
||||
gpg_pref = gajim.config.get_per('contacts', self.contact.jid,
|
||||
'gpg_enabled')
|
||||
tb.set_active(gpg_pref)
|
||||
|
||||
else:
|
||||
|
@ -1132,7 +1249,12 @@ class ChatControl(ChatControlBase):
|
|||
|
||||
def get_tab_label(self, chatstate):
|
||||
unread = ''
|
||||
num_unread = self.nb_unread
|
||||
if self.resource:
|
||||
jid = self.contact.get_full_jid()
|
||||
else:
|
||||
jid = self.contact.jid
|
||||
num_unread = len(gajim.events.get_events(self.account, jid,
|
||||
['printed_' + self.type_id, self.type_id]))
|
||||
if num_unread == 1 and not gajim.config.get('show_unread_tab_icon'):
|
||||
unread = '*'
|
||||
elif num_unread > 1:
|
||||
|
@ -1175,7 +1297,12 @@ class ChatControl(ChatControlBase):
|
|||
return (label_str, color)
|
||||
|
||||
def get_tab_image(self):
|
||||
num_unread = self.nb_unread
|
||||
if self.resource:
|
||||
jid = self.contact.get_full_jid()
|
||||
else:
|
||||
jid = self.contact.jid
|
||||
num_unread = len(gajim.events.get_events(self.account, jid,
|
||||
['printed_' + self.type_id, self.type_id]))
|
||||
# Set tab image (always 16x16); unread messages show the 'message' image
|
||||
tab_img = None
|
||||
|
||||
|
@ -1184,8 +1311,8 @@ class ChatControl(ChatControlBase):
|
|||
self.contact.jid, icon_name = 'message')
|
||||
tab_img = img_16['message']
|
||||
else:
|
||||
contact = gajim.contacts.get_contact_with_highest_priority(self.account,
|
||||
self.contact.jid)
|
||||
contact = gajim.contacts.get_contact_with_highest_priority(
|
||||
self.account, self.contact.jid)
|
||||
if not contact or self.resource:
|
||||
# For transient contacts
|
||||
contact = self.contact
|
||||
|
@ -1361,10 +1488,9 @@ class ChatControl(ChatControlBase):
|
|||
# Remove bigger avatar window
|
||||
if self.bigger_avatar_window:
|
||||
self.bigger_avatar_window.destroy()
|
||||
# Clean up systray
|
||||
if gajim.interface.systray_enabled and self.nb_unread > 0:
|
||||
gajim.interface.systray.remove_jid(self.contact.jid, self.account,
|
||||
self.type_id)
|
||||
# Clean events
|
||||
gajim.events.remove_events(self.account, self.get_full_jid(),
|
||||
types = ['printed_' + self.type_id, self.type_id])
|
||||
# remove all register handlers on wigets, created by self.xml
|
||||
# to prevent circular references among objects
|
||||
for i in self.handlers.keys():
|
||||
|
@ -1381,7 +1507,7 @@ class ChatControl(ChatControlBase):
|
|||
# 2 seconds
|
||||
dialog = dialogs.ConfirmationDialog(
|
||||
#%s is being replaced in the code with JID
|
||||
_('You just received a new message from "%s"' % self.contact.jid),
|
||||
_('You just received a new message from "%s"') % self.contact.jid,
|
||||
_('If you close this tab and you have history disabled, '\
|
||||
'this message will be lost.'))
|
||||
if dialog.get_response() != gtk.RESPONSE_OK:
|
||||
|
@ -1466,14 +1592,11 @@ class ChatControl(ChatControlBase):
|
|||
if restore_how_many <= 0:
|
||||
return
|
||||
timeout = gajim.config.get('restore_timeout') # in minutes
|
||||
# number of messages that are in queue and are already logged
|
||||
pending_how_many = 0 # we want to avoid duplication
|
||||
|
||||
if gajim.awaiting_events[self.account].has_key(jid):
|
||||
events = gajim.awaiting_events[self.account][jid]
|
||||
for event in events:
|
||||
if event[0] == 'chat':
|
||||
pending_how_many += 1
|
||||
events = gajim.events.get_events(self.account, jid, ['chat'])
|
||||
# number of messages that are in queue and are already logged, we want
|
||||
# to avoid duplication
|
||||
pending_how_many = len(events)
|
||||
|
||||
rows = gajim.logger.get_last_conversation_lines(jid, restore_how_many,
|
||||
pending_how_many, timeout, self.account)
|
||||
|
@ -1492,10 +1615,14 @@ class ChatControl(ChatControlBase):
|
|||
|
||||
tim = time.localtime(float(row[0]))
|
||||
|
||||
if gajim.config.get('restored_messages_small'):
|
||||
small_attr = ['small']
|
||||
else:
|
||||
small_attr = []
|
||||
ChatControlBase.print_conversation_line(self, row[2], kind, name, tim,
|
||||
['small'],
|
||||
['small', 'restored_message'],
|
||||
['small', 'restored_message'],
|
||||
small_attr,
|
||||
small_attr + ['restored_message'],
|
||||
small_attr + ['restored_message'],
|
||||
False, old_kind = local_old_kind)
|
||||
if row[2].startswith('/me ') or row[2].startswith('/me\n'):
|
||||
local_old_kind = None
|
||||
|
@ -1510,7 +1637,7 @@ class ChatControl(ChatControlBase):
|
|||
jid_with_resource = jid
|
||||
if self.resource:
|
||||
jid_with_resource += '/' + self.resource
|
||||
l = gajim.awaiting_events[self.account][jid_with_resource]
|
||||
events = gajim.events.get_events(self.account, jid_with_resource)
|
||||
|
||||
# Is it a pm ?
|
||||
is_pm = False
|
||||
|
@ -1518,15 +1645,12 @@ class ChatControl(ChatControlBase):
|
|||
control = gajim.interface.msg_win_mgr.get_control(room_jid, self.account)
|
||||
if control and control.type_id == message_control.TYPE_GC:
|
||||
is_pm = True
|
||||
events_to_keep = []
|
||||
# list of message ids which should be marked as read
|
||||
message_ids = []
|
||||
for event in l:
|
||||
typ = event[0]
|
||||
if typ != 'chat':
|
||||
events_to_keep.append(event)
|
||||
for event in events:
|
||||
if event.type_ != self.type_id:
|
||||
continue
|
||||
data = event[1]
|
||||
data = event.parameters
|
||||
kind = data[2]
|
||||
if kind == 'error':
|
||||
kind = 'info'
|
||||
|
@ -1536,33 +1660,31 @@ class ChatControl(ChatControlBase):
|
|||
encrypted = data[4], subject = data[1])
|
||||
if len(data) > 6 and isinstance(data[6], int):
|
||||
message_ids.append(data[6])
|
||||
# remove from gc nb_unread if it's pm or from roster
|
||||
if is_pm:
|
||||
control.nb_unread -= 1
|
||||
else:
|
||||
gajim.interface.roster.nb_unread -= 1
|
||||
if message_ids:
|
||||
gajim.logger.set_read_messages(message_ids)
|
||||
if is_pm:
|
||||
control.parent_win.show_title()
|
||||
else:
|
||||
gajim.interface.roster.show_title()
|
||||
# Keep only non-messages events
|
||||
if len(events_to_keep):
|
||||
gajim.awaiting_events[self.account][jid_with_resource] = events_to_keep
|
||||
else:
|
||||
del gajim.awaiting_events[self.account][jid_with_resource]
|
||||
gajim.events.remove_events(self.account, jid_with_resource,
|
||||
types = [self.type_id])
|
||||
|
||||
self.parent_win.show_title()
|
||||
self.parent_win.redraw_tab(self)
|
||||
# redraw roster
|
||||
gajim.interface.roster.show_title()
|
||||
|
||||
typ = 'chat' # Is it a normal chat or a pm ?
|
||||
# reset to status image in gc if it is a pm
|
||||
if is_pm:
|
||||
control.update_ui()
|
||||
typ = 'pm'
|
||||
|
||||
gajim.interface.roster.draw_contact(jid, self.account)
|
||||
if is_pm:
|
||||
room_jid, nick = gajim.get_room_and_nick_from_fjid(jid)
|
||||
groupchat_control = gajim.interface.msg_win_mgr.get_control(
|
||||
room_jid, self.account)
|
||||
groupchat_control.draw_contact(nick)
|
||||
else:
|
||||
gajim.interface.roster.draw_contact(jid, self.account)
|
||||
# Redraw parent too
|
||||
gajim.interface.roster.draw_parent_contact(jid, self.account)
|
||||
if gajim.interface.systray_enabled:
|
||||
gajim.interface.systray.remove_jid(jid_with_resource, self.account, typ)
|
||||
if (self.contact.show == 'offline' or self.contact.show == 'error'):
|
||||
showOffline = gajim.config.get('showoffline')
|
||||
if not showOffline and typ == 'chat' and \
|
||||
|
@ -1592,7 +1714,7 @@ class ChatControl(ChatControlBase):
|
|||
# It's why I set it transparent.
|
||||
image = self.xml.get_widget('avatar_image')
|
||||
pixbuf = image.get_pixbuf()
|
||||
pixbuf.fill(0xffffff00) # RGBA
|
||||
pixbuf.fill(0xffffff00L) # RGBA
|
||||
image.queue_draw()
|
||||
|
||||
screen_w = gtk.gdk.screen_width()
|
||||
|
|
|
@ -138,7 +138,7 @@ else:
|
|||
def verify(self, str, sign):
|
||||
if not USE_GPG:
|
||||
return str
|
||||
if not str:
|
||||
if str == None:
|
||||
return ''
|
||||
f = tmpfile()
|
||||
fd = f.fileno()
|
||||
|
|
|
@ -6,19 +6,19 @@ HAVE_XSCRNSAVER = $(shell pkg-config --exists xscrnsaver && echo 'YES')
|
|||
|
||||
ifeq ($(HAVE_XSCRNSAVER),YES)
|
||||
# We link with libXScrnsaver from modular X.Org X11
|
||||
CFLAGS = `pkg-config --cflags gtk+-2.0 pygtk-2.0 xscrnsaver` -fpic -I/usr/include/python$(PYTHONVER) -I.
|
||||
LDFLAGS = `pkg-config --libs gtk+-2.0 pygtk-2.0 xscrnsaver` -lpython$(PYTHONVER)
|
||||
gtk_and_x_CFLAGS = `pkg-config --cflags gtk+-2.0 pygtk-2.0 xscrnsaver` -fpic -I/usr/include/python$(PYTHONVER) -I.
|
||||
gtk_and_x_LDFLAGS = `pkg-config --libs gtk+-2.0 pygtk-2.0 xscrnsaver` -lpython$(PYTHONVER)
|
||||
else
|
||||
# # We link with libXScrnsaver from monolithic X.Org X11
|
||||
CFLAGS = `pkg-config --cflags gtk+-2.0 pygtk-2.0` -fpic -I/usr/include/python$(PYTHONVER) -I.
|
||||
LDFLAGS = `pkg-config --libs gtk+-2.0 pygtk-2.0` -L/usr/X11R6$(LIBDIR) -lX11 \
|
||||
-lXss -lXext -lpython$(PYTHONVER)
|
||||
gtk_and_x_CFLAGS = `pkg-config --cflags gtk+-2.0 pygtk-2.0` -fpic -I/usr/include/python$(PYTHONVER) -I.
|
||||
gtk_and_x_LDFLAGS = `pkg-config --libs gtk+-2.0 pygtk-2.0` \
|
||||
-L/usr/X11R6$(LIBDIR) -lX11 -lXss -lXext -lpython$(PYTHONVER)
|
||||
endif
|
||||
|
||||
all: idle.so
|
||||
|
||||
idle.so:
|
||||
$(CC) $(OPTFLAGS) $(CFLAGS) $(LDFLAGS) -shared idle.c $^ -o $@
|
||||
$(CC) $(OPTFLAGS) $(CFLAGS) $(LDFLAGS) $(gtk_and_x_CFLAGS) $(gtk_and_x_LDFLAGS) -shared idle.c $^ -o $@
|
||||
|
||||
clean:
|
||||
rm -f *.so
|
||||
|
|
|
@ -57,6 +57,11 @@ def create_log_db():
|
|||
jid_id INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE transports_cache (
|
||||
transport TEXT UNIQUE,
|
||||
type INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE logs(
|
||||
log_line_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
jid_id INTEGER,
|
||||
|
|
|
@ -48,7 +48,7 @@ class Config:
|
|||
'notify_on_signout': [ opt_bool, False ],
|
||||
'notify_on_new_message': [ opt_bool, True ],
|
||||
'autopopupaway': [ opt_bool, False ],
|
||||
'use_notif_daemon': [ opt_bool, True , _('Use DBus and Notification-Daemon to show notifications') ],
|
||||
'use_notif_daemon': [ opt_bool, True , _('Use D-Bus and Notification-Daemon to show notifications') ],
|
||||
'ignore_unknown_contacts': [ opt_bool, False ],
|
||||
'showoffline': [ opt_bool, False, '', True ],
|
||||
'autoaway': [ opt_bool, True ],
|
||||
|
@ -74,12 +74,13 @@ class Config:
|
|||
'statusmsgcolor': [ opt_color, '#1eaa1e', '', True ],
|
||||
'markedmsgcolor': [ opt_color, '#ff8080', '', True ],
|
||||
'urlmsgcolor': [ opt_color, '#0000ff', '', True ],
|
||||
'collapsed_rows': [ opt_str, '', _('List (space separated) of rows (accounts and groups) that are collapsed'), True ],
|
||||
'collapsed_rows': [ opt_str, '', _('List (space separated) of rows (accounts and groups) that are collapsed.'), True ],
|
||||
'roster_theme': [ opt_str, 'gtk+', '', True ],
|
||||
'saveposition': [ opt_bool, True ],
|
||||
'mergeaccounts': [ opt_bool, False, '', True ],
|
||||
'sort_by_show': [ opt_bool, True, '', True ],
|
||||
'use_speller': [ opt_bool, False, ],
|
||||
'speller_language': [ opt_str, '', _('Language used by speller')],
|
||||
'print_time': [ opt_str, 'always', _('\'always\' - print time for every message.\n\'sometimes\' - print time every print_ichat_every_foo_minutes minute.\n\'never\' - never print time.')],
|
||||
'print_time_fuzzy': [ opt_int, 0, _('Value of fuzziness from 1 to 4 or 0 to disable fuzzyclock. 1 is the most precise clock, 4 the less precise one.') ],
|
||||
'emoticons_theme': [opt_str, 'static', '', True ],
|
||||
|
@ -95,8 +96,8 @@ class Config:
|
|||
'custommailapp': [ opt_str, 'mozilla-thunderbird -compose' ],
|
||||
'custom_file_manager': [ opt_str, 'xffm' ],
|
||||
'gc-hpaned-position': [opt_int, 430],
|
||||
'gc_refer_to_nick_char': [opt_str, ',', _('Character to add after nickname when using nick completion (tab) in group chat')],
|
||||
'gc_proposed_nick_char': [opt_str, '_', _('Character to propose to add after desired nickname when desired nickname is used by someone else in group chat')],
|
||||
'gc_refer_to_nick_char': [opt_str, ',', _('Character to add after nickname when using nick completion (tab) in group chat.')],
|
||||
'gc_proposed_nick_char': [opt_str, '_', _('Character to propose to add after desired nickname when desired nickname is used by someone else in group chat.')],
|
||||
'msgwin-x-position': [opt_int, -1], # Default is to let the window manager decide
|
||||
'msgwin-y-position': [opt_int, -1], # Default is to let the window manager decide
|
||||
'msgwin-width': [opt_int, 500],
|
||||
|
@ -134,7 +135,7 @@ class Config:
|
|||
'send_on_ctrl_enter': [opt_bool, False, _('Send message on Ctrl+Enter and with Enter make new line (Mirabilis ICQ Client default behaviour).')],
|
||||
'show_roster_on_startup': [opt_bool, True],
|
||||
'key_up_lines': [opt_int, 25, _('How many lines to store for Ctrl+KeyUP.')],
|
||||
'version': [ opt_str, '0.10.1.2' ], # which version created the config
|
||||
'version': [ opt_str, '0.10.1.3' ], # which version created the config
|
||||
'search_engine': [opt_str, 'http://www.google.com/search?&q=%s&sourceid=gajim'],
|
||||
'dictionary_url': [opt_str, 'WIKTIONARY', _("Either custom url with %s in it where %s is the word/phrase or 'WIKTIONARY' which means use wiktionary.")],
|
||||
'always_english_wikipedia': [opt_bool, False],
|
||||
|
@ -142,7 +143,7 @@ class Config:
|
|||
'remote_control': [opt_bool, True, _('If checked, Gajim can be controlled remotely using gajim-remote.'), True],
|
||||
'chat_state_notifications': [opt_str, 'all'], # 'all', 'composing_only', 'disabled'
|
||||
'autodetect_browser_mailer': [opt_bool, False, '', True],
|
||||
'print_ichat_every_foo_minutes': [opt_int, 5, _('When not printing time for every message (print_time==sometimes), print it every x minutes')],
|
||||
'print_ichat_every_foo_minutes': [opt_int, 5, _('When not printing time for every message (print_time==sometimes), print it every x minutes.')],
|
||||
'confirm_close_muc': [opt_bool, True, _('Ask before closing a group chat tab/window.')],
|
||||
'confirm_close_muc_rooms': [opt_str, '', _('Always ask before closing group chat tab/window in this space separated list of room jids.')],
|
||||
'noconfirm_close_muc_rooms': [opt_str, '', _('Never ask before closing group chat tab/window in this space separated list of room jids.')],
|
||||
|
@ -177,31 +178,33 @@ class Config:
|
|||
'quit_on_roster_x_button': [opt_bool, False, _('If True, quits Gajim when X button of Window Manager is clicked. This setting is taken into account only if trayicon is used.')],
|
||||
'set_xmpp://_handler_everytime': [opt_bool, False, _('If True, Gajim registers for xmpp:// on each startup.')],
|
||||
'show_unread_tab_icon': [opt_bool, False, _('If True, Gajim will display an icon on each tab containing unread messages. Depending on the theme, this icon may be animated.')],
|
||||
'show_status_msgs_in_roster': [opt_bool, True, _('If True, Gajim will display the status message, if not empty, for every contact under the contact name in roster window'), True],
|
||||
'show_status_msgs_in_roster': [opt_bool, True, _('If True, Gajim will display the status message, if not empty, for every contact under the contact name in roster window.'), True],
|
||||
'show_avatars_in_roster': [opt_bool, True, '', True],
|
||||
'ask_avatars_on_startup': [opt_bool, True, _('If True, Gajim will ask for avatar each contact that did not have an avatar last time or has one cached that is too old.')],
|
||||
'print_status_in_chats': [opt_bool, True, _('If False, Gajim will no longer print status line in chats when a contact changes his or her status and/or his or her status message.')],
|
||||
'print_status_in_muc': [opt_str, 'in_and_out', _('can be "none", "all" or "in_and_out". If "none", Gajim will no longer print status line in groupchats when a member changes his or her status and/or his or her status message. If "all" Gajim will print all status messages. If "in_and_out", gajim will only print FOO enters/leaves room')],
|
||||
'print_status_in_muc': [opt_str, 'in_and_out', _('can be "none", "all" or "in_and_out". If "none", Gajim will no longer print status line in groupchats when a member changes his or her status and/or his or her status message. If "all" Gajim will print all status messages. If "in_and_out", gajim will only print FOO enters/leaves room.')],
|
||||
'log_contact_status_changes': [opt_bool, False],
|
||||
'restored_messages_color': [opt_str, 'grey'],
|
||||
'restored_messages_small': [opt_bool, True, _('If True, restored messages will use a smaller font than the default one.')],
|
||||
'hide_avatar_of_transport': [opt_bool, False, _('Don\'t show avatar for the transport itself.')],
|
||||
'roster_window_skip_taskbar': [opt_bool, False],
|
||||
'use_urgency_hint': [opt_bool, True, _('If True and installed GTK+ and PyGTK versions are at least 2.8, make the window flash (the default behaviour in most Window Managers) when holding pending events.')],
|
||||
'notification_timeout': [opt_int, 5],
|
||||
'send_sha_in_gc_presence': [opt_bool, True, _('Jabberd1.4 does not like sha info when one join a password protected room. Turn this option to False to stop sending sha info in groupchat presences')],
|
||||
'send_sha_in_gc_presence': [opt_bool, True, _('Jabberd1.4 does not like sha info when one join a password protected room. Turn this option to False to stop sending sha info in group chat presences.')],
|
||||
'one_message_window': [opt_str, 'always',
|
||||
#always, never, peracct, pertype should not be translated
|
||||
_('Controls the window where new messages are placed.\n\'always\' - All messages are sent to a single window.\n\'never\' - All messages get their own window.\n\'peracct\' - Messages for each account are sent to a specific window.\n\'pertype\' - Each message type (e.g., chats vs. groupchats) are sent to a specific window. Note, changing this option requires restarting Gajim before the changes will take effect')],
|
||||
'show_avatar_in_chat': [opt_bool, True, _('If False, you will no longer see the avatar in the chat window')],
|
||||
'escape_key_closes': [opt_bool, True, _('If True, pressing the escape key closes a tab/window')],
|
||||
'always_hide_groupchat_buttons': [opt_bool, False, _('Hides the buttons in group chat window')],
|
||||
'always_hide_chat_buttons': [opt_bool, False, _('Hides the buttons in two persons chat window')],
|
||||
_('Controls the window where new messages are placed.\n\'always\' - All messages are sent to a single window.\n\'never\' - All messages get their own window.\n\'peracct\' - Messages for each account are sent to a specific window.\n\'pertype\' - Each message type (e.g., chats vs. groupchats) are sent to a specific window. Note, changing this option requires restarting Gajim before the changes will take effect.')],
|
||||
'show_avatar_in_chat': [opt_bool, True, _('If False, you will no longer see the avatar in the chat window.')],
|
||||
'escape_key_closes': [opt_bool, True, _('If True, pressing the escape key closes a tab/window.')],
|
||||
'always_hide_groupchat_buttons': [opt_bool, False, _('Hides the buttons in group chat window.')],
|
||||
'always_hide_chat_buttons': [opt_bool, False, _('Hides the buttons in two persons chat window.')],
|
||||
'hide_groupchat_banner': [opt_bool, False, _('Hides the banner in a group chat window')],
|
||||
'hide_chat_banner': [opt_bool, False, _('Hides the banner in two persons chat window')],
|
||||
'hide_groupchat_occupants_list': [opt_bool, False, _('Hides the room occupants list in groupchat window')],
|
||||
'chat_merge_consecutive_nickname': [opt_bool, False, _('Merge consecutive nickname in chat window')],
|
||||
'chat_merge_consecutive_nickname_indent': [opt_str, ' ', _('Indentation when using merge consecutive nickame')],
|
||||
'gc_nicknames_colors': [ opt_str, '#a34526:#c000ff:#0012ff:#388a99:#38995d:#519938:#ff8a00:#94452d:#244b5a:#32645a', _('List of colors that will be used to color nicknames in groupchats'), True ],
|
||||
'hide_groupchat_occupants_list': [opt_bool, False, _('Hides the room occupants list in group chat window.')],
|
||||
'chat_merge_consecutive_nickname': [opt_bool, False, _('Merge consecutive nickname in chat window.')],
|
||||
'chat_merge_consecutive_nickname_indent': [opt_str, ' ', _('Indentation when using merge consecutive nickame.')],
|
||||
'gc_nicknames_colors': [ opt_str, '#a34526:#c000ff:#0012ff:#388a99:#38995d:#519938:#ff8a00:#94452d:#244b5a:#32645a', _('List of colors that will be used to color nicknames in group chats.'), True ],
|
||||
'ctrl_tab_go_to_next_composing': [opt_bool, True, _('Ctrl-Tab go to next composing tab when none is unread.')],
|
||||
}
|
||||
|
||||
__options_per_key = {
|
||||
|
@ -247,6 +250,10 @@ class Config:
|
|||
'statusmsg': ({
|
||||
'message': [ opt_str, '' ],
|
||||
}, {}),
|
||||
'defaultstatusmsg': ({
|
||||
'enabled': [ opt_bool, False ],
|
||||
'message': [ opt_str, '' ],
|
||||
}, {}),
|
||||
'soundevents': ({
|
||||
'enabled': [ opt_bool, True ],
|
||||
'path': [ opt_str, '' ],
|
||||
|
@ -289,7 +296,11 @@ class Config:
|
|||
'state_muc_directed_msg_color': [ opt_color, 'red2' ],
|
||||
}, {}),
|
||||
'contacts': ({
|
||||
'gpg_enabled': [ opt_bool, True ],
|
||||
'gpg_enabled': [ opt_bool, True, _('Is OpenPGP enabled for this contact?')],
|
||||
'speller_language': [ opt_str, '', _('Language for which we want to check misspelled words')],
|
||||
}, {}),
|
||||
'rooms': ({
|
||||
'speller_language': [ opt_str, '', _('Language for which we want to check misspelled words')],
|
||||
}, {}),
|
||||
'notifications': ({
|
||||
'event': [opt_str, ''],
|
||||
|
@ -319,6 +330,16 @@ class Config:
|
|||
_('Out'): _("I'm out enjoying life"),
|
||||
}
|
||||
|
||||
defaultstatusmsg_default = {
|
||||
'online': [ False, _("I'm available") ],
|
||||
'chat': [ False, _("I'm free for chat") ],
|
||||
'away': [ False, _('Be right back') ],
|
||||
'xa': [ False, _("I'm not available") ],
|
||||
'dnd': [ False, _('Do not disturb') ],
|
||||
'invisible': [ False, _('Bye!') ],
|
||||
'offline': [ False, _('Bye!') ],
|
||||
}
|
||||
|
||||
soundevents_default = {
|
||||
'first_message_received': [ True, '../data/sounds/message1.wav' ],
|
||||
'next_message_received': [ True, '../data/sounds/message2.wav' ],
|
||||
|
@ -532,3 +553,8 @@ class Config:
|
|||
self.set_per('soundevents', event, 'enabled', default[0])
|
||||
self.set_per('soundevents', event, 'path', default[1])
|
||||
|
||||
for status in self.defaultstatusmsg_default:
|
||||
default = self.defaultstatusmsg_default[status]
|
||||
self.add_per('defaultstatusmsg', status)
|
||||
self.set_per('defaultstatusmsg', status, 'enabled', default[0])
|
||||
self.set_per('defaultstatusmsg', status, 'message', default[1])
|
||||
|
|
|
@ -84,18 +84,12 @@ class Connection(ConnectionHandlers):
|
|||
self.on_connect_failure = None
|
||||
self.retrycount = 0
|
||||
self.jids_for_auto_auth = [] # list of jid to auto-authorize
|
||||
self.muc_jid = {} # jid of muc server for each transport type
|
||||
self.available_transports = {} # list of available transports on this
|
||||
# server {'icq': ['icq.server.com', 'icq2.server.com'], }
|
||||
self.vcard_supported = True
|
||||
# END __init__
|
||||
|
||||
def build_user_nick(self, user_nick):
|
||||
df = common.xmpp.DataForm(typ = 'result')
|
||||
field = df.setField('FORM_TYPE')
|
||||
field.setType('hidden')
|
||||
field.setValue(common.xmpp.NS_PROFILE)
|
||||
field = df.setField('nickname')
|
||||
field.delAttr('type')
|
||||
field.setValue(user_nick)
|
||||
return df
|
||||
|
||||
def put_event(self, ev):
|
||||
if gajim.handlers.has_key(ev[0]):
|
||||
gajim.handlers[ev[0]](self.name, ev[1])
|
||||
|
@ -143,22 +137,21 @@ class Connection(ConnectionHandlers):
|
|||
if not self.on_purpose:
|
||||
self.disconnect()
|
||||
if gajim.config.get_per('accounts', self.name, 'autoreconnect') \
|
||||
and self.retrycount <= 10:
|
||||
and self.retrycount <= 10:
|
||||
self.connected = 1
|
||||
self.dispatch('STATUS', 'connecting')
|
||||
self.time_to_reconnect = 10
|
||||
# this check has moved from _reconnect method
|
||||
if self.retrycount > 5:
|
||||
self.time_to_reconnect = 20
|
||||
else:
|
||||
self.time_to_reconnect = 10
|
||||
gajim.idlequeue.set_alarm(self._reconnect_alarm,
|
||||
self.time_to_reconnect)
|
||||
gajim.idlequeue.set_alarm(self._reconnect_alarm,
|
||||
self.time_to_reconnect)
|
||||
elif self.on_connect_failure:
|
||||
self.on_connect_failure()
|
||||
self.on_connect_failure = None
|
||||
else:
|
||||
# show error dialog
|
||||
# show error dialog
|
||||
self._connection_lost()
|
||||
else:
|
||||
self.disconnect()
|
||||
|
@ -168,9 +161,9 @@ class Connection(ConnectionHandlers):
|
|||
def _connection_lost(self):
|
||||
self.disconnect(on_purpose = False)
|
||||
self.dispatch('STATUS', 'offline')
|
||||
self.dispatch('ERROR',
|
||||
(_('Connection with account "%s" has been lost') % self.name,
|
||||
_('To continue sending and receiving messages, you will need to reconnect.')))
|
||||
self.dispatch('CONNECTION_LOST',
|
||||
(_('Connection with account "%s" has been lost') % self.name,
|
||||
_('To continue sending and receiving messages, you will need to reconnect.')))
|
||||
|
||||
def _event_dispatcher(self, realm, event, data):
|
||||
if realm == common.xmpp.NS_REGISTER:
|
||||
|
@ -394,7 +387,8 @@ class Connection(ConnectionHandlers):
|
|||
if not self.retrycount and self.connected != 0:
|
||||
self.disconnect(on_purpose = True)
|
||||
self.dispatch('STATUS', 'offline')
|
||||
self.dispatch('ERROR', (_('Could not connect to "%s"') % self._hostname,
|
||||
self.dispatch('CONNECTION_LOST',
|
||||
(_('Could not connect to "%s"') % self._hostname,
|
||||
_('Check your connection or try again later.')))
|
||||
|
||||
def _connect_success(self, con, con_type):
|
||||
|
@ -430,7 +424,8 @@ class Connection(ConnectionHandlers):
|
|||
if not con:
|
||||
self.disconnect(on_purpose = True)
|
||||
self.dispatch('STATUS', 'offline')
|
||||
self.dispatch('ERROR', (_('Could not connect to "%s"') % self._hostname,
|
||||
self.dispatch('CONNECTION_LOST',
|
||||
(_('Could not connect to "%s"') % self._hostname,
|
||||
_('Check your connection or try again later')))
|
||||
if self.on_connect_auth:
|
||||
self.on_connect_auth(None)
|
||||
|
@ -712,8 +707,8 @@ class Connection(ConnectionHandlers):
|
|||
|
||||
# JEP-0172: user_nickname
|
||||
if user_nick:
|
||||
df = self.build_user_nick(user_nick)
|
||||
msg_iq.addChild(node = df)
|
||||
msg_iq.setTag('nick', namespace = common.xmpp.NS_NICK).setData(
|
||||
user_nick)
|
||||
|
||||
# chatstates - if peer supports jep85 or jep22, send chatstates
|
||||
# please note that the only valid tag inside a message containing a <body>
|
||||
|
@ -788,12 +783,10 @@ class Connection(ConnectionHandlers):
|
|||
|
||||
p = common.xmpp.Presence(jid, 'subscribe')
|
||||
if user_nick:
|
||||
df = self.build_user_nick(user_nick)
|
||||
p.addChild(node = df)
|
||||
p.setTag('nick', namespace = common.xmpp.NS_NICK).setData(user_nick)
|
||||
p = self.add_sha(p)
|
||||
if not msg:
|
||||
msg = _('I would like to add you to my roster.')
|
||||
p.setStatus(msg)
|
||||
if msg:
|
||||
p.setStatus(msg)
|
||||
self.connection.send(p)
|
||||
|
||||
def send_authorization(self, jid):
|
||||
|
@ -876,6 +869,10 @@ class Connection(ConnectionHandlers):
|
|||
def request_os_info(self, jid, resource):
|
||||
if not self.connection:
|
||||
return
|
||||
# If we are invisible, do not request
|
||||
if self.connected == gajim.SHOW_LIST.index('invisible'):
|
||||
self.dispatch('OS_INFO', (jid, resource, _('Not fetched because of invisible status'), _('Not fetched because of invisible status')))
|
||||
return
|
||||
to_whom_jid = jid
|
||||
if resource:
|
||||
to_whom_jid += '/' + resource
|
||||
|
@ -932,6 +929,9 @@ class Connection(ConnectionHandlers):
|
|||
iq = common.xmpp.Iq(typ='get')
|
||||
iq2 = iq.addChild(name='query', namespace='jabber:iq:private')
|
||||
iq2.addChild(name='storage', namespace='storage:metacontacts')
|
||||
id = self.connection.getAnID()
|
||||
iq.setID(id)
|
||||
self.awaiting_answers[id] = (METACONTACTS_ARRIVED, )
|
||||
self.connection.send(iq)
|
||||
|
||||
def store_metacontacts(self, tags_list):
|
||||
|
|
|
@ -24,6 +24,7 @@ import sha
|
|||
import socket
|
||||
import sys
|
||||
|
||||
from time import localtime, strftime, gmtime
|
||||
from calendar import timegm
|
||||
|
||||
import socks5
|
||||
|
@ -43,6 +44,7 @@ STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
|
|||
VCARD_PUBLISHED = 'vcard_published'
|
||||
VCARD_ARRIVED = 'vcard_arrived'
|
||||
AGENT_REMOVED = 'agent_removed'
|
||||
METACONTACTS_ARRIVED = 'metacontacts_arrived'
|
||||
HAS_IDLE = True
|
||||
try:
|
||||
import common.idle as idle # when we launch gajim from sources
|
||||
|
@ -171,7 +173,12 @@ class ConnectionBytestream:
|
|||
file_props['sha_str'] = sha_str
|
||||
if not ft_override_host_to_send:
|
||||
ft_override_host_to_send = self.peerhost[0]
|
||||
ft_override_host_to_send = socket.gethostbyname(ft_override_host_to_send)
|
||||
try:
|
||||
ft_override_host_to_send = socket.gethostbyname(
|
||||
ft_override_host_to_send)
|
||||
except socket.gaierror:
|
||||
self.dispatch('ERROR', (_('Wrong host'), _('The host you configured as the ft_override_host_to_send advanced option is not valid, so ignored.')))
|
||||
ft_override_host_to_send = self.peerhost[0]
|
||||
listener = gajim.socks5queue.start_listener(self.peerhost[0], port,
|
||||
sha_str, self._result_socks5_sid, file_props['sid'])
|
||||
if listener == None:
|
||||
|
@ -582,8 +589,8 @@ class ConnectionDisco:
|
|||
iq.setID(id)
|
||||
# Wait the answer during 30 secondes
|
||||
self.awaiting_timeouts[gajim.idlequeue.current_time() + 30] = (id,
|
||||
_('Registration information for transport %s has not arrived in time' % \
|
||||
agent))
|
||||
_('Registration information for transport %s has not arrived in time') % \
|
||||
agent)
|
||||
self.connection.SendAndCallForResponse(iq, self._ReceivedRegInfo,
|
||||
{'agent': agent})
|
||||
|
||||
|
@ -746,17 +753,28 @@ class ConnectionDisco:
|
|||
qc = iq_obj.getQueryChildren()
|
||||
if not qc:
|
||||
qc = []
|
||||
is_muc = False
|
||||
transport_type = ''
|
||||
for i in qc:
|
||||
if i.getName() == 'identity':
|
||||
attr = {}
|
||||
for key in i.getAttrs().keys():
|
||||
attr[key] = i.getAttr(key)
|
||||
if attr.has_key('category') and attr['category'] in ('gateway', 'headline')\
|
||||
and attr.has_key('type'):
|
||||
transport_type = attr['type']
|
||||
if attr.has_key('category') and attr['category'] == 'conference' \
|
||||
and attr.has_key('type') and attr['type'] == 'text':
|
||||
is_muc = True
|
||||
identities.append(attr)
|
||||
elif i.getName() == 'feature':
|
||||
features.append(i.getAttr('var'))
|
||||
elif i.getName() == 'x' and i.getAttr('xmlns') == common.xmpp.NS_DATA:
|
||||
elif i.getName() == 'x' and i.getNamespace() == common.xmpp.NS_DATA:
|
||||
data.append(common.xmpp.DataForm(node=i))
|
||||
jid = helpers.get_full_jid_from_iq(iq_obj)
|
||||
if transport_type and jid not in gajim.transport_type:
|
||||
gajim.transport_type[jid] = transport_type
|
||||
gajim.logger.save_transport_type(jid, transport_type)
|
||||
id = iq_obj.getID()
|
||||
if not identities: # ejabberd doesn't send identities when we browse online users
|
||||
#FIXME: see http://www.jabber.ru/bugzilla/show_bug.cgi?id=225
|
||||
|
@ -764,6 +782,14 @@ class ConnectionDisco:
|
|||
if id[0] == 'p':
|
||||
if features.__contains__(common.xmpp.NS_BYTESTREAM):
|
||||
gajim.proxy65_manager.resolve(jid, self.connection, self.name)
|
||||
if features.__contains__(common.xmpp.NS_MUC) and is_muc:
|
||||
type_ = transport_type or 'jabber'
|
||||
self.muc_jid[type_] = jid
|
||||
if transport_type:
|
||||
if self.available_transports.has_key(transport_type):
|
||||
self.available_transports[transport_type].append(jid)
|
||||
else:
|
||||
self.available_transports[transport_type] = [jid]
|
||||
self.dispatch('AGENT_INFO_INFO', (jid, node, identities,
|
||||
features, data))
|
||||
|
||||
|
@ -871,7 +897,10 @@ class ConnectionVcard:
|
|||
|
||||
id = self.connection.getAnID()
|
||||
iq.setID(id)
|
||||
self.awaiting_answers[id] = (VCARD_ARRIVED, jid)
|
||||
j = jid
|
||||
if not j:
|
||||
j = gajim.get_jid_from_account(self.name)
|
||||
self.awaiting_answers[id] = (VCARD_ARRIVED, j)
|
||||
if is_fake_jid:
|
||||
room_jid, nick = gajim.get_room_and_nick_from_fjid(jid)
|
||||
if not room_jid in self.room_jids:
|
||||
|
@ -959,9 +988,12 @@ class ConnectionVcard:
|
|||
elif self.awaiting_answers[id][0] == VCARD_ARRIVED:
|
||||
# If vcard is empty, we send to the interface an empty vcard so that
|
||||
# it knows it arrived
|
||||
if not iq_obj.getTag('vCard'):
|
||||
jid = self.awaiting_answers[id][1]
|
||||
our_jid = gajim.get_jid_from_account(self.name)
|
||||
jid = self.awaiting_answers[id][1]
|
||||
our_jid = gajim.get_jid_from_account(self.name)
|
||||
if iq_obj.getType() == 'error' and jid == our_jid:
|
||||
# our server doesn't support vcard
|
||||
self.vcard_supported = False
|
||||
if not iq_obj.getTag('vCard') or iq_obj.getType() == 'error':
|
||||
if jid and jid != our_jid:
|
||||
# Write an empty file
|
||||
self.save_vcard_to_hd(jid, '')
|
||||
|
@ -971,6 +1003,29 @@ class ConnectionVcard:
|
|||
elif self.awaiting_answers[id][0] == AGENT_REMOVED:
|
||||
jid = self.awaiting_answers[id][1]
|
||||
self.dispatch('AGENT_REMOVED', jid)
|
||||
elif self.awaiting_answers[id][0] == METACONTACTS_ARRIVED:
|
||||
if iq_obj.getType() == 'result':
|
||||
# Metacontact tags
|
||||
# http://www.jabber.org/jeps/jep-XXXX.html
|
||||
meta_list = {}
|
||||
query = iq_obj.getTag('query')
|
||||
storage = query.getTag('storage')
|
||||
metas = storage.getTags('meta')
|
||||
for meta in metas:
|
||||
jid = meta.getAttr('jid')
|
||||
tag = meta.getAttr('tag')
|
||||
data = {'jid': jid}
|
||||
order = meta.getAttr('order')
|
||||
if order != None:
|
||||
data['order'] = order
|
||||
if meta_list.has_key(tag):
|
||||
meta_list[tag].append(data)
|
||||
else:
|
||||
meta_list[tag] = [data]
|
||||
self.dispatch('METACONTACTS', meta_list)
|
||||
# We can now continue connection by requesting the roster
|
||||
self.connection.initRoster()
|
||||
|
||||
del self.awaiting_answers[id]
|
||||
|
||||
def _vCardCB(self, con, vc):
|
||||
|
@ -1072,6 +1127,9 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
# keep the jids we auto added (transports contacts) to not send the
|
||||
# SUBSCRIBED event to gui
|
||||
self.automatically_added = []
|
||||
# keep the latest subscribed event for each jid to prevent loop when we
|
||||
# acknoledge presences
|
||||
self.subscribed_events = {}
|
||||
try:
|
||||
idle.init()
|
||||
except:
|
||||
|
@ -1134,26 +1192,6 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
self.bookmarks.append(bm)
|
||||
self.dispatch('BOOKMARKS', self.bookmarks)
|
||||
|
||||
elif ns == 'storage:metacontacts':
|
||||
# Metacontact tags
|
||||
# http://www.jabber.org/jeps/jep-XXXX.html
|
||||
meta_list = {}
|
||||
metas = storage.getTags('meta')
|
||||
for meta in metas:
|
||||
jid = meta.getAttr('jid')
|
||||
tag = meta.getAttr('tag')
|
||||
data = {'jid': jid}
|
||||
order = meta.getAttr('order')
|
||||
if order != None:
|
||||
data['order'] = order
|
||||
if meta_list.has_key(tag):
|
||||
meta_list[tag].append(data)
|
||||
else:
|
||||
meta_list[tag] = [data]
|
||||
self.dispatch('METACONTACTS', meta_list)
|
||||
# We can now continue connection by requesting the roster
|
||||
self.connection.initRoster()
|
||||
|
||||
elif ns == 'gajim:prefs':
|
||||
# Preferences data
|
||||
# http://www.jabber.org/jeps/jep-0049.html
|
||||
|
@ -1236,6 +1274,16 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
jid_stripped, resource = gajim.get_room_and_nick_from_fjid(who)
|
||||
self.dispatch('OS_INFO', (jid_stripped, resource, client_info, os_info))
|
||||
|
||||
def _TimeCB(self, con, iq_obj):
|
||||
gajim.log.debug('TimeCB')
|
||||
iq_obj = iq_obj.buildReply('result')
|
||||
qp = iq_obj.getTag('query')
|
||||
qp.setTagData('utc', strftime("%Y%m%dT%T", gmtime()))
|
||||
qp.setTagData('tz', strftime("%Z", gmtime()))
|
||||
qp.setTagData('display', strftime("%c", localtime()))
|
||||
self.connection.send(iq_obj)
|
||||
raise common.xmpp.NodeProcessed
|
||||
|
||||
|
||||
def _gMailNewMailCB(self, con, gm):
|
||||
'''Called when we get notified of new mail messages in gmail account'''
|
||||
|
@ -1332,16 +1380,10 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
if not msgtxt and chatstate_child.getTag('composing'):
|
||||
chatstate = 'composing'
|
||||
# JEP-0172 User Nickname
|
||||
user_nick = ''
|
||||
xtags = msg.getTags('x', attrs = {'type': 'result'},
|
||||
namespace = common.xmpp.NS_DATA)
|
||||
for xtag in xtags:
|
||||
df = common.xmpp.DataForm(node = xtag)
|
||||
field = df.getField('FORM_TYPE')
|
||||
if not field or field.getValue() != common.xmpp.NS_PROFILE:
|
||||
continue
|
||||
user_nick = df.getField('nickname').getValue()
|
||||
|
||||
user_nick = msg.getTagData('nick')
|
||||
if not user_nick:
|
||||
user_nick = ''
|
||||
|
||||
if encTag and GnuPG.USE_GPG:
|
||||
#decrypt
|
||||
encmsg = encTag.getData()
|
||||
|
@ -1372,8 +1414,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
if not self.last_history_line.has_key(jid):
|
||||
return
|
||||
self.dispatch('GC_MSG', (frm, msgtxt, tim))
|
||||
if self.name not in no_log_for and jid in self.last_history_line \
|
||||
and not int(float(time.mktime(tim))) <= \
|
||||
if self.name not in no_log_for and not int(float(time.mktime(tim))) <= \
|
||||
self.last_history_line[jid] and msgtxt:
|
||||
gajim.logger.write('gc_msg', frm, msgtxt, tim = tim)
|
||||
elif mtype == 'chat': # it's type 'chat'
|
||||
|
@ -1433,13 +1474,26 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
if ptype == 'available':
|
||||
ptype = None
|
||||
gajim.log.debug('PresenceCB: %s' % ptype)
|
||||
who = helpers.get_full_jid_from_iq(prs)
|
||||
try:
|
||||
who = helpers.get_full_jid_from_iq(prs)
|
||||
except:
|
||||
if prs.getTag('error').getTag('jid-malformed'):
|
||||
# wrong jid, we probably tried to change our nick in a room to a non valid
|
||||
# one
|
||||
who = str(prs.getFrom())
|
||||
jid_stripped, resource = gajim.get_room_and_nick_from_fjid(who)
|
||||
self.dispatch('GC_MSG', (jid_stripped, _('Nickname not allowed: %s') % \
|
||||
resource, None))
|
||||
return
|
||||
jid_stripped, resource = gajim.get_room_and_nick_from_fjid(who)
|
||||
timestamp = None
|
||||
is_gc = False # is it a GC presence ?
|
||||
sigTag = None
|
||||
avatar_sha = None
|
||||
user_nick = '' # for JEP-0172
|
||||
# JEP-0172 User Nickname
|
||||
user_nick = prs.getTagData('nick')
|
||||
if not user_nick:
|
||||
user_nick = ''
|
||||
transport_auto_auth = False
|
||||
xtags = prs.getTags('x')
|
||||
for x in xtags:
|
||||
|
@ -1460,19 +1514,10 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
agent = gajim.get_server_from_jid(jid_stripped)
|
||||
if self.connection.getRoster().getItem(agent): # to be sure it's a transport contact
|
||||
transport_auto_auth = True
|
||||
if namespace == common.xmpp.NS_DATA:
|
||||
# JEP-0172
|
||||
df = common.xmpp.DataForm(node = x)
|
||||
if df.getType() != 'result':
|
||||
continue
|
||||
field = df.getField('FORM_TYPE')
|
||||
if not field or field.getValue() != common.xmpp.NS_PROFILE:
|
||||
continue
|
||||
user_nick = df.getField('nickname').getValue()
|
||||
|
||||
no_log_for = gajim.config.get_per('accounts', self.name,
|
||||
'no_log_for').split()
|
||||
status = prs.getStatus()
|
||||
status = prs.getStatus() or ''
|
||||
show = prs.getShow()
|
||||
if not show in STATUS_LIST:
|
||||
show = '' # We ignore unknown show
|
||||
|
@ -1531,7 +1576,16 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
if not ptype or ptype == 'unavailable':
|
||||
if gajim.config.get('log_contact_status_changes') and self.name\
|
||||
not in no_log_for and jid_stripped not in no_log_for:
|
||||
gajim.logger.write('gcstatus', who, status, show)
|
||||
gc_c = gajim.contacts.get_gc_contact(self.name, jid_stripped, resource)
|
||||
st = status or ''
|
||||
if gc_c:
|
||||
jid = gc_c.jid
|
||||
else:
|
||||
jid = prs.getJid()
|
||||
if jid:
|
||||
# we know real jid, save it in db
|
||||
st += ' (%s)' % jid
|
||||
gajim.logger.write('gcstatus', who, st, show)
|
||||
if avatar_sha:
|
||||
if self.vcard_shas.has_key(who):
|
||||
if avatar_sha != self.vcard_shas[who]:
|
||||
|
@ -1567,14 +1621,40 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
if jid_stripped in self.automatically_added:
|
||||
self.automatically_added.remove(jid_stripped)
|
||||
else:
|
||||
self.dispatch('SUBSCRIBED', (jid_stripped, resource))
|
||||
# detect a subscription loop
|
||||
if not self.subscribed_events.has_key(jid_stripped):
|
||||
self.subscribed_events[jid_stripped] = []
|
||||
self.subscribed_events[jid_stripped].append(time.time())
|
||||
block = False
|
||||
if len(self.subscribed_events[jid_stripped]) > 5:
|
||||
if time.time() - self.subscribed_events[jid_stripped][0] < 5:
|
||||
block = True
|
||||
self.subscribed_events[jid_stripped] = self.subscribed_events[jid_stripped][1:]
|
||||
if block:
|
||||
gajim.config.set_per('account', self.name,
|
||||
'dont_ack_subscription', True)
|
||||
else:
|
||||
self.dispatch('SUBSCRIBED', (jid_stripped, resource))
|
||||
# BE CAREFUL: no con.updateRosterItem() in a callback
|
||||
gajim.log.debug(_('we are now subscribed to %s') % who)
|
||||
elif ptype == 'unsubscribe':
|
||||
gajim.log.debug(_('unsubscribe request from %s') % who)
|
||||
elif ptype == 'unsubscribed':
|
||||
gajim.log.debug(_('we are now unsubscribed from %s') % who)
|
||||
self.dispatch('UNSUBSCRIBED', jid_stripped)
|
||||
# detect a unsubscription loop
|
||||
if not self.subscribed_events.has_key(jid_stripped):
|
||||
self.subscribed_events[jid_stripped] = []
|
||||
self.subscribed_events[jid_stripped].append(time.time())
|
||||
block = False
|
||||
if len(self.subscribed_events[jid_stripped]) > 5:
|
||||
if time.time() - self.subscribed_events[jid_stripped][0] < 5:
|
||||
block = True
|
||||
self.subscribed_events[jid_stripped] = self.subscribed_events[jid_stripped][1:]
|
||||
if block:
|
||||
gajim.config.set_per('account', self.name, 'dont_ack_subscription',
|
||||
True)
|
||||
else:
|
||||
self.dispatch('UNSUBSCRIBED', jid_stripped)
|
||||
elif ptype == 'error':
|
||||
errmsg = prs.getError()
|
||||
errcode = prs.getErrorCode()
|
||||
|
@ -1733,13 +1813,18 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
print >> sys.stderr, _('JID %s is not RFC compliant. It will not be added to your roster. Use roster management tools such as http://jru.jabberstudio.org/ to remove it') % jid
|
||||
else:
|
||||
infos = raw_roster[jid]
|
||||
if jid != our_jid and (not infos['subscription'] or infos['subscription'] == \
|
||||
'none') and (not infos['ask'] or infos['ask'] == 'none') and not infos['name'] \
|
||||
and not infos['groups']:
|
||||
if jid != our_jid and (not infos['subscription'] or \
|
||||
infos['subscription'] == 'none') and (not infos['ask'] or \
|
||||
infos['ask'] == 'none') and not infos['name'] and \
|
||||
not infos['groups']:
|
||||
# remove this useless item, it won't be shown in roster anyway
|
||||
self.connection.getRoster().delItem(jid)
|
||||
elif jid != our_jid: # don't add our jid
|
||||
roster[j] = raw_roster[jid]
|
||||
if gajim.jid_is_transport(jid) and \
|
||||
not gajim.get_transport_name_from_jid(jid):
|
||||
# we can't determine which iconset to use
|
||||
self.discoverInfo(jid)
|
||||
|
||||
self.dispatch('ROSTER', roster)
|
||||
|
||||
|
@ -1831,6 +1916,8 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
common.xmpp.NS_DISCO_INFO)
|
||||
con.RegisterHandler('iq', self._VersionCB, 'get',
|
||||
common.xmpp.NS_VERSION)
|
||||
con.RegisterHandler('iq', self._TimeCB, 'get',
|
||||
common.xmpp.NS_TIME)
|
||||
con.RegisterHandler('iq', self._LastCB, 'get',
|
||||
common.xmpp.NS_LAST)
|
||||
con.RegisterHandler('iq', self._LastResultCB, 'result',
|
||||
|
@ -1845,8 +1932,6 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
common.xmpp.NS_ROSTER)
|
||||
con.RegisterHandler('iq', self._PrivateCB, 'result',
|
||||
common.xmpp.NS_PRIVATE)
|
||||
con.RegisterHandler('iq', self._PrivateErrorCB, 'error',
|
||||
common.xmpp.NS_PRIVATE)
|
||||
con.RegisterHandler('iq', self._HttpAuthCB, 'get',
|
||||
common.xmpp.NS_HTTP_AUTH)
|
||||
con.RegisterHandler('iq', self._CommandExecuteCB, 'set',
|
||||
|
|
|
@ -210,7 +210,7 @@ class Contacts:
|
|||
contacts = self.get_contacts_from_jid(account, jid)
|
||||
if not contacts and '/' in jid:
|
||||
# jid may be a fake jid, try it
|
||||
room, nick = jid.split('/')
|
||||
room, nick = jid.split('/', 1)
|
||||
contact = self.get_gc_contact(account, room, nick)
|
||||
return contact
|
||||
return self.get_highest_prio_contact_from_contacts(contacts)
|
||||
|
|
233
src/common/events.py
Normal file
|
@ -0,0 +1,233 @@
|
|||
## common/events.py
|
||||
##
|
||||
## Contributors for this file:
|
||||
## - Yann Le Boulanger <asterix@lagaule.org>
|
||||
##
|
||||
## Copyright (C) 2006 Yann Le Boulanger <asterix@lagaule.org>
|
||||
## Vincent Hanquez <tab@snarc.org>
|
||||
## Nikos Kouremenos <nkour@jabber.org>
|
||||
## Dimitur Kirov <dkirov@gmail.com>
|
||||
## Travis Shirk <travis@pobox.com>
|
||||
## Norman Rasmussen <norman@rasmussen.co.za>
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published
|
||||
## by the Free Software Foundation; version 2 only.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
|
||||
import time
|
||||
import gajim
|
||||
|
||||
class Event:
|
||||
'''Information concerning each event'''
|
||||
def __init__(self, type_, time_, parameters, show_in_roster = False,
|
||||
show_in_systray = True):
|
||||
''' type_ in chat, normal, file-request, file-error, file-completed,
|
||||
file-request-error, file-send-error, file-stopped, gc_msg, pm,
|
||||
printed_chat, printed_gc_msg, printed_pm
|
||||
parameters is (per type_):
|
||||
chat, normal: [message, subject, kind, time, encrypted, resource,
|
||||
msg_id]
|
||||
where kind in error, incoming
|
||||
file-*: file_props
|
||||
gc_msg: None
|
||||
printed_*: None
|
||||
messages that are already printed in chat, but not read'''
|
||||
self.type_ = type_
|
||||
self.time_ = time_
|
||||
self.parameters = parameters
|
||||
self.show_in_roster = show_in_roster
|
||||
self.show_in_systray = show_in_systray
|
||||
|
||||
class Events:
|
||||
'''Information concerning all events'''
|
||||
def __init__(self):
|
||||
self._events = {} # list of events {acct: {jid1: [E1, E2]}, }
|
||||
|
||||
def change_account_name(self, old_name, new_name):
|
||||
if self._events.has_key(old_name):
|
||||
self._events[new_name] = self._events[old_name]
|
||||
del self._events[old_name]
|
||||
|
||||
def add_account(self, account):
|
||||
self._events[account] = {}
|
||||
|
||||
def get_accounts(self):
|
||||
return self._events.keys()
|
||||
|
||||
def remove_account(self, account):
|
||||
del self._events[account]
|
||||
|
||||
def create_event(self, type_, parameters, time_ = time.time(),
|
||||
show_in_roster = False, show_in_systray = True):
|
||||
return Event(type_, time_, parameters, show_in_roster,
|
||||
show_in_systray)
|
||||
|
||||
def add_event(self, account, jid, event):
|
||||
# No such account before ?
|
||||
if not self._events.has_key(account):
|
||||
self._events[account] = {jid: [event]}
|
||||
# no such jid before ?
|
||||
elif not self._events[account].has_key(jid):
|
||||
self._events[account][jid] = [event]
|
||||
else:
|
||||
self._events[account][jid].append(event)
|
||||
if event.show_in_systray and gajim.interface.systray_capabilities:
|
||||
gajim.interface.systray.set_img()
|
||||
|
||||
def remove_events(self, account, jid, event = None, types = []):
|
||||
'''if event is not speficied, remove all events from this jid,
|
||||
optionnaly only from given type
|
||||
return True if no such event found'''
|
||||
if not self._events.has_key(account):
|
||||
return True
|
||||
if not self._events[account].has_key(jid):
|
||||
return True
|
||||
if event: # remove only one event
|
||||
if event in self._events[account][jid]:
|
||||
if len(self._events[account][jid]) == 1:
|
||||
del self._events[account][jid]
|
||||
else:
|
||||
self._events[account][jid].remove(event)
|
||||
if event.show_in_systray and gajim.interface.systray_capabilities:
|
||||
gajim.interface.systray.set_img()
|
||||
return
|
||||
else:
|
||||
return True
|
||||
if types:
|
||||
new_list = [] # list of events to keep
|
||||
for ev in self._events[account][jid]:
|
||||
if ev.type_ not in types:
|
||||
new_list.append(ev)
|
||||
if len(new_list) == len(self._events[account][jid]):
|
||||
return True
|
||||
if new_list:
|
||||
self._events[account][jid] = new_list
|
||||
else:
|
||||
del self._events[account][jid]
|
||||
if gajim.interface.systray_capabilities:
|
||||
gajim.interface.systray.set_img()
|
||||
return
|
||||
# no event nor type given, remove them all
|
||||
del self._events[account][jid]
|
||||
if gajim.interface.systray_capabilities:
|
||||
gajim.interface.systray.set_img()
|
||||
|
||||
def get_nb_events(self, types = []):
|
||||
return self._get_nb_events(types = types)
|
||||
|
||||
def get_events(self, account, jid = None, types = []):
|
||||
'''if event is not speficied, remove all events from this jid,
|
||||
optionnaly only from given type'''
|
||||
if not self._events.has_key(account):
|
||||
return []
|
||||
if not jid:
|
||||
return self._events[account]
|
||||
if not self._events[account].has_key(jid):
|
||||
return []
|
||||
events_list = [] # list of events
|
||||
for ev in self._events[account][jid]:
|
||||
if not types or ev.type_ in types:
|
||||
events_list.append(ev)
|
||||
return events_list
|
||||
|
||||
def get_first_event(self, account, jid = None, type_ = None):
|
||||
'''Return the first event of type type_ if given'''
|
||||
events_list = self.get_events(account, jid, type_)
|
||||
# be sure it's bigger than latest event
|
||||
first_event_time = time.time() + 1
|
||||
first_event = None
|
||||
for event in events_list:
|
||||
if event.time_ < first_event_time:
|
||||
first_event_time = event.time_
|
||||
first_event = event
|
||||
return first_event
|
||||
|
||||
def _get_nb_events(self, account = None, jid = None, attribute = None, types = []):
|
||||
'''return the number of events'''
|
||||
nb = 0
|
||||
if account:
|
||||
accounts = [account]
|
||||
else:
|
||||
accounts = self._events.keys()
|
||||
for acct in accounts:
|
||||
if not self._events.has_key(acct):
|
||||
continue
|
||||
if jid:
|
||||
jids = [jid]
|
||||
else:
|
||||
jids = self._events[acct].keys()
|
||||
for j in jids:
|
||||
if not self._events[acct].has_key(j):
|
||||
continue
|
||||
for event in self._events[acct][j]:
|
||||
if types and event.type_ not in types:
|
||||
continue
|
||||
if not attribute or \
|
||||
attribute == 'systray' and event.show_in_systray or \
|
||||
attribute == 'roster' and event.show_in_roster:
|
||||
nb += 1
|
||||
return nb
|
||||
|
||||
def _get_some_events(self, attribute):
|
||||
'''attribute in systray, roster'''
|
||||
events = {}
|
||||
for account in self._events:
|
||||
events[account] = {}
|
||||
for jid in self._events[account]:
|
||||
events[account][jid] = []
|
||||
for event in self._events[account][jid]:
|
||||
if attribute == 'systray' and event.show_in_systray or \
|
||||
attribute == 'roster' and event.show_in_roster:
|
||||
events[account][jid].append(event)
|
||||
if not events[account][jid]:
|
||||
del events[account][jid]
|
||||
if not events[account]:
|
||||
del events[account]
|
||||
return events
|
||||
|
||||
def _get_first_event_with_attribute(self, events):
|
||||
'''get the first event
|
||||
events is in the form {account1: {jid1: [ev1, ev2], },. }'''
|
||||
# be sure it's bigger than latest event
|
||||
first_event_time = time.time() + 1
|
||||
first_account = None
|
||||
first_jid = None
|
||||
first_event = None
|
||||
for account in events:
|
||||
for jid in events[account]:
|
||||
for event in events[account][jid]:
|
||||
if event.time_ < first_event_time:
|
||||
first_event_time = event.time_
|
||||
first_account = account
|
||||
first_jid = jid
|
||||
first_event = event
|
||||
return first_account, first_jid, first_event
|
||||
|
||||
def get_nb_systray_events(self, types = []):
|
||||
'''returns the number of events displayedin roster'''
|
||||
return self._get_nb_events(attribute = 'systray', types = types)
|
||||
|
||||
def get_systray_events(self):
|
||||
'''return all events that must be displayed in systray:
|
||||
{account1: {jid1: [ev1, ev2], },. }'''
|
||||
return self._get_some_events('systray')
|
||||
|
||||
def get_first_systray_event(self):
|
||||
events = self.get_systray_events()
|
||||
return self._get_first_event_with_attribute(events)
|
||||
|
||||
def get_nb_roster_events(self, account = None, jid = None, types = []):
|
||||
'''returns the number of events displayedin roster'''
|
||||
return self._get_nb_events(attribute = 'roster', account = account,
|
||||
jid = jid, types = types)
|
||||
|
||||
def get_roster_events(self):
|
||||
'''return all events that must be displayed in roster:
|
||||
{account1: {jid1: [ev1, ev2], },. }'''
|
||||
return self._get_some_events('roster')
|
|
@ -23,6 +23,7 @@ import locale
|
|||
|
||||
import config
|
||||
from contacts import Contacts
|
||||
from events import Events
|
||||
|
||||
interface = None # The actual interface (the gtk one for the moment)
|
||||
config = config.Config()
|
||||
|
@ -83,6 +84,8 @@ else:
|
|||
|
||||
gmail_domains = ['gmail.com', 'googlemail.com']
|
||||
|
||||
transport_type = {} # list the type of transport
|
||||
|
||||
last_message_time = {} # list of time of the latest incomming message
|
||||
# {acct1: {jid1: time1, jid2: time2}, }
|
||||
encrypted_chats = {} # list of encrypted chats {acct1: [jid1, jid2], ..}
|
||||
|
@ -90,19 +93,14 @@ encrypted_chats = {} # list of encrypted chats {acct1: [jid1, jid2], ..}
|
|||
contacts = Contacts()
|
||||
gc_connected = {} # tell if we are connected to the room or not {acct: {room_jid: True}}
|
||||
gc_passwords = {} # list of the pass required to enter a room {room_jid: password}
|
||||
automatic_rooms = {} # list of rooms that must be automaticaly configured and for which we have a list of invities {account: {room_jid: {'invities': []}}}
|
||||
|
||||
groups = {} # list of groups
|
||||
newly_added = {} # list of contacts that has just signed in
|
||||
to_be_removed = {} # list of contacts that has just signed out
|
||||
|
||||
awaiting_events = {} # list of messages/FT reveived but not printed
|
||||
# awaiting_events[jid] = (type, (data1, data2, ...))
|
||||
# if type in ('chat', 'normal'): data = (message, subject, kind, time,
|
||||
# encrypted, resource)
|
||||
# kind can be (incoming, error)
|
||||
# if type in file-request, file-request-error, file-send-error, file-error,
|
||||
# file-completed, file-stopped:
|
||||
# data = file_props
|
||||
events = Events()
|
||||
|
||||
nicks = {} # list of our nick names in each account
|
||||
# should we block 'contact signed in' notifications for this account?
|
||||
# this is only for the first 30 seconds after we change our show
|
||||
|
@ -222,8 +220,11 @@ def get_transport_name_from_jid(jid, use_config_setting = True):
|
|||
# jid was None. Yann why?
|
||||
if not jid or (use_config_setting and not config.get('use_transports_iconsets')):
|
||||
return
|
||||
|
||||
|
||||
host = get_server_from_jid(jid)
|
||||
if host in transport_type:
|
||||
return transport_type[host]
|
||||
|
||||
# host is now f.e. icq.foo.org or just icq (sometimes on hacky transports)
|
||||
host_splitted = host.split('.')
|
||||
if len(host_splitted) != 0:
|
||||
|
@ -233,7 +234,7 @@ def get_transport_name_from_jid(jid, use_config_setting = True):
|
|||
if host == 'aim':
|
||||
return 'aim'
|
||||
elif host == 'gg':
|
||||
return 'gadugadu'
|
||||
return 'gadu-gadu'
|
||||
elif host == 'irc':
|
||||
return 'irc'
|
||||
elif host == 'icq':
|
||||
|
@ -281,18 +282,6 @@ def get_hostname_from_account(account_name, use_srv = False):
|
|||
return config.get_per('accounts', account_name, 'custom_host')
|
||||
return config.get_per('accounts', account_name, 'hostname')
|
||||
|
||||
def get_first_event(account, jid, typ = None):
|
||||
'''returns the first event of the given type from the awaiting_events queue'''
|
||||
if not awaiting_events[account].has_key(jid):
|
||||
return None
|
||||
q = awaiting_events[account][jid]
|
||||
if not typ:
|
||||
return q[0]
|
||||
for ev in q:
|
||||
if ev[0] == typ:
|
||||
return ev
|
||||
return None
|
||||
|
||||
def get_notification_image_prefix(jid):
|
||||
'''returns the prefix for the notification images'''
|
||||
transport_name = get_transport_name_from_jid(jid)
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
import sre
|
||||
import os
|
||||
import subprocess
|
||||
import urllib
|
||||
import errno
|
||||
import select
|
||||
|
@ -360,6 +361,11 @@ def is_in_path(name_of_command, return_abs_path = False):
|
|||
else:
|
||||
return is_in_dir
|
||||
|
||||
def exec_command(command):
|
||||
'''command is a string that contain arguments'''
|
||||
# os.system(command)
|
||||
subprocess.Popen(command.split())
|
||||
|
||||
def launch_browser_mailer(kind, uri):
|
||||
#kind = 'url' or 'mail'
|
||||
if os.name == 'nt':
|
||||
|
@ -383,11 +389,9 @@ def launch_browser_mailer(kind, uri):
|
|||
command = gajim.config.get('custommailapp')
|
||||
if command == '': # if no app is configured
|
||||
return
|
||||
# we add the uri in "" so we have good parsing from shell
|
||||
uri = uri.replace('"', '\\"') # escape "
|
||||
command = command + ' "' + uri + '" &'
|
||||
try: #FIXME: when we require python2.4+ use subprocess module
|
||||
os.system(command)
|
||||
command = command + ' ' + uri
|
||||
try:
|
||||
exec_command(command)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
@ -406,11 +410,9 @@ def launch_file_manager(path_to_open):
|
|||
command = gajim.config.get('custom_file_manager')
|
||||
if command == '': # if no app is configured
|
||||
return
|
||||
# we add the path in "" so we have good parsing from shell
|
||||
path_to_open = path_to_open.replace('"', '\\"') # escape "
|
||||
command = command + ' "' + path_to_open + '" &'
|
||||
try: #FIXME: when we require python2.4+ use subprocess module
|
||||
os.system(command)
|
||||
command = command + ' ' + path_to_open
|
||||
try:
|
||||
exec_command(command)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
@ -436,11 +438,8 @@ def play_sound_file(path_to_soundfile):
|
|||
if gajim.config.get('soundplayer') == '':
|
||||
return
|
||||
player = gajim.config.get('soundplayer')
|
||||
# we add the path in "" so we have good parsing from shell
|
||||
path_to_soundfile = path_to_soundfile.replace('"', '\\"') # escape "
|
||||
command = player + ' "' + path_to_soundfile + '" &'
|
||||
#FIXME: when we require 2.4+ use subprocess module
|
||||
os.system(command)
|
||||
command = player + ' ' + path_to_soundfile
|
||||
exec_command(command)
|
||||
|
||||
def get_file_path_from_dnd_dropped_uri(uri):
|
||||
path = urllib.url2pathname(uri) # escape special chars
|
||||
|
@ -464,14 +463,6 @@ def from_xs_boolean_to_python_boolean(value):
|
|||
|
||||
return val
|
||||
|
||||
def ensure_unicode_string(s):
|
||||
# py23 u'abc'.decode('utf-8') raises
|
||||
# python24 does not. if python23 is ooold we can remove this func
|
||||
# FIXME: remove this when we abandon py23
|
||||
if isinstance(s, str):
|
||||
s = s.decode('utf-8')
|
||||
return s
|
||||
|
||||
def get_xmpp_show(show):
|
||||
if show in ('online', 'offline'):
|
||||
return None
|
||||
|
@ -514,9 +505,9 @@ def get_global_status():
|
|||
|
||||
def get_icon_name_to_show(contact, account = None):
|
||||
'''Get the icon name to show in online, away, requested, ...'''
|
||||
if account and gajim.awaiting_events[account].has_key(contact.jid):
|
||||
if account and gajim.events.get_nb_roster_events(account, contact.jid):
|
||||
return 'message'
|
||||
if account and gajim.awaiting_events[account].has_key(
|
||||
if account and gajim.events.get_nb_roster_events(account,
|
||||
contact.get_full_jid()):
|
||||
return 'message'
|
||||
if contact.jid.find('@') <= 0: # if not '@' or '@' starts the jid ==> agent
|
||||
|
@ -543,6 +534,14 @@ def decode_string(string):
|
|||
|
||||
return string
|
||||
|
||||
def ensure_utf8_string(string):
|
||||
'''make sure string is in UTF-8'''
|
||||
try:
|
||||
string = decode_string(string).encode('utf-8')
|
||||
except:
|
||||
pass
|
||||
return string
|
||||
|
||||
def get_windows_reg_env(varname, default=''):
|
||||
'''asks for paths commonly used but not exposed as ENVs
|
||||
in english Windows 2003 those are:
|
||||
|
@ -727,20 +726,73 @@ def sanitize_filename(filename):
|
|||
|
||||
return filename
|
||||
|
||||
def allow_showing_notification(account):
|
||||
def allow_showing_notification(account, type = None, advanced_notif_num = None,
|
||||
first = True):
|
||||
'''is it allowed to show nofication?
|
||||
check OUR status and if we allow notifications for that status'''
|
||||
check OUR status and if we allow notifications for that status
|
||||
type is the option that need to be True ex: notify_on_signing
|
||||
first: set it to false when it's not the first message'''
|
||||
if advanced_notif_num != None:
|
||||
popup = gajim.config.get_per('notifications', str(advanced_notif_num),
|
||||
'popup')
|
||||
if popup == 'yes':
|
||||
return True
|
||||
if popup == 'no':
|
||||
return False
|
||||
if type and (not gajim.config.get(type) or not first):
|
||||
return False
|
||||
if type and gajim.config.get(type) and first:
|
||||
return True
|
||||
if gajim.config.get('autopopupaway'): # always show notification
|
||||
return True
|
||||
if gajim.connections[account].connected in (2, 3): # we're online or chat
|
||||
return True
|
||||
return False
|
||||
|
||||
def allow_popup_window(account):
|
||||
def allow_popup_window(account, advanced_notif_num = None):
|
||||
'''is it allowed to popup windows?'''
|
||||
if advanced_notif_num != None:
|
||||
popup = gajim.config.get_per('notifications', str(advanced_notif_num),
|
||||
'auto_open')
|
||||
if popup == 'yes':
|
||||
return True
|
||||
if popup == 'no':
|
||||
return False
|
||||
autopopup = gajim.config.get('autopopup')
|
||||
autopopupaway = gajim.config.get('autopopupaway')
|
||||
if autopopup and (autopopupaway or \
|
||||
gajim.connections[account].connected in (2, 3)): # we're online or chat
|
||||
return True
|
||||
return False
|
||||
|
||||
def allow_sound_notification(sound_event, advanced_notif_num = None):
|
||||
if advanced_notif_num != None:
|
||||
sound = gajim.config.get_per('notifications', str(advanced_notif_num),
|
||||
'sound')
|
||||
if sound == 'yes':
|
||||
return True
|
||||
if sound == 'no':
|
||||
return False
|
||||
if gajim.config.get_per('soundevents', sound_event, 'enabled'):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_chat_control(account, contact):
|
||||
full_jid_with_resource = contact.jid
|
||||
if contact.resource:
|
||||
full_jid_with_resource += '/' + contact.resource
|
||||
highest_contact = gajim.contacts.get_contact_with_highest_priority(
|
||||
account, contact.jid)
|
||||
# Look for a chat control that has the given resource, or default to
|
||||
# one without resource
|
||||
ctrl = gajim.interface.msg_win_mgr.get_control(full_jid_with_resource,
|
||||
account)
|
||||
if ctrl:
|
||||
return ctrl
|
||||
elif not highest_contact or not highest_contact.resource:
|
||||
# unknow contact or offline message
|
||||
return gajim.interface.msg_win_mgr.get_control(contact.jid, account)
|
||||
elif highest_contact and contact.resource != \
|
||||
highest_contact.resource:
|
||||
return None
|
||||
return gajim.interface.msg_win_mgr.get_control(contact.jid, account)
|
||||
|
|
|
@ -78,30 +78,50 @@ class Constants:
|
|||
self.SHOW_OFFLINE
|
||||
) = range(6)
|
||||
|
||||
(
|
||||
self.TYPE_AIM,
|
||||
self.TYPE_GG,
|
||||
self.TYPE_HTTP_WS,
|
||||
self.TYPE_ICQ,
|
||||
self.TYPE_MSN,
|
||||
self.TYPE_QQ,
|
||||
self.TYPE_SMS,
|
||||
self.TYPE_SMTP,
|
||||
self.TYPE_TLEN,
|
||||
self.TYPE_YAHOO,
|
||||
self.TYPE_NEWMAIL,
|
||||
self.TYPE_RSS,
|
||||
self.TYPE_WEATHER,
|
||||
) = range(13)
|
||||
|
||||
constants = Constants()
|
||||
|
||||
class Logger:
|
||||
def __init__(self):
|
||||
self.jids_already_in = [] # holds jids that we already have in DB
|
||||
|
||||
self.con = None
|
||||
|
||||
if not os.path.exists(LOG_DB_PATH):
|
||||
# this can happen only the first time (the time we create the db)
|
||||
# db is not created here but in src/common/checks_paths.py
|
||||
return
|
||||
self.init_vars()
|
||||
|
||||
|
||||
def init_vars(self):
|
||||
# if locked, wait up to 20 sec to unlock
|
||||
# before raise (hopefully should be enough)
|
||||
if self.con:
|
||||
self.con.close()
|
||||
self.con = sqlite.connect(LOG_DB_PATH, timeout = 20.0,
|
||||
isolation_level = 'IMMEDIATE')
|
||||
self.cur = self.con.cursor()
|
||||
|
||||
|
||||
self.get_jids_already_in_db()
|
||||
|
||||
def get_jids_already_in_db(self):
|
||||
self.cur.execute('SELECT jid FROM jids')
|
||||
rows = self.cur.fetchall() # list of tupples: [(u'aaa@bbb',), (u'cc@dd',)]
|
||||
self.jids_already_in = []
|
||||
for row in rows:
|
||||
# row[0] is first item of row (the only result here, the jid)
|
||||
self.jids_already_in.append(row[0])
|
||||
|
@ -192,7 +212,66 @@ class Logger:
|
|||
show_col = 'UNKNOWN'
|
||||
|
||||
return kind_col, show_col
|
||||
|
||||
|
||||
def convert_human_transport_type_to_db_api_values(self, type_):
|
||||
'''converts from string style to constant ints for db'''
|
||||
if type_ == 'aim':
|
||||
return constants.TYPE_AIM
|
||||
if type_ == 'gadu-gadu':
|
||||
return constants.TYPE_GG
|
||||
if type_ == 'http-ws':
|
||||
return constants.TYPE_HTTP_WS
|
||||
if type_ == 'icq':
|
||||
return constants.TYPE_ICQ
|
||||
if type_ == 'msn':
|
||||
return constants.TYPE_MSN
|
||||
if type_ == 'qq':
|
||||
return constants.TYPE_QQ
|
||||
if type_ == 'sms':
|
||||
return constants.TYPE_SMS
|
||||
if type_ == 'smtp':
|
||||
return constants.TYPE_SMTP
|
||||
if type_ == 'tlen':
|
||||
return constants.TYPE_TLEN
|
||||
if type_ == 'yahoo':
|
||||
return constants.TYPE_YAHOO
|
||||
if type_ == 'newmail':
|
||||
return constants.TYPE_NEWMAIL
|
||||
if type_ == 'rss':
|
||||
return constants.TYPE_RSS
|
||||
if type_ == 'weather':
|
||||
return constants.TYPE_WEATHER
|
||||
return None
|
||||
|
||||
def convert_api_values_to_human_transport_type(self, type_id):
|
||||
'''converts from constant ints for db to string style'''
|
||||
if type_id == constants.TYPE_AIM:
|
||||
return 'aim'
|
||||
if type_id == constants.TYPE_GG:
|
||||
return 'gadu-gadu'
|
||||
if type_id == constants.TYPE_HTTP_WS:
|
||||
return 'http-ws'
|
||||
if type_id == constants.TYPE_ICQ:
|
||||
return 'icq'
|
||||
if type_id == constants.TYPE_MSN:
|
||||
return 'msn'
|
||||
if type_id == constants.TYPE_QQ:
|
||||
return 'qq'
|
||||
if type_id == constants.TYPE_SMS:
|
||||
return 'sms'
|
||||
if type_id == constants.TYPE_SMTP:
|
||||
return 'smtp'
|
||||
if type_id == constants.TYPE_TLEN:
|
||||
return 'tlen'
|
||||
if type_id == constants.TYPE_YAHOO:
|
||||
return 'yahoo'
|
||||
if type_id == constants.TYPE_NEWMAIL:
|
||||
return 'newmail'
|
||||
if type_id == constants.TYPE_RSS:
|
||||
return 'rss'
|
||||
if type_id == constants.TYPE_WEATHER:
|
||||
return 'weather'
|
||||
|
||||
def commit_to_db(self, values, write_unread = False):
|
||||
#print 'saving', values
|
||||
sql = 'INSERT INTO logs (jid_id, contact_name, time, kind, show, message, subject) VALUES (?, ?, ?, ?, ?, ?, ?)'
|
||||
|
@ -238,25 +317,8 @@ class Logger:
|
|||
self.cur.execute(
|
||||
'SELECT message_id from unread_messages WHERE jid_id = %d' % jid_id)
|
||||
results = self.cur.fetchall()
|
||||
# Remove before 0.10
|
||||
except:
|
||||
try:
|
||||
self.cur.executescript('DROP TABLE unread_messages;')
|
||||
self.con.commit()
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
self.cur.executescript('''CREATE TABLE unread_messages(
|
||||
message_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
jid_id INTEGER
|
||||
);''')
|
||||
self.con.commit()
|
||||
except:
|
||||
pass
|
||||
self.con.close()
|
||||
self.jids_already_in = []
|
||||
self.init_vars()
|
||||
return []
|
||||
pass
|
||||
|
||||
for message in results:
|
||||
msg_id = message[0]
|
||||
|
@ -515,3 +577,43 @@ class Logger:
|
|||
jid_id = self.get_jid_id(jid)
|
||||
where_sql = 'jid_id = %s' % jid_id
|
||||
return where_sql
|
||||
|
||||
def save_transport_type(self, jid, type_):
|
||||
'''save the type of the transport in DB'''
|
||||
type_id = self.convert_human_transport_type_to_db_api_values(type_)
|
||||
if not type_id:
|
||||
# unknown type
|
||||
return
|
||||
self.cur.execute(
|
||||
'SELECT type from transports_cache WHERE transport = "%s"' % jid)
|
||||
results = self.cur.fetchall()
|
||||
if results:
|
||||
result = results[0][0]
|
||||
if result == type_id:
|
||||
return
|
||||
self.cur.execute(
|
||||
'UPDATE transports_cache SET type = %d WHERE transport = "%s"' % (type_id,
|
||||
jid))
|
||||
try:
|
||||
self.con.commit()
|
||||
except sqlite.OperationalError, e:
|
||||
print >> sys.stderr, str(e)
|
||||
return
|
||||
self.cur.execute(
|
||||
'INSERT INTO transports_cache VALUES ("%s", %d)' % (jid, type_id))
|
||||
try:
|
||||
self.con.commit()
|
||||
except sqlite.OperationalError, e:
|
||||
print >> sys.stderr, str(e)
|
||||
|
||||
def get_transports_type(self):
|
||||
'''return all the type of the transports in DB'''
|
||||
self.cur.execute(
|
||||
'SELECT * from transports_cache')
|
||||
results = self.cur.fetchall()
|
||||
if not results:
|
||||
return {}
|
||||
answer = {}
|
||||
for result in results:
|
||||
answer[result[0]] = self.convert_api_values_to_human_transport_type(result[1])
|
||||
return answer
|
||||
|
|
|
@ -144,7 +144,10 @@ class OptionsParser:
|
|||
self.update_config_to_01011()
|
||||
if old < [0, 10, 1, 2] and new >= [0, 10, 1, 2]:
|
||||
self.update_config_to_01012()
|
||||
if old < [0, 10, 1, 3] and new >= [0, 10, 1, 3]:
|
||||
self.update_config_to_01013()
|
||||
|
||||
gajim.logger.init_vars()
|
||||
gajim.config.set('version', new_version)
|
||||
|
||||
def update_config_x_to_09(self):
|
||||
|
@ -272,3 +275,29 @@ class OptionsParser:
|
|||
self.old_values['emoticons_theme'] == 'Disabled':
|
||||
gajim.config.set('emoticons_theme', '')
|
||||
gajim.config.set('version', '0.10.1.2')
|
||||
|
||||
def update_config_to_01013(self):
|
||||
'''create table transports_cache if there is no such table'''
|
||||
import exceptions
|
||||
try:
|
||||
from pysqlite2 import dbapi2 as sqlite
|
||||
except ImportError:
|
||||
raise exceptions.PysqliteNotAvailable
|
||||
import logger
|
||||
|
||||
con = sqlite.connect(logger.LOG_DB_PATH)
|
||||
cur = con.cursor()
|
||||
try:
|
||||
cur.executescript(
|
||||
'''
|
||||
CREATE TABLE transports_cache (
|
||||
transport TEXT UNIQUE,
|
||||
type INTEGER
|
||||
);
|
||||
'''
|
||||
)
|
||||
con.commit()
|
||||
except sqlite.OperationalError, e:
|
||||
pass
|
||||
con.close()
|
||||
gajim.config.set('version', '0.10.1.3')
|
||||
|
|
|
@ -126,12 +126,11 @@ class NBCommonClient(CommonClient):
|
|||
|
||||
def _on_connected(self):
|
||||
self.connected = 'tcp'
|
||||
if (self._Ssl is None and self.Connection.getPort() in (5223, 443)) or self._Ssl:
|
||||
try:
|
||||
transports_nb.NonBlockingTLS().PlugIn(self, now=1)
|
||||
self.connected = 'ssl'
|
||||
except socket.sslerror:
|
||||
if self._Ssl:
|
||||
transports_nb.NonBlockingTLS().PlugIn(self, now=1)
|
||||
if not self.Connection: # ssl error, stream is closed
|
||||
return
|
||||
self.connected = 'ssl'
|
||||
self.onreceive(self._on_receive_document_attrs)
|
||||
dispatcher_nb.Dispatcher().PlugIn(self)
|
||||
|
||||
|
@ -194,6 +193,8 @@ class NonBlockingClient(NBCommonClient):
|
|||
self.isplugged = True
|
||||
self.onreceive(None)
|
||||
transports_nb.NonBlockingTLS().PlugIn(self)
|
||||
if not self.Connection: # ssl error, stream is closed
|
||||
return True
|
||||
if not self.Dispatcher.Stream._document_attrs.has_key('version') or \
|
||||
not self.Dispatcher.Stream._document_attrs['version']=='1.0':
|
||||
self._is_connected()
|
||||
|
|
|
@ -134,6 +134,7 @@ class Dispatcher(PlugIn):
|
|||
return 0
|
||||
except ExpatError:
|
||||
sys.exc_clear()
|
||||
self.DEBUG('Invalid XML received from server. Forcing disconnect.')
|
||||
self._owner.Connection.pollend()
|
||||
return 0
|
||||
if len(self._pendingExceptions) > 0:
|
||||
|
|
|
@ -62,6 +62,7 @@ NS_MUC ='http://jabber.org/protocol/muc'
|
|||
NS_MUC_USER =NS_MUC+'#user'
|
||||
NS_MUC_ADMIN =NS_MUC+'#admin'
|
||||
NS_MUC_OWNER =NS_MUC+'#owner'
|
||||
NS_NICK ='http://jabber.org/protocol/nick' # JEP-0172
|
||||
NS_OFFLINE ='http://www.jabber.org/jeps/jep-0030.html' # JEP-0013
|
||||
NS_PHYSLOC ='http://jabber.org/protocol/physloc' # JEP-0112
|
||||
NS_PRESENCE ='presence' # Jabberd2
|
||||
|
@ -83,7 +84,7 @@ NS_SIGNED ='jabber:x:signed' # JEP-00
|
|||
NS_STANZAS ='urn:ietf:params:xml:ns:xmpp-stanzas'
|
||||
NS_STREAM ='http://affinix.com/jabber/stream'
|
||||
NS_STREAMS ='http://etherx.jabber.org/streams'
|
||||
NS_TIME ='jabber:iq:time'
|
||||
NS_TIME ='jabber:iq:time' # JEP-0900
|
||||
NS_TLS ='urn:ietf:params:xml:ns:xmpp-tls'
|
||||
NS_VACATION ='http://jabber.org/protocol/vacation'
|
||||
NS_VCARD ='vcard-temp'
|
||||
|
|
|
@ -371,8 +371,12 @@ class NonBlockingTLS(PlugIn):
|
|||
PlugIn.PlugIn(self, owner)
|
||||
DBG_LINE='NonBlockingTLS'
|
||||
self.on_tls_start = on_tls_start
|
||||
if now:
|
||||
res = self._startSSL()
|
||||
if now:
|
||||
try:
|
||||
res = self._startSSL()
|
||||
except Exception, e:
|
||||
self._owner.socket.pollend()
|
||||
return
|
||||
self.tls_start()
|
||||
return res
|
||||
if self._owner.Dispatcher.Stream.features:
|
||||
|
@ -434,7 +438,11 @@ class NonBlockingTLS(PlugIn):
|
|||
self.DEBUG('Got starttls response: ' + self.starttls,'error')
|
||||
return
|
||||
self.DEBUG('Got starttls proceed response. Switching to TLS/SSL...','ok')
|
||||
self._startSSL()
|
||||
try:
|
||||
self._startSSL()
|
||||
except Exception, e:
|
||||
self._owner.socket.pollend()
|
||||
return
|
||||
self._owner.Dispatcher.PlugOut()
|
||||
dispatcher_nb.Dispatcher().PlugIn(self._owner)
|
||||
|
||||
|
|
172
src/config.py
|
@ -53,6 +53,7 @@ class PreferencesWindow:
|
|||
'''Initialize Preferences window'''
|
||||
self.xml = gtkgui_helpers.get_glade('preferences_window.glade')
|
||||
self.window = self.xml.get_widget('preferences_window')
|
||||
self.window.set_transient_for(gajim.interface.roster.window)
|
||||
self.iconset_combobox = self.xml.get_widget('iconset_combobox')
|
||||
self.notify_on_new_message_radiobutton = self.xml.get_widget(
|
||||
'notify_on_new_message_radiobutton')
|
||||
|
@ -375,6 +376,32 @@ class PreferencesWindow:
|
|||
self.xml.get_widget('prompt_offline_status_message_checkbutton').\
|
||||
set_active(st)
|
||||
|
||||
# Default Status messages
|
||||
self.default_msg_tree = self.xml.get_widget('default_msg_treeview')
|
||||
# (status, translated_status, message, enabled)
|
||||
model = gtk.ListStore(str, str, str, bool)
|
||||
self.default_msg_tree.set_model(model)
|
||||
col = gtk.TreeViewColumn('Status')
|
||||
self.default_msg_tree.append_column(col)
|
||||
renderer = gtk.CellRendererText()
|
||||
col.pack_start(renderer, False)
|
||||
col.set_attributes(renderer, text = 1)
|
||||
col = gtk.TreeViewColumn('Message')
|
||||
self.default_msg_tree.append_column(col)
|
||||
renderer = gtk.CellRendererText()
|
||||
col.pack_start(renderer, True)
|
||||
col.set_attributes(renderer, text = 2)
|
||||
renderer.connect('edited', self.on_default_msg_cell_edited)
|
||||
renderer.set_property('editable', True)
|
||||
col = gtk.TreeViewColumn('Enabled')
|
||||
self.default_msg_tree.append_column(col)
|
||||
renderer = gtk.CellRendererToggle()
|
||||
col.pack_start(renderer, False)
|
||||
col.set_attributes(renderer, active = 3)
|
||||
renderer.set_property('activatable', True)
|
||||
renderer.connect('toggled', self.default_msg_toggled_cb)
|
||||
self.fill_default_msg_treeview()
|
||||
|
||||
#Status messages
|
||||
self.msg_tree = self.xml.get_widget('msg_treeview')
|
||||
model = gtk.ListStore(str, str)
|
||||
|
@ -455,11 +482,14 @@ class PreferencesWindow:
|
|||
self.on_msg_treemodel_row_changed)
|
||||
self.msg_tree.get_model().connect('row-deleted',
|
||||
self.on_msg_treemodel_row_deleted)
|
||||
self.default_msg_tree.get_model().connect('row-changed',
|
||||
self.on_default_msg_treemodel_row_changed)
|
||||
|
||||
self.theme_preferences = None
|
||||
|
||||
self.notebook.set_current_page(0)
|
||||
self.window.show_all()
|
||||
gtkgui_helpers.possibly_move_window_in_current_desktop(self.window)
|
||||
|
||||
def on_preferences_window_key_press_event(self, widget, event):
|
||||
if event.keyval == gtk.keysyms.Escape:
|
||||
|
@ -590,7 +620,23 @@ class PreferencesWindow:
|
|||
gajim.config.set('use_speller', active)
|
||||
gajim.interface.save_config()
|
||||
if active:
|
||||
self.apply_speller()
|
||||
lang = gajim.config.get('speller_language')
|
||||
if not lang:
|
||||
lang = gajim.LANG
|
||||
tv = gtk.TextView()
|
||||
try:
|
||||
spell = gtkspell.Spell(tv, lang)
|
||||
except:
|
||||
dialogs.ErrorDialog(
|
||||
_('Dictionary for lang %s not available') % lang,
|
||||
_('You have to install %s dictionary to use spellchecking, or '
|
||||
'choose another language by setting the speller_language option.'
|
||||
) % lang)
|
||||
gajim.config.set('use_speller', False)
|
||||
widget.set_active(False)
|
||||
else:
|
||||
gajim.config.set('speller_language', lang)
|
||||
self.apply_speller()
|
||||
else:
|
||||
self.remove_speller()
|
||||
|
||||
|
@ -787,6 +833,36 @@ class PreferencesWindow:
|
|||
def on_auto_xa_message_entry_changed(self, widget):
|
||||
gajim.config.set('autoxa_message', widget.get_text().decode('utf-8'))
|
||||
|
||||
def fill_default_msg_treeview(self):
|
||||
model = self.default_msg_tree.get_model()
|
||||
model.clear()
|
||||
status = []
|
||||
for status_ in gajim.config.get_per('defaultstatusmsg'):
|
||||
status.append(status_)
|
||||
status.sort()
|
||||
for status_ in status:
|
||||
msg = gajim.config.get_per('defaultstatusmsg', status_, 'message')
|
||||
enabled = gajim.config.get_per('defaultstatusmsg', status_, 'enabled')
|
||||
iter = model.append()
|
||||
uf_show = helpers.get_uf_show(status_)
|
||||
model.set(iter, 0, status_, 1, uf_show, 2, msg, 3, enabled)
|
||||
|
||||
def on_default_msg_cell_edited(self, cell, row, new_text):
|
||||
model = self.default_msg_tree.get_model()
|
||||
iter = model.get_iter_from_string(row)
|
||||
model.set_value(iter, 2, new_text)
|
||||
|
||||
def default_msg_toggled_cb(self, cell, path):
|
||||
model = self.default_msg_tree.get_model()
|
||||
model[path][3] = not model[path][3]
|
||||
|
||||
def on_default_msg_treemodel_row_changed(self, model, path, iter):
|
||||
status = model[iter][0]
|
||||
message = model[iter][2].decode('utf-8')
|
||||
gajim.config.set_per('defaultstatusmsg', status, 'enabled',
|
||||
model[iter][3])
|
||||
gajim.config.set_per('defaultstatusmsg', status, 'message', message)
|
||||
|
||||
def save_status_messages(self, model):
|
||||
for msg in gajim.config.get_per('statusmsg'):
|
||||
gajim.config.del_per('statusmsg', msg)
|
||||
|
@ -1005,6 +1081,7 @@ class AccountModificationWindow:
|
|||
def __init__(self, account):
|
||||
self.xml = gtkgui_helpers.get_glade('account_modification_window.glade')
|
||||
self.window = self.xml.get_widget('account_modification_window')
|
||||
self.window.set_transient_for(gajim.interface.roster.window)
|
||||
self.account = account
|
||||
|
||||
# init proxy list
|
||||
|
@ -1153,7 +1230,7 @@ class AccountModificationWindow:
|
|||
_('You are currently connected to the server'),
|
||||
_('To change the account name, you must be disconnected.'))
|
||||
return
|
||||
if len(gajim.awaiting_events[self.account]):
|
||||
if len(gajim.events.get_events(self.account)):
|
||||
dialogs.ErrorDialog(_('Unread events'),
|
||||
_('To change the account name, you must read all pending '
|
||||
'events.'))
|
||||
|
@ -1262,12 +1339,12 @@ class AccountModificationWindow:
|
|||
if name != self.account:
|
||||
#update variables
|
||||
gajim.interface.instances[name] = gajim.interface.instances[self.account]
|
||||
gajim.awaiting_events[name] = gajim.awaiting_events[self.account]
|
||||
gajim.nicks[name] = gajim.nicks[self.account]
|
||||
gajim.block_signed_in_notifications[name] = \
|
||||
gajim.block_signed_in_notifications[self.account]
|
||||
gajim.groups[name] = gajim.groups[self.account]
|
||||
gajim.gc_connected[name] = gajim.gc_connected[self.account]
|
||||
gajim.automatic_rooms[name] = gajim.automatic_rooms[self.account]
|
||||
gajim.newly_added[name] = gajim.newly_added[self.account]
|
||||
gajim.to_be_removed[name] = gajim.to_be_removed[self.account]
|
||||
gajim.sleeper_state[name] = gajim.sleeper_state[self.account]
|
||||
|
@ -1278,27 +1355,25 @@ class AccountModificationWindow:
|
|||
gajim.status_before_autoaway[self.account]
|
||||
|
||||
gajim.contacts.change_account_name(self.account, name)
|
||||
gajim.events.change_account_name(self.account, name)
|
||||
|
||||
#upgrade account variable in opened windows
|
||||
for kind in ('infos', 'disco', 'chats', 'gc', 'gc_config'):
|
||||
# change account variable for chat / gc controls
|
||||
for ctrl in gajim.interface.msg_win_mgr.get_controls():
|
||||
ctrl.account = name
|
||||
# upgrade account variable in opened windows
|
||||
for kind in ('infos', 'disco', 'gc_config'):
|
||||
for j in gajim.interface.instances[name][kind]:
|
||||
gajim.interface.instances[name][kind][j].account = name
|
||||
|
||||
#upgrade account in systray
|
||||
if gajim.interface.systray_enabled:
|
||||
for list in gajim.interface.systray.jids:
|
||||
if list[0] == self.account:
|
||||
list[0] = name
|
||||
|
||||
# ServiceCache object keep old property account
|
||||
if hasattr(gajim.connections[self.account], 'services_cache'):
|
||||
gajim.connections[self.account].services_cache.account = name
|
||||
del gajim.interface.instances[self.account]
|
||||
del gajim.awaiting_events[self.account]
|
||||
del gajim.nicks[self.account]
|
||||
del gajim.block_signed_in_notifications[self.account]
|
||||
del gajim.groups[self.account]
|
||||
del gajim.gc_connected[self.account]
|
||||
del gajim.automatic_rooms[self.account]
|
||||
del gajim.newly_added[self.account]
|
||||
del gajim.to_be_removed[self.account]
|
||||
del gajim.sleeper_state[self.account]
|
||||
|
@ -1411,6 +1486,11 @@ class AccountModificationWindow:
|
|||
_('Without a connection, you can not edit your personal information.'))
|
||||
return
|
||||
|
||||
if not gajim.connections[self.account].vcard_supported:
|
||||
dialogs.ErrorDialog(_("Your server doesn't support Vcard"),
|
||||
_("Your server can't save your personal information."))
|
||||
return
|
||||
|
||||
gajim.interface.edit_own_details(self.account)
|
||||
|
||||
def on_manage_proxies_button_clicked(self, widget):
|
||||
|
@ -1435,7 +1515,7 @@ class AccountModificationWindow:
|
|||
dialogs.ErrorDialog(_('Failed to get secret keys'),
|
||||
_('There was a problem retrieving your OpenPGP secret keys.'))
|
||||
return
|
||||
secret_keys['None'] = 'None'
|
||||
secret_keys[_('None')] = _('None')
|
||||
instance = dialogs.ChooseGPGKeyDialog(_('OpenPGP Key Selection'),
|
||||
_('Choose your OpenPGP key'), secret_keys)
|
||||
keyID = instance.run()
|
||||
|
@ -1444,7 +1524,7 @@ class AccountModificationWindow:
|
|||
checkbutton = self.xml.get_widget('gpg_save_password_checkbutton')
|
||||
gpg_key_label = self.xml.get_widget('gpg_key_label')
|
||||
gpg_name_label = self.xml.get_widget('gpg_name_label')
|
||||
if keyID[0] == 'None':
|
||||
if keyID[0] == _('None'):
|
||||
gpg_key_label.set_text(_('No key selected'))
|
||||
gpg_name_label.set_text('')
|
||||
checkbutton.set_sensitive(False)
|
||||
|
@ -1492,6 +1572,7 @@ class ManageProxiesWindow:
|
|||
def __init__(self):
|
||||
self.xml = gtkgui_helpers.get_glade('manage_proxies_window.glade')
|
||||
self.window = self.xml.get_widget('manage_proxies_window')
|
||||
self.window.set_transient_for(gajim.interface.roster.window)
|
||||
self.proxies_treeview = self.xml.get_widget('proxies_treeview')
|
||||
self.proxyname_entry = self.xml.get_widget('proxyname_entry')
|
||||
self.init_list()
|
||||
|
@ -1656,6 +1737,7 @@ class AccountsWindow:
|
|||
def __init__(self):
|
||||
self.xml = gtkgui_helpers.get_glade('accounts_window.glade')
|
||||
self.window = self.xml.get_widget('accounts_window')
|
||||
self.window.set_transient_for(gajim.interface.roster.window)
|
||||
self.accounts_treeview = self.xml.get_widget('accounts_treeview')
|
||||
self.modify_button = self.xml.get_widget('modify_button')
|
||||
self.remove_button = self.xml.get_widget('remove_button')
|
||||
|
@ -1711,7 +1793,7 @@ class AccountsWindow:
|
|||
if not iter:
|
||||
return
|
||||
account = model.get_value(iter, 0).decode('utf-8')
|
||||
if len(gajim.awaiting_events[account]):
|
||||
if len(gajim.events.get_events(account)):
|
||||
dialogs.ErrorDialog(_('Unread events'),
|
||||
_('Read all pending events before removing this account.'))
|
||||
return
|
||||
|
@ -1758,6 +1840,7 @@ class DataFormWindow:
|
|||
self.config = config
|
||||
self.xml = gtkgui_helpers.get_glade('data_form_window.glade')
|
||||
self.window = self.xml.get_widget('data_form_window')
|
||||
self.window.set_transient_for(gajim.interface.roster.window)
|
||||
self.config_vbox = self.xml.get_widget('config_vbox')
|
||||
if config:
|
||||
self.fill_vbox()
|
||||
|
@ -1907,10 +1990,11 @@ class ServiceRegistrationWindow(DataFormWindow):
|
|||
else:
|
||||
self.xml = gtkgui_helpers.get_glade('service_registration_window.glade')
|
||||
self.window = self.xml.get_widget('service_registration_window')
|
||||
self.window.set_transient_for(gajim.interface.roster.window)
|
||||
if infos.has_key('registered'):
|
||||
self.window.set_title(_('Edit %s' % service))
|
||||
self.window.set_title(_('Edit %s') % service)
|
||||
else:
|
||||
self.window.set_title(_('Register to %s' % service))
|
||||
self.window.set_title(_('Register to %s') % service)
|
||||
self.xml.get_widget('label').set_text(infos['instructions'])
|
||||
self.entries = {}
|
||||
self.draw_table()
|
||||
|
@ -1980,7 +2064,7 @@ class GroupchatConfigWindow(DataFormWindow):
|
|||
self.room_jid = room_jid
|
||||
self.remove_button = {}
|
||||
self.affiliation_treeview = {}
|
||||
self.removed_jid = {}
|
||||
self.list_init = {} # list at the begining
|
||||
ui_list = {'outcast': _('Ban List'),
|
||||
'member': _('Member List'),
|
||||
'owner': _('Owner List'),
|
||||
|
@ -1990,7 +2074,7 @@ class GroupchatConfigWindow(DataFormWindow):
|
|||
add_on_vbox = self.xml.get_widget('add_on_vbox')
|
||||
|
||||
for affiliation in ('outcast', 'member', 'owner', 'admin'):
|
||||
self.removed_jid[affiliation] = []
|
||||
self.list_init[affiliation] = {}
|
||||
hbox = gtk.HBox(spacing = 5)
|
||||
add_on_vbox.pack_start(hbox, False)
|
||||
|
||||
|
@ -2083,8 +2167,6 @@ class GroupchatConfigWindow(DataFormWindow):
|
|||
return
|
||||
model = self.affiliation_treeview[affiliation].get_model()
|
||||
model.append((jid,'', '', ''))
|
||||
if jid in self.removed_jid[affiliation]:
|
||||
self.removed_jid[affiliation].remove(jid)
|
||||
|
||||
def on_remove_button_clicked(self, widget, affiliation):
|
||||
selection = self.affiliation_treeview[affiliation].get_selection()
|
||||
|
@ -2097,7 +2179,6 @@ class GroupchatConfigWindow(DataFormWindow):
|
|||
iter = model.get_iter(path)
|
||||
jid = model[iter][0]
|
||||
model.remove(iter)
|
||||
self.removed_jid[affiliation].append(jid)
|
||||
self.remove_button[affiliation].set_sensitive(False)
|
||||
|
||||
def on_affiliation_treeview_cursor_changed(self, widget, affiliation):
|
||||
|
@ -2105,6 +2186,7 @@ class GroupchatConfigWindow(DataFormWindow):
|
|||
|
||||
def affiliation_list_received(self, affiliation, list):
|
||||
'''Fill the affiliation treeview'''
|
||||
self.list_init[affiliation] = list
|
||||
if not affiliation:
|
||||
return
|
||||
tv = self.affiliation_treeview[affiliation]
|
||||
|
@ -2131,18 +2213,28 @@ class GroupchatConfigWindow(DataFormWindow):
|
|||
self.config)
|
||||
for affiliation in ('outcast', 'member', 'owner', 'admin'):
|
||||
list = {}
|
||||
actual_jid_list = []
|
||||
model = self.affiliation_treeview[affiliation].get_model()
|
||||
iter = model.get_iter_first()
|
||||
# add new jid
|
||||
while iter:
|
||||
jid = model[iter][0].decode('utf-8')
|
||||
list[jid] = {'affiliation': affiliation}
|
||||
if affiliation == 'outcast':
|
||||
list[jid]['reason'] = model[iter][1].decode('utf-8')
|
||||
actual_jid_list.append(jid)
|
||||
if jid not in self.list_init[affiliation] or \
|
||||
(affiliation == 'outcast' and self.list_init[affiliation]\
|
||||
[jid].has_key('reason') and self.list_init[affiliation][jid]\
|
||||
['reason'] != model[iter][1].decode('utf-8')):
|
||||
list[jid] = {'affiliation': affiliation}
|
||||
if affiliation == 'outcast':
|
||||
list[jid]['reason'] = model[iter][1].decode('utf-8')
|
||||
iter = model.iter_next(iter)
|
||||
for jid in self.removed_jid[affiliation]:
|
||||
list[jid] = {'affiliation': 'none'}
|
||||
gajim.connections[self.account].send_gc_affiliation_list(self.room_jid,
|
||||
list)
|
||||
# remove removed one
|
||||
for jid in self.list_init[affiliation]:
|
||||
if jid not in actual_jid_list:
|
||||
list[jid] = {'affiliation': 'none'}
|
||||
if list:
|
||||
gajim.connections[self.account].send_gc_affiliation_list(
|
||||
self.room_jid, list)
|
||||
self.window.destroy()
|
||||
|
||||
#---------- RemoveAccountWindow class -------------#
|
||||
|
@ -2161,8 +2253,9 @@ class RemoveAccountWindow:
|
|||
self.account = account
|
||||
xml = gtkgui_helpers.get_glade('remove_account_window.glade')
|
||||
self.window = xml.get_widget('remove_account_window')
|
||||
self.window.set_transient_for(gajim.interface.roster.window)
|
||||
self.remove_and_unregister_radiobutton = xml.get_widget(
|
||||
'remove_and_unregister_radiobutton')
|
||||
'remove_and_unregister_radiobutton')
|
||||
self.window.set_title(_('Removing %s account') % self.account)
|
||||
xml.signal_autoconnect(self)
|
||||
self.window.show_all()
|
||||
|
@ -2195,7 +2288,7 @@ class RemoveAccountWindow:
|
|||
self.dialog = None
|
||||
if gajim.connections[self.account].connected:
|
||||
self.dialog = dialogs.ConfirmationDialog(
|
||||
_('Account "%s" is connected to the server' % self.account),
|
||||
_('Account "%s" is connected to the server') % self.account,
|
||||
_('If you remove it, the connection will be lost.'),
|
||||
on_response_ok = remove)
|
||||
else:
|
||||
|
@ -2207,18 +2300,18 @@ class RemoveAccountWindow:
|
|||
if not res:
|
||||
return
|
||||
# Close all opened windows
|
||||
gajim.interface.roster.close_all(gajim.interface.instances[self.account])
|
||||
gajim.interface.roster.close_all(self.account)
|
||||
gajim.connections[self.account].disconnect(on_purpose = True)
|
||||
del gajim.connections[self.account]
|
||||
gajim.config.del_per('accounts', self.account)
|
||||
gajim.interface.save_config()
|
||||
del gajim.interface.instances[self.account]
|
||||
del gajim.awaiting_events[self.account]
|
||||
del gajim.nicks[self.account]
|
||||
del gajim.block_signed_in_notifications[self.account]
|
||||
del gajim.groups[self.account]
|
||||
gajim.contacts.remove_account(self.account)
|
||||
del gajim.gc_connected[self.account]
|
||||
del gajim.automatic_rooms[self.account]
|
||||
del gajim.to_be_removed[self.account]
|
||||
del gajim.newly_added[self.account]
|
||||
del gajim.sleeper_state[self.account]
|
||||
|
@ -2240,6 +2333,7 @@ class ManageBookmarksWindow:
|
|||
def __init__(self):
|
||||
self.xml = gtkgui_helpers.get_glade('manage_bookmarks_window.glade')
|
||||
self.window = self.xml.get_widget('manage_bookmarks_window')
|
||||
self.window.set_transient_for(gajim.interface.roster.window)
|
||||
|
||||
#Account-JID, RoomName, Room-JID, Autojoin, Passowrd, Nick, Show_Status
|
||||
self.treestore = gtk.TreeStore(str, str, str, bool, str, str, str)
|
||||
|
@ -2538,8 +2632,11 @@ class AccountCreationWizardWindow:
|
|||
|
||||
# Connect events from comboboxentry.child
|
||||
server_comboboxentry = self.xml.get_widget('server_comboboxentry')
|
||||
server_comboboxentry.child.connect('key_press_event',
|
||||
entry = server_comboboxentry.child
|
||||
entry.connect('key_press_event',
|
||||
self.on_server_comboboxentry_key_press_event)
|
||||
completion = gtk.EntryCompletion()
|
||||
entry.set_completion(completion)
|
||||
|
||||
# parse servers.xml
|
||||
servers_xml = os.path.join(gajim.DATA_DIR, 'other', 'servers.xml')
|
||||
|
@ -2548,6 +2645,9 @@ class AccountCreationWizardWindow:
|
|||
for server in servers:
|
||||
servers_model.append((str(server[0]), int(server[1])))
|
||||
|
||||
completion.set_model(servers_model)
|
||||
completion.set_text_column(0)
|
||||
|
||||
# Put servers into comboboxentries
|
||||
server_comboboxentry.set_model(servers_model)
|
||||
server_comboboxentry.set_text_column(0)
|
||||
|
@ -2836,12 +2936,12 @@ _('You can set advanced account options by pressing Advanced button, or later by
|
|||
|
||||
# update variables
|
||||
gajim.interface.instances[self.account] = {'infos': {}, 'disco': {},
|
||||
'chats': {}, 'gc': {}, 'gc_config': {}}
|
||||
gajim.awaiting_events[self.account] = {}
|
||||
'gc_config': {}}
|
||||
gajim.connections[self.account].connected = 0
|
||||
gajim.groups[self.account] = {}
|
||||
gajim.contacts.add_account(self.account)
|
||||
gajim.gc_connected[self.account] = {}
|
||||
gajim.automatic_rooms[self.account] = {}
|
||||
gajim.newly_added[self.account] = []
|
||||
gajim.to_be_removed[self.account] = []
|
||||
gajim.nicks[self.account] = config['name']
|
||||
|
|
|
@ -28,6 +28,7 @@ import pango
|
|||
import gobject
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
import tooltips
|
||||
import dialogs
|
||||
import locale
|
||||
|
@ -132,6 +133,10 @@ class ConversationTextview:
|
|||
|
||||
buffer.create_tag('focus-out-line', justification = gtk.JUSTIFY_CENTER)
|
||||
|
||||
self.allow_focus_out_line = True
|
||||
# holds the iter's offset which points to the end of --- line
|
||||
self.focus_out_end_iter_offset = None
|
||||
|
||||
self.line_tooltip = tooltips.BaseTooltip()
|
||||
|
||||
def del_handlers(self):
|
||||
|
@ -187,6 +192,68 @@ class ConversationTextview:
|
|||
self.tv.scroll_to_iter(end_iter, 0, False, 1, 1)
|
||||
return False # when called in an idle_add, just do it once
|
||||
|
||||
def show_focus_out_line(self):
|
||||
if not self.allow_focus_out_line:
|
||||
# if room did not receive focus-in from the last time we added
|
||||
# --- line then do not readd
|
||||
return
|
||||
|
||||
print_focus_out_line = False
|
||||
buffer = self.tv.get_buffer()
|
||||
|
||||
if self.focus_out_end_iter_offset is None:
|
||||
# this happens only first time we focus out on this room
|
||||
print_focus_out_line = True
|
||||
|
||||
else:
|
||||
if self.focus_out_end_iter_offset != buffer.get_end_iter().\
|
||||
get_offset():
|
||||
# this means after last-focus something was printed
|
||||
# (else end_iter's offset is the same as before)
|
||||
# only then print ---- line (eg. we avoid printing many following
|
||||
# ---- lines)
|
||||
print_focus_out_line = True
|
||||
|
||||
if print_focus_out_line and buffer.get_char_count() > 0:
|
||||
buffer.begin_user_action()
|
||||
|
||||
# remove previous focus out line if such focus out line exists
|
||||
if self.focus_out_end_iter_offset is not None:
|
||||
end_iter_for_previous_line = buffer.get_iter_at_offset(
|
||||
self.focus_out_end_iter_offset)
|
||||
begin_iter_for_previous_line = end_iter_for_previous_line.copy()
|
||||
# img_char+1 (the '\n')
|
||||
begin_iter_for_previous_line.backward_chars(2)
|
||||
|
||||
# remove focus out line
|
||||
buffer.delete(begin_iter_for_previous_line,
|
||||
end_iter_for_previous_line)
|
||||
|
||||
# add the new focus out line
|
||||
# FIXME: Why is this loaded from disk everytime
|
||||
path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps', 'muc_separator.png')
|
||||
focus_out_line_pixbuf = gtk.gdk.pixbuf_new_from_file(path_to_file)
|
||||
end_iter = buffer.get_end_iter()
|
||||
buffer.insert(end_iter, '\n')
|
||||
buffer.insert_pixbuf(end_iter, focus_out_line_pixbuf)
|
||||
|
||||
end_iter = buffer.get_end_iter()
|
||||
before_img_iter = end_iter.copy()
|
||||
before_img_iter.backward_char() # one char back (an image also takes one char)
|
||||
buffer.apply_tag_by_name('focus-out-line', before_img_iter, end_iter)
|
||||
#FIXME: remove this workaround when bug is fixed
|
||||
# c http://bugzilla.gnome.org/show_bug.cgi?id=318569
|
||||
|
||||
self.allow_focus_out_line = False
|
||||
|
||||
# update the iter we hold to make comparison the next time
|
||||
self.focus_out_end_iter_offset = buffer.get_end_iter().get_offset()
|
||||
|
||||
buffer.end_user_action()
|
||||
|
||||
# scroll to the end (via idle in case the scrollbar has appeared)
|
||||
gobject.idle_add(self.scroll_to_end)
|
||||
|
||||
def show_line_tooltip(self):
|
||||
pointer = self.tv.get_pointer()
|
||||
x, y = self.tv.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT, pointer[0],
|
||||
|
@ -241,6 +308,7 @@ class ConversationTextview:
|
|||
buffer = self.tv.get_buffer()
|
||||
start, end = buffer.get_bounds()
|
||||
buffer.delete(start, end)
|
||||
self.focus_out_end_iter_offset = None
|
||||
|
||||
def visit_url_from_menuitem(self, widget, link):
|
||||
'''basically it filters out the widget instance'''
|
||||
|
@ -613,9 +681,11 @@ class ConversationTextview:
|
|||
if day_str:
|
||||
format += day_str + ' '
|
||||
format += '%X' + after_str
|
||||
# format comes as unicode, because of day_str.
|
||||
# we convert it to the encoding that we want
|
||||
tim_format = time.strftime(format, tim).encode('utf-8')
|
||||
tim_format = time.strftime(format, tim)
|
||||
# if tim_format comes as unicode because of day_str.
|
||||
# we convert it to the encoding that we want (and that is utf-8)
|
||||
tim_format = helpers.ensure_utf8_string(tim_format)
|
||||
tim_format = tim_format.encode('utf-8')
|
||||
buffer.insert_with_tags_by_name(end_iter, tim_format + ' ',
|
||||
*other_tags_for_time)
|
||||
elif current_print_time == 'sometimes' and kind != 'info':
|
||||
|
@ -627,7 +697,7 @@ class ConversationTextview:
|
|||
end_iter = buffer.get_end_iter()
|
||||
if gajim.config.get('print_time_fuzzy') > 0:
|
||||
fc = FuzzyClock()
|
||||
fc.setTime(time.strftime('%H:%M'))
|
||||
fc.setTime(time.strftime('%H:%M', tim))
|
||||
ft = fc.getFuzzyTime(gajim.config.get('print_time_fuzzy'))
|
||||
tim_format = ft.decode(locale.getpreferredencoding())
|
||||
else:
|
||||
|
@ -642,6 +712,7 @@ class ConversationTextview:
|
|||
other_text_tag = self.detect_other_text_tag(text, kind)
|
||||
text_tags = other_tags_for_text[:] # create a new list
|
||||
if other_text_tag:
|
||||
# note that color of /me may be overwritten in gc_control
|
||||
text_tags.append(other_text_tag)
|
||||
else: # not status nor /me
|
||||
if gajim.config.get(
|
||||
|
|
555
src/dialogs.py
|
@ -21,7 +21,6 @@
|
|||
import gtk
|
||||
import gobject
|
||||
import os
|
||||
import sys
|
||||
|
||||
import gtkgui_helpers
|
||||
import vcard
|
||||
|
@ -44,85 +43,97 @@ from common import helpers
|
|||
|
||||
class EditGroupsDialog:
|
||||
'''Class for the edit group dialog window'''
|
||||
def __init__(self, user, account):
|
||||
def __init__(self, list_):
|
||||
'''list_ is a list of (contact, account) tuples'''
|
||||
self.xml = gtkgui_helpers.get_glade('edit_groups_dialog.glade')
|
||||
self.dialog = self.xml.get_widget('edit_groups_dialog')
|
||||
self.account = account
|
||||
self.user = user
|
||||
self.dialog.set_transient_for(gajim.interface.roster.window)
|
||||
self.list_ = list_
|
||||
self.changes_made = False
|
||||
self.list = self.xml.get_widget('groups_treeview')
|
||||
self.xml.get_widget('nickname_label').set_markup(
|
||||
_("Contact's name: <i>%s</i>") % user.get_shown_name())
|
||||
self.xml.get_widget('jid_label').set_markup(
|
||||
_('JID: <i>%s</i>') % user.jid)
|
||||
|
||||
if len(list_) == 1:
|
||||
contact = list_[0][0]
|
||||
self.xml.get_widget('nickname_label').set_markup(
|
||||
_("Contact name: <i>%s</i>") % contact.get_shown_name())
|
||||
self.xml.get_widget('jid_label').set_markup(
|
||||
_('JID: <i>%s</i>') % contact.jid)
|
||||
else:
|
||||
self.xml.get_widget('nickname_label').set_no_show_all(True)
|
||||
self.xml.get_widget('nickname_label').hide()
|
||||
self.xml.get_widget('jid_label').set_no_show_all(True)
|
||||
self.xml.get_widget('jid_label').hide()
|
||||
|
||||
self.xml.signal_autoconnect(self)
|
||||
self.init_list()
|
||||
|
||||
def run(self):
|
||||
self.dialog.show_all()
|
||||
if self.changes_made:
|
||||
gajim.connections[self.account].update_contact(self.user.jid,
|
||||
self.user.name, self.user.groups)
|
||||
for (contact, account) in self.list_:
|
||||
gajim.connections[account].update_contact(contact.jid, contact.name,
|
||||
contact.groups)
|
||||
|
||||
def on_edit_groups_dialog_response(self, widget, response_id):
|
||||
if response_id == gtk.RESPONSE_CLOSE:
|
||||
self.dialog.destroy()
|
||||
|
||||
def update_contact(self):
|
||||
tag = gajim.contacts.get_metacontacts_tag(self.account, self.user.jid)
|
||||
if not tag:
|
||||
gajim.interface.roster.remove_contact(self.user, self.account)
|
||||
gajim.interface.roster.add_contact_to_roster(self.user.jid,
|
||||
self.account)
|
||||
gajim.connections[self.account].update_contact(self.user.jid,
|
||||
self.user.name, self.user.groups)
|
||||
return
|
||||
all_jid = gajim.contacts.get_metacontacts_jids(tag)
|
||||
for _account in all_jid:
|
||||
if not gajim.interface.roster.regroup and _account != self.account:
|
||||
for (contact, account) in self.list_:
|
||||
tag = gajim.contacts.get_metacontacts_tag(account, contact.jid)
|
||||
if not tag:
|
||||
gajim.interface.roster.remove_contact(contact, account)
|
||||
gajim.interface.roster.add_contact_to_roster(contact.jid, account)
|
||||
gajim.connections[account].update_contact(contact.jid, contact.name,
|
||||
contact.groups)
|
||||
continue
|
||||
for _jid in all_jid[_account]:
|
||||
c = gajim.contacts.get_first_contact_from_jid(_account, _jid)
|
||||
if not c:
|
||||
all_jid = gajim.contacts.get_metacontacts_jids(tag)
|
||||
for _account in all_jid:
|
||||
if not gajim.interface.roster.regroup and _account != account:
|
||||
continue
|
||||
gajim.interface.roster.remove_contact(c, _account)
|
||||
gajim.interface.roster.add_contact_to_roster(_jid, _account)
|
||||
gajim.connections[_account].update_contact(_jid, c.name, c.groups)
|
||||
for _jid in all_jid[_account]:
|
||||
c = gajim.contacts.get_first_contact_from_jid(_account, _jid)
|
||||
if not c:
|
||||
continue
|
||||
gajim.interface.roster.remove_contact(c, _account)
|
||||
gajim.interface.roster.add_contact_to_roster(_jid, _account)
|
||||
gajim.connections[_account].update_contact(_jid, c.name,
|
||||
c.groups)
|
||||
|
||||
def remove_group(self, group):
|
||||
'''add group group to self.user and all his brothers'''
|
||||
tag = gajim.contacts.get_metacontacts_tag(self.account, self.user.jid)
|
||||
if not tag:
|
||||
if group in self.user.groups:
|
||||
self.user.groups.remove(group)
|
||||
return
|
||||
all_jid = gajim.contacts.get_metacontacts_jids(tag)
|
||||
for _account in all_jid:
|
||||
if not gajim.interface.roster.regroup and _account != self.account:
|
||||
'''remove group group from all contacts and all their brothers'''
|
||||
for (contact, account) in self.list_:
|
||||
tag = gajim.contacts.get_metacontacts_tag(account, contact.jid)
|
||||
if not tag:
|
||||
if group in contact.groups:
|
||||
contact.groups.remove(group)
|
||||
continue
|
||||
for _jid in all_jid[_account]:
|
||||
contacts = gajim.contacts.get_contact(_account, _jid)
|
||||
for contact in contacts:
|
||||
if group in contact.groups:
|
||||
contact.groups.remove(group)
|
||||
all_jid = gajim.contacts.get_metacontacts_jids(tag)
|
||||
for _account in all_jid:
|
||||
if not gajim.interface.roster.regroup and _account != account:
|
||||
continue
|
||||
for _jid in all_jid[_account]:
|
||||
contacts = gajim.contacts.get_contact(_account, _jid)
|
||||
for c in contacts:
|
||||
if group in c.groups:
|
||||
c.groups.remove(group)
|
||||
|
||||
def add_group(self, group):
|
||||
'''add group group to self.user and all his brothers'''
|
||||
tag = gajim.contacts.get_metacontacts_tag(self.account, self.user.jid)
|
||||
if not tag:
|
||||
if group not in self.user.groups:
|
||||
self.user.groups.append(group)
|
||||
return
|
||||
all_jid = gajim.contacts.get_metacontacts_jids(tag)
|
||||
for _account in all_jid:
|
||||
if not gajim.interface.roster.regroup and _account != self.account:
|
||||
'''add group group to all contacts and all their brothers'''
|
||||
for (contact, account) in self.list_:
|
||||
tag = gajim.contacts.get_metacontacts_tag(account, contact.jid)
|
||||
if not tag:
|
||||
if group not in contact.groups:
|
||||
contact.groups.append(group)
|
||||
continue
|
||||
for _jid in all_jid[_account]:
|
||||
contacts = gajim.contacts.get_contact(_account, _jid)
|
||||
for contact in contacts:
|
||||
if not group in contact.groups:
|
||||
contact.groups.append(group)
|
||||
all_jid = gajim.contacts.get_metacontacts_jids(tag)
|
||||
for _account in all_jid:
|
||||
if not gajim.interface.roster.regroup and _account != account:
|
||||
continue
|
||||
for _jid in all_jid[_account]:
|
||||
contacts = gajim.contacts.get_contact(_account, _jid)
|
||||
for c in contacts:
|
||||
if not group in c.groups:
|
||||
c.groups.append(group)
|
||||
|
||||
def on_add_button_clicked(self, widget):
|
||||
group = self.xml.get_widget('group_entry').get_text().decode('utf-8')
|
||||
|
@ -136,7 +147,7 @@ class EditGroupsDialog:
|
|||
return
|
||||
iter = model.iter_next(iter)
|
||||
self.changes_made = True
|
||||
model.append((group, True))
|
||||
model.append((group, True, False))
|
||||
self.add_group(group)
|
||||
self.update_contact()
|
||||
self.init_list() # Re-draw list to sort new item
|
||||
|
@ -144,7 +155,11 @@ class EditGroupsDialog:
|
|||
def group_toggled_cb(self, cell, path):
|
||||
self.changes_made = True
|
||||
model = self.list.get_model()
|
||||
model[path][1] = not model[path][1]
|
||||
if model[path][2]:
|
||||
model[path][2] = False
|
||||
model[path][1] = True
|
||||
else:
|
||||
model[path][1] = not model[path][1]
|
||||
group = model[path][0].decode('utf-8')
|
||||
if model[path][1]:
|
||||
self.add_group(group)
|
||||
|
@ -153,23 +168,39 @@ class EditGroupsDialog:
|
|||
self.update_contact()
|
||||
|
||||
def init_list(self):
|
||||
store = gtk.ListStore(str, bool)
|
||||
store = gtk.ListStore(str, bool, bool)
|
||||
self.list.set_model(store)
|
||||
for column in self.list.get_columns(): # Clear treeview when re-drawing
|
||||
self.list.remove_column(column)
|
||||
groups = [] # Store accounts in a list so we can sort them
|
||||
for g in gajim.groups[self.account].keys():
|
||||
if g in helpers.special_groups:
|
||||
continue
|
||||
in_group = False
|
||||
if g in self.user.groups:
|
||||
in_group = True
|
||||
groups.append([g, in_group])
|
||||
groups.sort()
|
||||
for group in groups:
|
||||
accounts = []
|
||||
# Store groups in a list so we can sort them and the number of contacts in
|
||||
# it
|
||||
groups = {}
|
||||
for (contact, account) in self.list_:
|
||||
if account not in accounts:
|
||||
accounts.append(account)
|
||||
for g in gajim.groups[account].keys():
|
||||
if g in helpers.special_groups:
|
||||
continue
|
||||
if g in groups:
|
||||
continue
|
||||
groups[g] = 0
|
||||
for g in contact.groups:
|
||||
groups[g] += 1
|
||||
group_list = groups.keys()
|
||||
group_list.sort()
|
||||
for group in group_list:
|
||||
iter = store.append()
|
||||
store.set(iter, 0, group[0]) # Group name
|
||||
store.set(iter, 1, group[1]) # In group boolean
|
||||
store.set(iter, 0, group) # Group name
|
||||
if groups[group] == 0:
|
||||
store.set(iter, 1, False)
|
||||
else:
|
||||
store.set(iter, 1, True)
|
||||
if groups[group] == len(self.list_):
|
||||
# all contacts are in this group
|
||||
store.set(iter, 2, False)
|
||||
else:
|
||||
store.set(iter, 2, True)
|
||||
column = gtk.TreeViewColumn(_('Group'))
|
||||
column.set_expand(True)
|
||||
self.list.append_column(column)
|
||||
|
@ -184,7 +215,7 @@ class EditGroupsDialog:
|
|||
column.pack_start(renderer)
|
||||
renderer.set_property('activatable', True)
|
||||
renderer.connect('toggled', self.group_toggled_cb)
|
||||
column.set_attributes(renderer, active = 1)
|
||||
column.set_attributes(renderer, active = 1, inconsistent = 2)
|
||||
|
||||
class PassphraseDialog:
|
||||
'''Class for Passphrase dialog'''
|
||||
|
@ -223,6 +254,7 @@ class ChooseGPGKeyDialog:
|
|||
prompt_label = xml.get_widget('prompt_label')
|
||||
prompt_label.set_text(prompt_text)
|
||||
model = gtk.ListStore(str, str)
|
||||
model.set_sort_func(1, self.sort_keys)
|
||||
model.set_sort_column_id(1, gtk.SORT_ASCENDING)
|
||||
self.keys_treeview.set_model(model)
|
||||
#columns
|
||||
|
@ -235,6 +267,17 @@ class ChooseGPGKeyDialog:
|
|||
self.fill_tree(secret_keys, selected)
|
||||
self.window.show_all()
|
||||
|
||||
def sort_keys(self, model, iter1, iter2):
|
||||
value1 = model[iter1][1]
|
||||
value2 = model[iter2][1]
|
||||
if value1 == _('None'):
|
||||
return -1
|
||||
elif value2 == _('None'):
|
||||
return 1
|
||||
elif value1 < value2:
|
||||
return -1
|
||||
return 1
|
||||
|
||||
def run(self):
|
||||
rep = self.window.run()
|
||||
if rep == gtk.RESPONSE_OK:
|
||||
|
@ -261,6 +304,7 @@ class ChangeStatusMessageDialog:
|
|||
self.show = show
|
||||
self.xml = gtkgui_helpers.get_glade('change_status_message_dialog.glade')
|
||||
self.window = self.xml.get_widget('change_status_message_dialog')
|
||||
self.window.set_transient_for(gajim.interface.roster.window)
|
||||
if show:
|
||||
uf_show = helpers.get_uf_show(show)
|
||||
title_text = _('%s Status Message') % uf_show
|
||||
|
@ -361,6 +405,12 @@ class ChangeStatusMessageDialog:
|
|||
|
||||
class AddNewContactWindow:
|
||||
'''Class for AddNewContactWindow'''
|
||||
uid_labels = {'jabber': _('Jabber ID'),
|
||||
'aim': _('AIM Address'),
|
||||
'gadu-gadu': _('GG Number'),
|
||||
'icq': _('ICQ Number'),
|
||||
'msn': _('MSN Address'),
|
||||
'yahoo': _('Yahoo! Address')}
|
||||
def __init__(self, account = None, jid = None, user_nick = None,
|
||||
group = None):
|
||||
self.account = account
|
||||
|
@ -376,87 +426,123 @@ class AddNewContactWindow:
|
|||
self.account = account
|
||||
else:
|
||||
accounts = [self.account]
|
||||
if self.account:
|
||||
location = gajim.interface.instances[self.account]
|
||||
else:
|
||||
location = gajim.interface.instances
|
||||
if location.has_key('add_contact'):
|
||||
location['add_contact'].window.present()
|
||||
# An instance is already opened
|
||||
return
|
||||
location['add_contact'] = self
|
||||
self.xml = gtkgui_helpers.get_glade('add_new_contact_window.glade')
|
||||
self.account_combobox = self.xml.get_widget('account_combobox')
|
||||
self.account_hbox = self.xml.get_widget('account_hbox')
|
||||
self.account_label = self.xml.get_widget('account_label')
|
||||
self.window = self.xml.get_widget('add_new_contact_window')
|
||||
self.uid_entry = self.xml.get_widget('uid_entry')
|
||||
self.protocol_combobox = self.xml.get_widget('protocol_combobox')
|
||||
self.protocol_hbox = self.xml.get_widget('protocol_hbox')
|
||||
self.jid_entry = self.xml.get_widget('jid_entry')
|
||||
self.nickname_entry = self.xml.get_widget('nickname_entry')
|
||||
for w in ('account_combobox', 'account_hbox', 'account_label',
|
||||
'uid_label', 'uid_entry', 'protocol_combobox', 'protocol_jid_combobox',
|
||||
'protocol_hbox', 'nickname_entry', 'message_scrolledwindow',
|
||||
'register_hbox', 'subscription_table', 'add_button',
|
||||
'message_textview', 'connected_label', 'group_comboboxentry'):
|
||||
self.__dict__[w] = self.xml.get_widget(w)
|
||||
if account and len(gajim.connections) >= 2:
|
||||
prompt_text =\
|
||||
_('Please fill in the data of the contact you want to add in account %s') %account
|
||||
else:
|
||||
prompt_text = _('Please fill in the data of the contact you want to add')
|
||||
self.xml.get_widget('prompt_label').set_text(prompt_text)
|
||||
self.old_uid_value = ''
|
||||
liststore = gtk.ListStore(str, str)
|
||||
liststore.append(['Jabber', ''])
|
||||
self.agents = ['Jabber']
|
||||
jid_agents = []
|
||||
self.agents = {'jabber': []}
|
||||
# types to which we are not subscribed but account has an agent for it
|
||||
self.available_types = []
|
||||
for acct in accounts:
|
||||
for j in gajim.contacts.get_jid_list(acct):
|
||||
contact = gajim.contacts.get_first_contact_from_jid(acct, j)
|
||||
if _('Transports') in contact.groups and contact.show != 'offline' and\
|
||||
contact.show != 'error':
|
||||
jid_agents.append(j)
|
||||
for a in jid_agents:
|
||||
if a.find('aim') > -1:
|
||||
name = 'AIM'
|
||||
elif a.find('icq') > -1:
|
||||
name = 'ICQ'
|
||||
elif a.find('msn') > -1:
|
||||
name = 'MSN'
|
||||
elif a.find('yahoo') > -1:
|
||||
name = 'Yahoo!'
|
||||
else:
|
||||
name = a
|
||||
liststore.append([name, a])
|
||||
self.agents.append(name)
|
||||
self.protocol_combobox.set_model(liststore)
|
||||
self.protocol_combobox.set_active(0)
|
||||
self.fill_jid()
|
||||
if jid:
|
||||
self.jid_entry.set_text(jid)
|
||||
self.uid_entry.set_sensitive(False)
|
||||
jid_splited = jid.split('@')
|
||||
if jid_splited[1] in jid_agents:
|
||||
uid = jid_splited[0].replace('%', '@')
|
||||
self.uid_entry.set_text(uid)
|
||||
self.protocol_combobox.set_active(jid_agents.index(jid_splited[1])\
|
||||
+ 1)
|
||||
else:
|
||||
self.uid_entry.set_text(jid)
|
||||
self.protocol_combobox.set_active(0)
|
||||
if user_nick:
|
||||
self.nickname_entry.set_text(user_nick)
|
||||
else:
|
||||
self.set_nickname()
|
||||
self.nickname_entry.grab_focus()
|
||||
self.group_comboboxentry = self.xml.get_widget('group_comboboxentry')
|
||||
if _('Transports') in contact.groups:
|
||||
type_ = gajim.get_transport_name_from_jid(j)
|
||||
if self.agents.has_key(type_):
|
||||
self.agents[type_].append(j)
|
||||
else:
|
||||
self.agents[type_] = [j]
|
||||
# Now add the one to which we can register
|
||||
for acct in accounts:
|
||||
for type_ in gajim.connections[account].available_transports:
|
||||
if type_ in self.agents:
|
||||
continue
|
||||
self.agents[type_] = []
|
||||
for jid_ in gajim.connections[account].available_transports[type_]:
|
||||
self.agents[type_].append(jid_)
|
||||
self.available_types.append(type_)
|
||||
liststore = gtk.ListStore(str)
|
||||
self.group_comboboxentry.set_model(liststore)
|
||||
liststore = gtk.ListStore(str, str)
|
||||
uf_type = {'jabber': 'Jabber', 'aim': 'AIM', 'gadu-gadu': 'Gadu Gadu',
|
||||
'icq': 'ICQ', 'msn': 'MSN', 'yahoo': 'Yahoo'}
|
||||
# Jabber as first
|
||||
liststore.append(['Jabber', 'jabber'])
|
||||
for type_ in self.agents:
|
||||
if type_ == 'jabber':
|
||||
continue
|
||||
if type_ in uf_type:
|
||||
liststore.append([uf_type[type_], type_])
|
||||
else:
|
||||
liststore.append([type_, type_])
|
||||
self.protocol_combobox.set_model(liststore)
|
||||
self.protocol_combobox.set_active(0)
|
||||
self.protocol_jid_combobox.set_sensitive(False)
|
||||
self.subscription_table.set_no_show_all(True)
|
||||
self.message_scrolledwindow.set_no_show_all(True)
|
||||
self.register_hbox.set_no_show_all(True)
|
||||
self.register_hbox.hide()
|
||||
self.connected_label.set_no_show_all(True)
|
||||
self.connected_label.hide()
|
||||
liststore = gtk.ListStore(str)
|
||||
self.protocol_jid_combobox.set_model(liststore)
|
||||
self.xml.signal_autoconnect(self)
|
||||
if jid:
|
||||
type_ = gajim.get_transport_name_from_jid(jid) or 'jabber'
|
||||
if type_ == 'jabber':
|
||||
self.uid_entry.set_text(jid)
|
||||
else:
|
||||
uid, transport = gajim.get_room_name_and_server_from_room_jid(jid)
|
||||
self.uid_entry.set_text(uid.replace('%', '@', 1))
|
||||
#set protocol_combobox
|
||||
model = self.protocol_combobox.get_model()
|
||||
iter = model.get_iter_first()
|
||||
i = 0
|
||||
while iter:
|
||||
if model[iter][1] == type_:
|
||||
self.protocol_combobox.set_active(i)
|
||||
break
|
||||
iter = model.iter_next(iter)
|
||||
i += 1
|
||||
|
||||
# set protocol_jid_combobox
|
||||
self.protocol_combobox.set_active(0)
|
||||
model = self.protocol_jid_combobox.get_model()
|
||||
iter = model.get_iter_first()
|
||||
i = 0
|
||||
while iter:
|
||||
if model[iter][0] == transport:
|
||||
self.protocol_combobox.set_active(i)
|
||||
break
|
||||
iter = model.iter_next(iter)
|
||||
i += 1
|
||||
if user_nick:
|
||||
self.nickname_entry.set_text(user_nick)
|
||||
self.nickname_entry.grab_focus()
|
||||
else:
|
||||
self.uid_entry.grab_focus()
|
||||
group_names = []
|
||||
i = 0
|
||||
for acct in accounts:
|
||||
for g in gajim.groups[acct].keys():
|
||||
if g not in helpers.special_groups and g not in group_names:
|
||||
group_names.append(g)
|
||||
self.group_comboboxentry.append_text(g)
|
||||
if group == g:
|
||||
self.group_comboboxentry.set_active(i)
|
||||
i += 1
|
||||
group_names.sort()
|
||||
i = 0
|
||||
for g in group_names:
|
||||
self.group_comboboxentry.append_text(g)
|
||||
if group == g:
|
||||
self.group_comboboxentry.set_active(i)
|
||||
i += 1
|
||||
|
||||
if not jid_agents:
|
||||
# There are no transports, so hide the protocol combobox and label
|
||||
self.protocol_hbox.hide()
|
||||
self.protocol_hbox.set_no_show_all(True)
|
||||
protocol_label = self.xml.get_widget('protocol_label')
|
||||
protocol_label.hide()
|
||||
protocol_label.set_no_show_all(True)
|
||||
if self.account:
|
||||
self.account_label.hide()
|
||||
self.account_hbox.hide()
|
||||
|
@ -468,9 +554,19 @@ _('Please fill in the data of the contact you want to add in account %s') %accou
|
|||
liststore.append([acct, acct])
|
||||
self.account_combobox.set_model(liststore)
|
||||
self.account_combobox.set_active(0)
|
||||
self.xml.signal_autoconnect(self)
|
||||
self.window.show_all()
|
||||
|
||||
def on_add_new_contact_window_destroy(self, widget):
|
||||
if self.account:
|
||||
location = gajim.interface.instances[self.account]
|
||||
else:
|
||||
location = gajim.interface.instances
|
||||
del location['add_contact']
|
||||
|
||||
def on_register_button_clicked(self, widget):
|
||||
jid = self.protocol_jid_combobox.get_active_text().decode('utf-8')
|
||||
gajim.connections[self.account].request_register_agent_info(jid)
|
||||
|
||||
def on_add_new_contact_window_key_press_event(self, widget, event):
|
||||
if event.keyval == gtk.keysyms.Escape: # ESCAPE
|
||||
self.window.destroy()
|
||||
|
@ -479,13 +575,20 @@ _('Please fill in the data of the contact you want to add in account %s') %accou
|
|||
'''When Cancel button is clicked'''
|
||||
self.window.destroy()
|
||||
|
||||
def on_subscribe_button_clicked(self, widget):
|
||||
def on_add_button_clicked(self, widget):
|
||||
'''When Subscribe button is clicked'''
|
||||
jid = self.jid_entry.get_text().decode('utf-8')
|
||||
nickname = self.nickname_entry.get_text().decode('utf-8')
|
||||
jid = self.uid_entry.get_text().decode('utf-8')
|
||||
if not jid:
|
||||
return
|
||||
|
||||
|
||||
model = self.protocol_combobox.get_model()
|
||||
iter = self.protocol_combobox.get_active_iter()
|
||||
type_ = model[iter][1]
|
||||
if type_ != 'jabber':
|
||||
transport = self.protocol_jid_combobox.get_active_text().decode(
|
||||
'utf-8')
|
||||
jid = jid.replace('@', '%') + '@' + transport
|
||||
|
||||
# check if jid is conform to RFC and stringprep it
|
||||
try:
|
||||
jid = helpers.parse_jid(jid)
|
||||
|
@ -500,6 +603,7 @@ _('Please fill in the data of the contact you want to add in account %s') %accou
|
|||
ErrorDialog(pritext, _('The user ID must not contain a resource.'))
|
||||
return
|
||||
|
||||
nickname = self.nickname_entry.get_text().decode('utf-8') or ''
|
||||
# get value of account combobox, if account was not specified
|
||||
if not self.account:
|
||||
model = self.account_combobox.get_model()
|
||||
|
@ -514,57 +618,81 @@ _('Please fill in the data of the contact you want to add in account %s') %accou
|
|||
_('This contact is already listed in your roster.'))
|
||||
return
|
||||
|
||||
message_buffer = self.xml.get_widget('message_textview').get_buffer()
|
||||
start_iter = message_buffer.get_start_iter()
|
||||
end_iter = message_buffer.get_end_iter()
|
||||
message = message_buffer.get_text(start_iter, end_iter).decode('utf-8')
|
||||
if type_ == 'jabber':
|
||||
message_buffer = self.message_textview.get_buffer()
|
||||
start_iter = message_buffer.get_start_iter()
|
||||
end_iter = message_buffer.get_end_iter()
|
||||
message = message_buffer.get_text(start_iter, end_iter).decode('utf-8')
|
||||
else:
|
||||
message= ''
|
||||
group = self.group_comboboxentry.child.get_text().decode('utf-8')
|
||||
auto_auth = self.xml.get_widget('auto_authorize_checkbutton').get_active()
|
||||
gajim.interface.roster.req_sub(self, jid, message, self.account,
|
||||
group = group, pseudo = nickname, auto_auth = auto_auth)
|
||||
self.window.destroy()
|
||||
|
||||
def fill_jid(self):
|
||||
model = self.protocol_combobox.get_model()
|
||||
index = self.protocol_combobox.get_active()
|
||||
jid = self.uid_entry.get_text().decode('utf-8').strip()
|
||||
if index > 0: # it's not jabber but a transport
|
||||
jid = jid.replace('@', '%')
|
||||
agent = model[index][1].decode('utf-8')
|
||||
if agent:
|
||||
jid += '@' + agent
|
||||
self.jid_entry.set_text(jid)
|
||||
|
||||
def on_protocol_combobox_changed(self, widget):
|
||||
self.fill_jid()
|
||||
model = widget.get_model()
|
||||
iter = widget.get_active_iter()
|
||||
type_ = model[iter][1]
|
||||
model = self.protocol_jid_combobox.get_model()
|
||||
model.clear()
|
||||
if len(self.agents[type_]):
|
||||
for jid_ in self.agents[type_]:
|
||||
model.append([jid_])
|
||||
self.protocol_jid_combobox.set_active(0)
|
||||
self.protocol_jid_combobox.set_sensitive(True)
|
||||
else:
|
||||
self.protocol_jid_combobox.set_sensitive(False)
|
||||
if type_ in self.uid_labels:
|
||||
self.uid_label.set_text(self.uid_labels[type_])
|
||||
else:
|
||||
self.uid_label.set_text(_('User ID'))
|
||||
if type_ == 'jabber':
|
||||
self.message_scrolledwindow.show()
|
||||
else:
|
||||
self.message_scrolledwindow.hide()
|
||||
if type_ in self.available_types:
|
||||
self.register_hbox.set_no_show_all(False)
|
||||
self.register_hbox.show_all()
|
||||
self.connected_label.hide()
|
||||
self.subscription_table.hide()
|
||||
self.add_button.set_sensitive(False)
|
||||
else:
|
||||
self.register_hbox.hide()
|
||||
if type_ != 'jabber':
|
||||
jid = self.protocol_jid_combobox.get_active_text()
|
||||
contact = gajim.contacts.get_first_contact_from_jid(self.account,
|
||||
jid)
|
||||
if contact.show in ('offline', 'error'):
|
||||
self.subscription_table.hide()
|
||||
self.connected_label.show()
|
||||
self.add_button.set_sensitive(False)
|
||||
return
|
||||
self.subscription_table.set_no_show_all(False)
|
||||
self.subscription_table.show_all()
|
||||
self.connected_label.hide()
|
||||
self.add_button.set_sensitive(True)
|
||||
|
||||
def guess_agent(self):
|
||||
uid = self.uid_entry.get_text().decode('utf-8')
|
||||
model = self.protocol_combobox.get_model()
|
||||
|
||||
#If login contains only numbers, it's probably an ICQ number
|
||||
if uid.isdigit():
|
||||
if 'ICQ' in self.agents:
|
||||
self.protocol_combobox.set_active(self.agents.index('ICQ'))
|
||||
return
|
||||
def transport_signed_in(self, jid):
|
||||
if self.protocol_jid_combobox.get_active_text() == jid:
|
||||
self.register_hbox.hide()
|
||||
self.connected_label.hide()
|
||||
self.subscription_table.set_no_show_all(False)
|
||||
self.subscription_table.show_all()
|
||||
self.add_button.set_sensitive(True)
|
||||
|
||||
def set_nickname(self):
|
||||
uid = self.uid_entry.get_text().decode('utf-8')
|
||||
nickname = self.nickname_entry.get_text().decode('utf-8')
|
||||
if nickname == self.old_uid_value:
|
||||
self.nickname_entry.set_text(uid.split('@')[0])
|
||||
|
||||
def on_uid_entry_changed(self, widget):
|
||||
uid = self.uid_entry.get_text().decode('utf-8')
|
||||
self.guess_agent()
|
||||
self.set_nickname()
|
||||
self.fill_jid()
|
||||
self.old_uid_value = uid.split('@')[0]
|
||||
def transport_signed_out(self, jid):
|
||||
if self.protocol_jid_combobox.get_active_text() == jid:
|
||||
self.subscription_table.hide()
|
||||
self.connected_label.show()
|
||||
self.add_button.set_sensitive(False)
|
||||
|
||||
class AboutDialog:
|
||||
'''Class for about dialog'''
|
||||
def __init__(self):
|
||||
dlg = gtk.AboutDialog()
|
||||
dlg.set_transient_for(gajim.interface.roster.window)
|
||||
dlg.set_name('Gajim')
|
||||
dlg.set_version(gajim.version)
|
||||
s = u'Copyright © 2003-2006 Gajim Team'
|
||||
|
@ -576,7 +704,7 @@ class AboutDialog:
|
|||
% (_('A GTK+ jabber client'), \
|
||||
_('GTK+ Version:'), self.tuple2str(gtk.gtk_version), \
|
||||
_('PyGTK Version:'), self.tuple2str(gtk.pygtk_version)))
|
||||
dlg.set_website('http://www.gajim.org')
|
||||
dlg.set_website('http://www.gajim.org/')
|
||||
|
||||
authors = []
|
||||
authors_file = open('../AUTHORS').read()
|
||||
|
@ -585,7 +713,7 @@ class AboutDialog:
|
|||
if author == 'CURRENT DEVELOPERS:':
|
||||
authors.append(_('Current Developers:'))
|
||||
elif author == 'PAST DEVELOPERS:':
|
||||
authors.append('\n' +_('Past Developers:'))
|
||||
authors.append('\n' + _('Past Developers:'))
|
||||
elif author != '': # Real author line
|
||||
authors.append(author)
|
||||
|
||||
|
@ -735,7 +863,7 @@ class FileChooserDialog(gtk.FileChooserDialog):
|
|||
|
||||
class BindPortError(HigDialog):
|
||||
def __init__(self, port):
|
||||
ErrorDialog(_('Unable to bind to port %s.' % port),
|
||||
ErrorDialog(_('Unable to bind to port %s.') % port,
|
||||
_('Maybe you have another running instance of Gajim. '
|
||||
'File Transfer will be canceled.'))
|
||||
|
||||
|
@ -917,8 +1045,18 @@ class SubscriptionRequestWindow:
|
|||
self.window.destroy()
|
||||
|
||||
class JoinGroupchatWindow:
|
||||
def __init__(self, account, server = '', room = '', nick = ''):
|
||||
def __init__(self, account, server = '', room = '', nick = '',
|
||||
automatic = False):
|
||||
'''automatic is a dict like {'invities': []}
|
||||
If automatic is not empty, this means room must be automaticaly configured
|
||||
and when done, invities must be automatically invited'''
|
||||
if server and room:
|
||||
jid = room + '@' + server
|
||||
if jid in gajim.gc_connected[account] and gajim.gc_connected[account][jid]:
|
||||
ErrorDialog(_('You are already in room %s') % jid)
|
||||
raise RuntimeError, 'You are already in this room'
|
||||
self.account = account
|
||||
self.automatic = automatic
|
||||
if nick == '':
|
||||
nick = gajim.nicks[self.account]
|
||||
if gajim.connections[account].connected < 2:
|
||||
|
@ -1019,10 +1157,12 @@ _('You can not join a group chat unless you are connected.'))
|
|||
|
||||
def on_join_button_clicked(self, widget):
|
||||
'''When Join button is clicked'''
|
||||
nickname = self.xml.get_widget('nickname_entry').get_text().decode('utf-8')
|
||||
nickname = self.xml.get_widget('nickname_entry').get_text().decode(
|
||||
'utf-8')
|
||||
room = self.xml.get_widget('room_entry').get_text().decode('utf-8')
|
||||
server = self.xml.get_widget('server_entry').get_text().decode('utf-8')
|
||||
password = self.xml.get_widget('password_entry').get_text().decode('utf-8')
|
||||
password = self.xml.get_widget('password_entry').get_text().decode(
|
||||
'utf-8')
|
||||
jid = '%s@%s' % (room, server)
|
||||
try:
|
||||
jid = helpers.parse_jid(jid)
|
||||
|
@ -1037,7 +1177,9 @@ _('You can not join a group chat unless you are connected.'))
|
|||
if len(self.recently_groupchat) > 10:
|
||||
self.recently_groupchat = self.recently_groupchat[0:10]
|
||||
gajim.config.set('recently_groupchat', ' '.join(self.recently_groupchat))
|
||||
|
||||
|
||||
if self.automatic:
|
||||
gajim.automatic_rooms[self.account][jid] = self.automatic
|
||||
gajim.interface.roster.join_gc_room(self.account, jid, nickname, password)
|
||||
|
||||
self.window.destroy()
|
||||
|
@ -1076,7 +1218,7 @@ class NewChatDialog(InputDialog):
|
|||
if gajim.connections[self.account].connected <= 1:
|
||||
#if offline or connecting
|
||||
ErrorDialog(_('Connection not available'),
|
||||
_('Please make sure you are connected with "%s".' % self.account))
|
||||
_('Please make sure you are connected with "%s".') % self.account)
|
||||
return
|
||||
|
||||
if self.completion_dict.has_key(jid):
|
||||
|
@ -1088,7 +1230,7 @@ class NewChatDialog(InputDialog):
|
|||
ErrorDialog(_('Invalid JID'), e[0])
|
||||
return
|
||||
except:
|
||||
ErrorDialog(_('Invalid JID'), _('Unable to parse "%s".' % jid))
|
||||
ErrorDialog(_('Invalid JID'), _('Unable to parse "%s".') % jid)
|
||||
return
|
||||
gajim.interface.roster.new_chat_from_jid(self.account, jid)
|
||||
|
||||
|
@ -1284,10 +1426,13 @@ class SingleMessageWindow:
|
|||
|
||||
if gajim.config.get('use_speller') and HAS_GTK_SPELL and action == 'send':
|
||||
try:
|
||||
gtkspell.Spell(self.conversation_textview.tv)
|
||||
gtkspell.Spell(self.message_textview)
|
||||
spell1 = gtkspell.Spell(self.conversation_textview.tv)
|
||||
spell2 = gtkspell.Spell(self.message_textview)
|
||||
lang = gajim.config.get('speller_language')
|
||||
if lang:
|
||||
spell1.set_language(lang)
|
||||
spell2.set_language(lang)
|
||||
except gobject.GError, msg:
|
||||
#FIXME: add a ui for this use spell.set_language()
|
||||
ErrorDialog(unicode(msg), _('If that is not your language for which you want to highlight misspelled words, then please set your $LANG as appropriate. Eg. for French do export LANG=fr_FR or export LANG=fr_FR.UTF-8 in ~/.bash_profile or to make it global in /etc/profile.\n\nHighlighting misspelled words feature will not be used'))
|
||||
gajim.config.set('use_speller', False)
|
||||
|
||||
|
@ -1355,8 +1500,10 @@ class SingleMessageWindow:
|
|||
|
||||
def prepare_widgets_for(self, action):
|
||||
if len(gajim.connections) > 1:
|
||||
#FIXME: for Received with should become 'in'
|
||||
title = _('Single Message with account %s') % self.account
|
||||
if action == 'send':
|
||||
title = _('Single Message using account %s') % self.account
|
||||
else:
|
||||
title = _('Single Message in account %s') % self.account
|
||||
else:
|
||||
title = _('Single Message')
|
||||
|
||||
|
@ -1425,7 +1572,7 @@ class SingleMessageWindow:
|
|||
if gajim.connections[self.account].connected <= 1:
|
||||
# if offline or connecting
|
||||
ErrorDialog(_('Connection not available'),
|
||||
_('Please make sure you are connected with "%s".' % self.account))
|
||||
_('Please make sure you are connected with "%s".') % self.account)
|
||||
return
|
||||
to_whom_jid = self.to_entry.get_text().decode('utf-8')
|
||||
if self.completion_dict.has_key(to_whom_jid):
|
||||
|
@ -1452,7 +1599,7 @@ class SingleMessageWindow:
|
|||
def on_reply_button_clicked(self, widget):
|
||||
# we create a new blank window to send and we preset RE: and to jid
|
||||
self.subject = _('RE: %s') % self.subject
|
||||
self.message = _('%s wrote:\n' % self.from_whom) + self.message
|
||||
self.message = _('%s wrote:\n') % self.from_whom + self.message
|
||||
# add > at the begining of each line
|
||||
self.message = self.message.replace('\n', '\n> ') + '\n\n'
|
||||
self.window.destroy()
|
||||
|
@ -1549,7 +1696,7 @@ class XMLConsoleWindow:
|
|||
if gajim.connections[self.account].connected <= 1:
|
||||
#if offline or connecting
|
||||
ErrorDialog(_('Connection not available'),
|
||||
_('Please make sure you are connected with "%s".' % self.account))
|
||||
_('Please make sure you are connected with "%s".') % self.account)
|
||||
return
|
||||
begin_iter, end_iter = self.input_tv_buffer.get_bounds()
|
||||
stanza = self.input_tv_buffer.get_text(begin_iter, end_iter).decode('utf-8')
|
||||
|
@ -1889,6 +2036,7 @@ class PrivacyListsWindow:
|
|||
'privacy_lists_refresh_button', 'close_privacy_lists_window_button']:
|
||||
self.__dict__[widget_to_add] = self.xml.get_widget(widget_to_add)
|
||||
|
||||
self.draw_privacy_lists_in_combobox()
|
||||
self.privacy_lists_refresh()
|
||||
|
||||
self.enabled = True
|
||||
|
@ -2008,7 +2156,10 @@ class InvitationReceivedDialog:
|
|||
def on_accept_button_clicked(self, widget):
|
||||
self.dialog.destroy()
|
||||
room, server = gajim.get_room_name_and_server_from_room_jid(self.room_jid)
|
||||
JoinGroupchatWindow(self.account, server = server, room = room)
|
||||
try:
|
||||
JoinGroupchatWindow(self.account, server = server, room = room)
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
class ProgressDialog:
|
||||
def __init__(self, title_text, during_text, messages_queue):
|
||||
|
@ -2081,6 +2232,8 @@ class ImageChooserDialog(FileChooserDialog):
|
|||
def on_ok(widget, callback):
|
||||
'''check if file exists and call callback'''
|
||||
path_to_file = self.get_filename()
|
||||
if not path_to_file:
|
||||
return
|
||||
path_to_file = gtkgui_helpers.decode_filechooser_file_paths(
|
||||
(path_to_file,))[0]
|
||||
if os.path.exists(path_to_file):
|
||||
|
@ -2254,8 +2407,6 @@ class AdvancedNotificationsWindow:
|
|||
|
||||
# No rule selected at init time
|
||||
self.conditions_treeview.get_selection().unselect_all()
|
||||
#TODO
|
||||
# self.conditions_treeview.set_cursor(None)
|
||||
self.active_num = -1
|
||||
self.config_vbox.set_sensitive(False)
|
||||
self.delete_button.set_sensitive(False)
|
||||
|
@ -2277,8 +2428,7 @@ class AdvancedNotificationsWindow:
|
|||
if value:
|
||||
self.event_combobox.set_active(self.events_list.index(value))
|
||||
else:
|
||||
#TODO: unselect all
|
||||
pass
|
||||
self.event_combobox.set_active(-1)
|
||||
# recipient_type
|
||||
value = gajim.config.get_per('notifications', str(self.active_num),
|
||||
'recipient_type')
|
||||
|
@ -2286,8 +2436,7 @@ class AdvancedNotificationsWindow:
|
|||
self.recipient_type_combobox.set_active(
|
||||
self.recipient_types_list.index(value))
|
||||
else:
|
||||
#TODO: unselect all
|
||||
pass
|
||||
self.recipient_type_combobox.set_active(-1)
|
||||
# recipient
|
||||
value = gajim.config.get_per('notifications', str(self.active_num),
|
||||
'recipients')
|
||||
|
@ -2457,7 +2606,11 @@ class AdvancedNotificationsWindow:
|
|||
def on_event_combobox_changed(self, widget):
|
||||
if self.active_num < 0:
|
||||
return
|
||||
event = self.events_list[self.event_combobox.get_active()]
|
||||
active = self.event_combobox.get_active()
|
||||
if active == -1:
|
||||
event = ''
|
||||
else:
|
||||
event = self.events_list[active]
|
||||
gajim.config.set_per('notifications', str(self.active_num), 'event',
|
||||
event)
|
||||
self.set_treeview_string()
|
||||
|
|
18
src/disco.py
|
@ -87,7 +87,7 @@ def _gen_agent_type_info():
|
|||
('proxy', 'bytestreams'): (None, 'bytestreams.png'), # Socks5 FT proxy
|
||||
|
||||
# Transports
|
||||
('conference', 'irc'): (False, 'irc.png'),
|
||||
('conference', 'irc'): (ToplevelAgentBrowser, 'irc.png'),
|
||||
('_jid', 'irc'): (False, 'irc.png'),
|
||||
('gateway', 'aim'): (False, 'aim.png'),
|
||||
('_jid', 'aim'): (False, 'aim.png'),
|
||||
|
@ -135,7 +135,8 @@ class CacheDictionary:
|
|||
|
||||
def _expire_timeout(self, key):
|
||||
'''The timeout has expired, remove the object.'''
|
||||
del self.cache[key]
|
||||
if key in self.cache:
|
||||
del self.cache[key]
|
||||
return False
|
||||
|
||||
def _refresh_timeout(self, key):
|
||||
|
@ -274,7 +275,7 @@ class ServicesCache:
|
|||
except KeyError:
|
||||
continue
|
||||
browser = info[0]
|
||||
if browser is not None:
|
||||
if browser:
|
||||
break
|
||||
# Note: possible outcome here is browser=False
|
||||
if browser is None:
|
||||
|
@ -457,7 +458,6 @@ _('Without a connection, you can not browse available services'))
|
|||
self.address_comboboxentry.set_text_column(0)
|
||||
self.latest_addresses = gajim.config.get(
|
||||
'latest_disco_addresses').split()
|
||||
jid = gajim.get_hostname_from_account(self.account)
|
||||
if jid in self.latest_addresses:
|
||||
self.latest_addresses.remove(jid)
|
||||
self.latest_addresses.insert(0, jid)
|
||||
|
@ -1202,7 +1202,10 @@ class ToplevelAgentBrowser(AgentBrowser):
|
|||
else:
|
||||
room = ''
|
||||
if not gajim.interface.instances[self.account].has_key('join_gc'):
|
||||
dialogs.JoinGroupchatWindow(self.account, service, room)
|
||||
try:
|
||||
dialogs.JoinGroupchatWindow(self.account, service, room)
|
||||
except RuntimeError:
|
||||
pass
|
||||
else:
|
||||
gajim.interface.instances[self.account]['join_gc'].window.present()
|
||||
self.window.destroy(chain = True)
|
||||
|
@ -1532,7 +1535,10 @@ class MucBrowser(AgentBrowser):
|
|||
else:
|
||||
room = model[iter][1].decode('utf-8')
|
||||
if not gajim.interface.instances[self.account].has_key('join_gc'):
|
||||
dialogs.JoinGroupchatWindow(self.account, service, room)
|
||||
try:
|
||||
dialogs.JoinGroupchatWindow(self.account, service, room)
|
||||
except RuntimeError:
|
||||
pass
|
||||
else:
|
||||
gajim.interface.instances[self.account]['join_gc'].window.present()
|
||||
self.window.destroy(chain = True)
|
||||
|
|
|
@ -221,7 +221,7 @@ _('Connection with peer cannot be established.'))
|
|||
else:
|
||||
file_name = file_props['name']
|
||||
sectext = '\t' + _('Filename: %s') % file_name
|
||||
sectext += '\n\t' + _('Sender: %s') % jid
|
||||
sectext += '\n\t' + _('Recipient: %s') % jid
|
||||
dialogs.ErrorDialog(_('File transfer stopped by the contact of the other side'), \
|
||||
sectext)
|
||||
self.tree.get_selection().unselect_all()
|
||||
|
@ -328,7 +328,7 @@ _('Connection with peer cannot be established.'))
|
|||
else:
|
||||
dirname = os.path.dirname(file_path)
|
||||
if not os.access(dirname, os.W_OK):
|
||||
dialogs.ErrorDialog(_('Directory "%s" is not writable' % dirname), _('You do not have permission to create files in this directory.'))
|
||||
dialogs.ErrorDialog(_('Directory "%s" is not writable') % dirname, _('You do not have permission to create files in this directory.'))
|
||||
return
|
||||
dialog2.destroy()
|
||||
self._start_receive(file_path, account, contact, file_props)
|
||||
|
@ -445,12 +445,11 @@ _('Connection with peer cannot be established.'))
|
|||
jid = gajim.get_jid_without_resource(other)
|
||||
else: # It's a Contact instance
|
||||
jid = other.jid
|
||||
if gajim.awaiting_events[account].has_key(jid):
|
||||
for event in gajim.awaiting_events[account][jid]:
|
||||
if event[0] in ('file-error', 'file-completed',
|
||||
'file-request-error', 'file-send-error', 'file-stopped') and \
|
||||
event[1]['sid'] == file_props['sid']:
|
||||
gajim.interface.remove_event(account, jid, event)
|
||||
for ev_type in ('file-error', 'file-completed', 'file-request-error',
|
||||
'file-send-error', 'file-stopped'):
|
||||
for event in gajim.events.get_events(account, jid, [ev_type]):
|
||||
if event.parameters[1]['sid'] == file_props['sid']:
|
||||
gajim.events.remove_events(account, jid, event)
|
||||
del(self.files_props[sid[0]][sid[1:]])
|
||||
del(file_props)
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ BASENAME = 'gajim-remote'
|
|||
|
||||
|
||||
class GajimRemote:
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.argv_len = len(sys.argv)
|
||||
# define commands dict. Prototype :
|
||||
|
@ -79,7 +79,7 @@ class GajimRemote:
|
|||
#
|
||||
self.commands = {
|
||||
'help':[
|
||||
_('shows a help on specific command'),
|
||||
_('Shows a help on specific command'),
|
||||
[
|
||||
#User gets help for the command, specified by this parameter
|
||||
(_('command'),
|
||||
|
@ -99,7 +99,7 @@ class GajimRemote:
|
|||
[
|
||||
(_('account'), _('show only contacts of the given account'), False)
|
||||
]
|
||||
|
||||
|
||||
],
|
||||
'list_accounts': [
|
||||
_('Prints a list of registered accounts'),
|
||||
|
@ -201,7 +201,7 @@ class GajimRemote:
|
|||
('jid', _('JID of the contact'), True),
|
||||
(_('account'), _('if specified, contact is taken from the '
|
||||
'contact list of this account'), False)
|
||||
|
||||
|
||||
]
|
||||
],
|
||||
'add_contact': [
|
||||
|
@ -211,14 +211,14 @@ class GajimRemote:
|
|||
(_('account'), _('Adds new contact to this account'), False)
|
||||
]
|
||||
],
|
||||
|
||||
|
||||
'get_status': [
|
||||
_('Returns current status (the global one unless account is specified)'),
|
||||
[
|
||||
(_('account'), _(''), False)
|
||||
]
|
||||
],
|
||||
|
||||
|
||||
'get_status_message': [
|
||||
_('Returns current status message(the global one unless account is specified)'),
|
||||
[
|
||||
|
@ -231,11 +231,20 @@ class GajimRemote:
|
|||
[ ]
|
||||
],
|
||||
'start_chat': [
|
||||
_('Open \'Start Chat\' dialog'),
|
||||
_('Opens \'Start Chat\' dialog'),
|
||||
[
|
||||
(_('account'), _('Starts chat, using this account'), True)
|
||||
]
|
||||
],
|
||||
'send_xml': [
|
||||
_('Sends custom XML'),
|
||||
[
|
||||
('xml', _('XML to send'), True),
|
||||
('account', _('Account in which the xml will be sent; '
|
||||
'if not specified, xml will be sent to all accounts'),
|
||||
False)
|
||||
]
|
||||
],
|
||||
}
|
||||
if self.argv_len < 2 or \
|
||||
sys.argv[1] not in self.commands.keys(): # no args or bad args
|
||||
|
@ -247,14 +256,14 @@ class GajimRemote:
|
|||
else:
|
||||
print self.compose_help().encode(PREFERRED_ENCODING)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
self.init_connection()
|
||||
self.check_arguments()
|
||||
|
||||
|
||||
if self.command == 'contact_info':
|
||||
if self.argv_len < 3:
|
||||
send_error(_('Missing argument "contact_jid"'))
|
||||
|
||||
|
||||
try:
|
||||
res = self.call_remote_method()
|
||||
except exceptions.ServiceNotAvailable:
|
||||
|
@ -262,14 +271,14 @@ class GajimRemote:
|
|||
sys.exit(1)
|
||||
else:
|
||||
self.print_result(res)
|
||||
|
||||
|
||||
def print_result(self, res):
|
||||
''' Print retrieved result to the output '''
|
||||
if res is not None:
|
||||
if self.command in ('open_chat', 'send_message', 'send_single_message', 'start_chat'):
|
||||
if self.command in ('send_message', 'send_single_message'):
|
||||
self.argv_len -= 2
|
||||
|
||||
|
||||
if res is False:
|
||||
if self.argv_len < 4:
|
||||
send_error(_('\'%s\' is not in your roster.\n'
|
||||
|
@ -302,7 +311,7 @@ class GajimRemote:
|
|||
print self.print_info(0, res, True)
|
||||
elif res:
|
||||
print unicode(res).encode(PREFERRED_ENCODING)
|
||||
|
||||
|
||||
def init_connection(self):
|
||||
''' create the onnection to the session dbus,
|
||||
or exit if it is not possible '''
|
||||
|
@ -310,7 +319,7 @@ class GajimRemote:
|
|||
self.sbus = dbus.SessionBus()
|
||||
except:
|
||||
raise exceptions.SessionBusNotPresent
|
||||
|
||||
|
||||
if _version[1] >= 30:
|
||||
obj = self.sbus.get_object(SERVICE, OBJ_PATH)
|
||||
interface = dbus.Interface(obj, INTERFACE)
|
||||
|
@ -319,10 +328,10 @@ class GajimRemote:
|
|||
interface = self.service.get_object(OBJ_PATH, INTERFACE)
|
||||
else:
|
||||
send_error(_('Unknown D-Bus version: %s') % _version[1])
|
||||
|
||||
|
||||
# get the function asked
|
||||
self.method = interface.__getattr__(self.command)
|
||||
|
||||
|
||||
def make_arguments_row(self, args):
|
||||
''' return arguments list. Mandatory arguments are enclosed with:
|
||||
'<', '>', optional arguments - with '[', ']' '''
|
||||
|
@ -339,7 +348,7 @@ class GajimRemote:
|
|||
else:
|
||||
str += ']'
|
||||
return str
|
||||
|
||||
|
||||
def help_on_command(self, command):
|
||||
''' return help message for a given command '''
|
||||
if command in self.commands:
|
||||
|
@ -353,7 +362,7 @@ class GajimRemote:
|
|||
str += ' ' + argument[0] + ' - ' + argument[1] + '\n'
|
||||
return str
|
||||
send_error(_('%s not found') % command)
|
||||
|
||||
|
||||
def compose_help(self):
|
||||
''' print usage, and list available commands '''
|
||||
str = _('Usage: %s command [arguments]\nCommand is one of:\n' ) % BASENAME
|
||||
|
@ -374,7 +383,7 @@ class GajimRemote:
|
|||
str += ']'
|
||||
str += '\n'
|
||||
return str
|
||||
|
||||
|
||||
def print_info(self, level, prop_dict, encode_return = False):
|
||||
''' return formated string from data structure '''
|
||||
if prop_dict is None or not isinstance(prop_dict, (dict, list, tuple)):
|
||||
|
@ -423,7 +432,7 @@ class GajimRemote:
|
|||
except:
|
||||
pass
|
||||
return ret_str
|
||||
|
||||
|
||||
def check_arguments(self):
|
||||
''' Make check if all necessary arguments are given '''
|
||||
argv_len = self.argv_len - 2
|
||||
|
@ -433,7 +442,7 @@ class GajimRemote:
|
|||
send_error(_('Argument "%s" is not specified. \n'
|
||||
'Type "%s help %s" for more info') %
|
||||
(args[argv_len][0], BASENAME, self.command))
|
||||
|
||||
|
||||
def call_remote_method(self):
|
||||
''' calls self.method with arguments from sys.argv[2:] '''
|
||||
args = sys.argv[2:]
|
||||
|
|
278
src/gajim.py
|
@ -42,6 +42,14 @@ from atom_window import AtomWindow
|
|||
|
||||
from common import exceptions
|
||||
|
||||
if os.name == 'posix': # dl module is Unix Only
|
||||
try: # rename the process name to gajim
|
||||
import dl
|
||||
libc = dl.open('/lib/libc.so.6')
|
||||
libc.call('prctl', 15, 'gajim\0', 0, 0, 0)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
import gtk
|
||||
except RuntimeError, msg:
|
||||
|
@ -71,6 +79,15 @@ except exceptions.PysqliteNotAvailable, e:
|
|||
pritext = _('Gajim needs PySQLite2 to run')
|
||||
sectext = str(e)
|
||||
|
||||
if os.name == 'nt':
|
||||
try:
|
||||
import winsound # windows-only built-in module for playing wav
|
||||
import win32api
|
||||
import win32con
|
||||
except:
|
||||
pritext = _('Gajim needs pywin32 to run')
|
||||
sectext = _('Please make sure that Pywin32 is installed on your system. You can get it at %s') % 'http://sourceforge.net/project/showfiles.php?group_id=78018'
|
||||
|
||||
if pritext:
|
||||
dlg = gtk.MessageDialog(None,
|
||||
gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
|
||||
|
@ -178,23 +195,9 @@ parser = optparser.OptionsParser(config_filename)
|
|||
|
||||
import roster_window
|
||||
import systray
|
||||
import vcard
|
||||
import profile_window
|
||||
import config
|
||||
|
||||
class MigrateCommand(nslookup.IdleCommand):
|
||||
def __init__(self, on_result):
|
||||
nslookup.IdleCommand.__init__(self, on_result)
|
||||
self.commandtimeout = 10
|
||||
|
||||
def _compose_command_args(self):
|
||||
return ['python', 'migrate_logs_to_dot9_db.py', 'dont_wait']
|
||||
|
||||
def _return_result(self):
|
||||
print self.result
|
||||
if self.result_handler:
|
||||
self.result_handler(self.result)
|
||||
self.result_handler = None
|
||||
|
||||
class GlibIdleQueue(idlequeue.IdleQueue):
|
||||
'''
|
||||
Extends IdleQueue to use glib io_add_wath, instead of select/poll
|
||||
|
@ -307,6 +310,14 @@ class Interface:
|
|||
gajim.con_types[account] = con_type
|
||||
self.roster.draw_account(account)
|
||||
|
||||
def handle_event_connection_lost(self, account, array):
|
||||
# ('CONNECTION_LOST', account, [title, text])
|
||||
path = os.path.join(gajim.DATA_DIR, 'pixmaps', 'events',
|
||||
'connection_lost.png')
|
||||
path = gtkgui_helpers.get_path_to_generic_or_avatar(path)
|
||||
notify.popup(_('Connection Failed'), account, account,
|
||||
'connection_failed', path, array[0], array[1])
|
||||
|
||||
def unblock_signed_in_notifications(self, account):
|
||||
gajim.block_signed_in_notifications[account] = False
|
||||
|
||||
|
@ -346,9 +357,9 @@ class Interface:
|
|||
|
||||
def edit_own_details(self, account):
|
||||
jid = gajim.get_jid_from_account(account)
|
||||
if not self.instances[account]['infos'].has_key(jid):
|
||||
self.instances[account]['infos'][jid] = \
|
||||
vcard.VcardWindow(jid, account, True)
|
||||
if not self.instances[account].has_key('profile'):
|
||||
self.instances[account]['profile'] = \
|
||||
profile_window.ProfileWindow(account)
|
||||
gajim.connections[account].request_vcard(jid)
|
||||
|
||||
def handle_event_notify(self, account, array):
|
||||
|
@ -396,7 +407,9 @@ class Interface:
|
|||
else:
|
||||
contact1 = gajim.contacts.get_first_contact_from_jid(account, ji)
|
||||
if not contact1:
|
||||
# presence of another resource of out jid
|
||||
# presence of another resource of our jid
|
||||
if resource == gajim.connections[account].server_resource:
|
||||
return
|
||||
contact1 = gajim.contacts.create_contact(jid = ji,
|
||||
name = gajim.nicks[account], groups = [],
|
||||
show = array[1], status = status_message, sub = 'both',
|
||||
|
@ -452,6 +465,15 @@ class Interface:
|
|||
gajim.block_signed_in_notifications[account_ji] = True
|
||||
gobject.timeout_add(30000, self.unblock_signed_in_notifications,
|
||||
account_ji)
|
||||
locations = (self.instances, self.instances[account])
|
||||
for location in locations:
|
||||
if location.has_key('add_contact'):
|
||||
if old_show == 0 and new_show > 1:
|
||||
location['add_contact'].transport_signed_in(jid)
|
||||
break
|
||||
elif old_show > 1 and new_show == 0:
|
||||
location['add_contact'].transport_signed_out(jid)
|
||||
break
|
||||
elif ji in jid_list:
|
||||
# It isn't an agent
|
||||
# reset chatstate if needed:
|
||||
|
@ -495,6 +517,7 @@ class Interface:
|
|||
|
||||
message = array[1]
|
||||
msg_type = array[4]
|
||||
subject = array[5]
|
||||
chatstate = array[6]
|
||||
msg_id = array[7]
|
||||
composing_jep = array[8]
|
||||
|
@ -560,10 +583,13 @@ class Interface:
|
|||
not gajim.contacts.get_contact(account, jid) and not pm:
|
||||
return
|
||||
|
||||
advanced_notif_num = notify.get_advanced_notification('message_received',
|
||||
account, contact)
|
||||
|
||||
# Is it a first or next message received ?
|
||||
first = False
|
||||
if not chat_control and not gajim.awaiting_events[account].has_key(
|
||||
jid_of_control):
|
||||
if not chat_control and not gajim.events.get_events(account,
|
||||
jid_of_control, ['chat']):
|
||||
# It's a first message and not a Private Message
|
||||
first = True
|
||||
|
||||
|
@ -574,11 +600,14 @@ class Interface:
|
|||
else:
|
||||
# array: (jid, msg, time, encrypted, msg_type, subject)
|
||||
self.roster.on_message(jid, message, array[2], account, array[3],
|
||||
msg_type, array[5], resource, msg_id, array[9])
|
||||
msg_type, subject, resource, msg_id, array[9], advanced_notif_num)
|
||||
nickname = gajim.get_name_from_jid(account, jid)
|
||||
# Check and do wanted notifications
|
||||
msg = message
|
||||
if subject:
|
||||
msg = _('Subject: %s') % subject + '\n' + msg
|
||||
notify.notify('new_message', jid, account, [msg_type, first, nickname,
|
||||
message])
|
||||
msg], advanced_notif_num)
|
||||
|
||||
if self.remote_ctrl:
|
||||
self.remote_ctrl.raise_signal('NewMessage', (account, array))
|
||||
|
@ -712,8 +741,8 @@ class Interface:
|
|||
config.ServiceRegistrationWindow(array[0], array[1], account,
|
||||
array[2])
|
||||
else:
|
||||
dialogs.ErrorDialog(_('Contact with "%s" cannot be established'\
|
||||
% array[0]), _('Check your connection or try again later.'))
|
||||
dialogs.ErrorDialog(_('Contact with "%s" cannot be established')\
|
||||
% array[0], _('Check your connection or try again later.'))
|
||||
|
||||
def handle_event_agent_info_items(self, account, array):
|
||||
#('AGENT_INFO_ITEMS', account, (agent, node, items))
|
||||
|
@ -753,8 +782,8 @@ class Interface:
|
|||
nick = array['NICKNAME']
|
||||
if nick:
|
||||
gajim.nicks[account] = nick
|
||||
if self.instances[account]['infos'].has_key(array['jid']):
|
||||
win = self.instances[account]['infos'][array['jid']]
|
||||
if self.instances[account].has_key('profile'):
|
||||
win = self.instances[account]['profile']
|
||||
win.set_values(array)
|
||||
if account in self.show_vcard_when_connect:
|
||||
self.show_vcard_when_connect.remove(account)
|
||||
|
@ -859,7 +888,6 @@ class Interface:
|
|||
uf_show = helpers.get_uf_show(show)
|
||||
ctrl.print_conversation(_('%s is now %s (%s)') % (nick, uf_show, status),
|
||||
'status')
|
||||
ctrl.draw_banner()
|
||||
ctrl.parent_win.redraw_tab(ctrl)
|
||||
if self.remote_ctrl:
|
||||
self.remote_ctrl.raise_signal('GCPresence', (account, array))
|
||||
|
@ -899,10 +927,18 @@ class Interface:
|
|||
|
||||
def handle_event_gc_config(self, account, array):
|
||||
#('GC_CONFIG', account, (jid, config)) config is a dict
|
||||
jid = array[0].split('/')[0]
|
||||
if not self.instances[account]['gc_config'].has_key(jid):
|
||||
self.instances[account]['gc_config'][jid] = \
|
||||
config.GroupchatConfigWindow(account, jid, array[1])
|
||||
room_jid = array[0].split('/')[0]
|
||||
if room_jid in gajim.automatic_rooms[account]:
|
||||
# use default configuration
|
||||
gajim.connections[account].send_gc_config(room_jid, array[1])
|
||||
# invite contacts
|
||||
if gajim.automatic_rooms[account][room_jid].has_key('invities'):
|
||||
for jid in gajim.automatic_rooms[account][room_jid]['invities']:
|
||||
gajim.connections[account].send_invite(room_jid, jid)
|
||||
del gajim.automatic_rooms[account][room_jid]
|
||||
elif not self.instances[account]['gc_config'].has_key(room_jid):
|
||||
self.instances[account]['gc_config'][room_jid] = \
|
||||
config.GroupchatConfigWindow(account, room_jid, array[1])
|
||||
|
||||
def handle_event_gc_affiliation(self, account, array):
|
||||
#('GC_AFFILIATION', account, (room_jid, affiliation, list)) list is list
|
||||
|
@ -923,8 +959,7 @@ class Interface:
|
|||
self.add_event(account, jid, 'gc-invitation', (room_jid, array[2],
|
||||
array[3]))
|
||||
|
||||
if gajim.config.get('notify_on_new_message') and \
|
||||
helpers.allow_showing_notification(account):
|
||||
if helpers.allow_showing_notification(account, 'notify_on_new_message'):
|
||||
path = os.path.join(gajim.DATA_DIR, 'pixmaps', 'events',
|
||||
'gc_invitation.png')
|
||||
path = gtkgui_helpers.get_path_to_generic_or_avatar(path)
|
||||
|
@ -956,7 +991,7 @@ class Interface:
|
|||
c = contacts[0]
|
||||
self.roster.remove_contact(c, account)
|
||||
gajim.contacts.remove_jid(account, jid)
|
||||
if gajim.awaiting_events[account].has_key(c.jid):
|
||||
if gajim.events.get_events(account, c.jid):
|
||||
keyID = ''
|
||||
attached_keys = gajim.config.get_per('accounts', account,
|
||||
'attached_gpg_keys').split()
|
||||
|
@ -1091,60 +1126,48 @@ class Interface:
|
|||
path_to_bw_file = path_to_file + '_notif_size_bw.png'
|
||||
bwbuf.save(path_to_bw_file, 'png')
|
||||
|
||||
def add_event(self, account, jid, typ, args):
|
||||
'''add an event to the awaiting_events var'''
|
||||
# We add it to the awaiting_events queue
|
||||
def add_event(self, account, jid, type_, args):
|
||||
'''add an event to the gajim.events var'''
|
||||
# We add it to the gajim.events queue
|
||||
# Do we have a queue?
|
||||
jid = gajim.get_jid_without_resource(jid)
|
||||
qs = gajim.awaiting_events[account]
|
||||
no_queue = False
|
||||
if not qs.has_key(jid):
|
||||
no_queue = True
|
||||
qs[jid] = []
|
||||
qs[jid].append((typ, args))
|
||||
self.roster.nb_unread += 1
|
||||
no_queue = len(gajim.events.get_events(account, jid)) == 0
|
||||
event_type = None
|
||||
# type_ can be gc-invitation file-send-error file-error file-request-error
|
||||
# file-request file-completed file-stopped
|
||||
# event_type can be in advancedNotificationWindow.events_list
|
||||
event_types = {'file-request': 'ft_request',
|
||||
'file-completed': 'ft_finished'}
|
||||
if type_ in event_types:
|
||||
event_type = event_types[type_]
|
||||
show_in_roster = notify.get_show_in_roster(event_type, account, jid)
|
||||
show_in_systray = notify.get_show_in_systray(event_type, account, jid)
|
||||
event = gajim.events.create_event(type_, args,
|
||||
show_in_roster = show_in_roster,
|
||||
show_in_systray = show_in_systray)
|
||||
gajim.events.add_event(account, jid, event)
|
||||
|
||||
self.roster.show_title()
|
||||
if no_queue: # We didn't have a queue: we change icons
|
||||
self.roster.draw_contact(jid, account)
|
||||
if self.systray_enabled:
|
||||
self.systray.add_jid(jid, account, typ)
|
||||
|
||||
def redraw_roster_systray(self, account, jid, typ = None):
|
||||
self.roster.nb_unread -= 1
|
||||
self.roster.show_title()
|
||||
self.roster.draw_contact(jid, account)
|
||||
if self.systray_enabled:
|
||||
self.systray.remove_jid(jid, account, typ)
|
||||
def remove_first_event(self, account, jid, type_ = None):
|
||||
event = gajim.events.get_first_event(account, jid, type_)
|
||||
self.remove_event(account, jid, event)
|
||||
|
||||
def remove_first_event(self, account, jid, typ = None):
|
||||
qs = gajim.awaiting_events[account]
|
||||
event = gajim.get_first_event(account, jid, typ)
|
||||
qs[jid].remove(event)
|
||||
# Is it the last event?
|
||||
if not len(qs[jid]):
|
||||
del qs[jid]
|
||||
def remove_event(self, account, jid, event):
|
||||
if gajim.events.remove_events(account, jid, event):
|
||||
# No such event found
|
||||
return
|
||||
# no other event?
|
||||
if not len(gajim.events.get_events(account, jid)):
|
||||
if not gajim.config.get('showoffline'):
|
||||
contact = gajim.contacts.get_contact_with_highest_priority(account,
|
||||
jid)
|
||||
if contact:
|
||||
self.roster.really_remove_contact(contact, account)
|
||||
self.redraw_roster_systray(account, jid, typ)
|
||||
|
||||
def remove_event(self, account, jid, event):
|
||||
qs = gajim.awaiting_events[account]
|
||||
if not event in qs[jid]:
|
||||
return
|
||||
qs[jid].remove(event)
|
||||
# Is it the last event?
|
||||
if not len(qs[jid]):
|
||||
del qs[jid]
|
||||
if not gajim.config.get('showoffline'):
|
||||
contact = gajim.contacts.get_contact_with_highest_priority(account,
|
||||
jid)
|
||||
if contact:
|
||||
self.roster.really_remove_contact(contact, account)
|
||||
self.redraw_roster_systray(account, jid, event[0])
|
||||
self.roster.show_title()
|
||||
self.roster.draw_contact(jid, account)
|
||||
|
||||
def handle_event_file_request_error(self, account, array):
|
||||
jid = array[0]
|
||||
|
@ -1170,7 +1193,7 @@ class Interface:
|
|||
if helpers.allow_showing_notification(account):
|
||||
# check if we should be notified
|
||||
img = os.path.join(gajim.DATA_DIR, 'pixmaps', 'events', 'ft_error.png')
|
||||
|
||||
|
||||
path = gtkgui_helpers.get_path_to_generic_or_avatar(img)
|
||||
event_type = _('File Transfer Error')
|
||||
notify.popup(event_type, jid, account, msg_type, path,
|
||||
|
@ -1193,7 +1216,8 @@ class Interface:
|
|||
if helpers.allow_showing_notification(account):
|
||||
img = os.path.join(gajim.DATA_DIR, 'pixmaps', 'events',
|
||||
'ft_request.png')
|
||||
txt = _('%s wants to send you a file.') % gajim.get_name_from_jid(account, jid)
|
||||
txt = _('%s wants to send you a file.') % gajim.get_name_from_jid(
|
||||
account, jid)
|
||||
path = gtkgui_helpers.get_path_to_generic_or_avatar(img)
|
||||
event_type = _('File Transfer Request')
|
||||
notify.popup(event_type, jid, account, 'file-request',
|
||||
|
@ -1202,7 +1226,7 @@ class Interface:
|
|||
def handle_event_file_progress(self, account, file_props):
|
||||
self.instances['file_transfers'].set_progress(file_props['type'],
|
||||
file_props['sid'], file_props['received-len'])
|
||||
|
||||
|
||||
def handle_event_file_rcv_completed(self, account, file_props):
|
||||
ft = self.instances['file_transfers']
|
||||
if file_props['error'] == 0:
|
||||
|
@ -1228,13 +1252,14 @@ class Interface:
|
|||
|
||||
msg_type = ''
|
||||
event_type = ''
|
||||
if file_props['error'] == 0 and gajim.config.get('notify_on_file_complete'):
|
||||
if file_props['error'] == 0 and gajim.config.get(
|
||||
'notify_on_file_complete'):
|
||||
msg_type = 'file-completed'
|
||||
event_type = _('File Transfer Completed')
|
||||
elif file_props['error'] == -1:
|
||||
msg_type = 'file-stopped'
|
||||
event_type = _('File Transfer Stopped')
|
||||
|
||||
|
||||
if event_type == '':
|
||||
# FIXME: ugly workaround (this can happen Gajim sent, Gaim recvs)
|
||||
# this should never happen but it does. see process_result() in socks5.py
|
||||
|
@ -1244,7 +1269,7 @@ class Interface:
|
|||
|
||||
if msg_type:
|
||||
self.add_event(account, jid, msg_type, file_props)
|
||||
|
||||
|
||||
if file_props is not None:
|
||||
if file_props['type'] == 'r':
|
||||
# get the name of the sender, as it is in the roster
|
||||
|
@ -1429,12 +1454,12 @@ class Interface:
|
|||
return False
|
||||
|
||||
def show_systray(self):
|
||||
self.systray.show_icon()
|
||||
self.systray_enabled = True
|
||||
self.systray.show_icon()
|
||||
|
||||
def hide_systray(self):
|
||||
self.systray.hide_icon()
|
||||
self.systray_enabled = False
|
||||
self.systray.hide_icon()
|
||||
|
||||
def image_is_ok(self, image):
|
||||
if not os.path.exists(image):
|
||||
|
@ -1664,6 +1689,7 @@ class Interface:
|
|||
'ROSTER_INFO': self.handle_event_roster_info,
|
||||
'BOOKMARKS': self.handle_event_bookmarks,
|
||||
'CON_TYPE': self.handle_event_con_type,
|
||||
'CONNECTION_LOST': self.handle_event_connection_lost,
|
||||
'FILE_REQUEST': self.handle_event_file_request,
|
||||
'GMAIL_NOTIFY': self.handle_event_gmail_notify,
|
||||
'FILE_REQUEST_ERROR': self.handle_event_file_request_error,
|
||||
|
@ -1700,14 +1726,14 @@ class Interface:
|
|||
err_str)
|
||||
sys.exit()
|
||||
|
||||
def handle_event(self, account, jid, typ):
|
||||
def handle_event(self, account, jid, type_):
|
||||
w = None
|
||||
fjid = jid
|
||||
resource = gajim.get_resource_from_jid(jid)
|
||||
jid = gajim.get_jid_without_resource(jid)
|
||||
if typ == message_control.TYPE_GC:
|
||||
if type_ in ('printed_gc_msg', 'gc_msg'):
|
||||
w = self.msg_win_mgr.get_window(jid, account)
|
||||
elif typ == message_control.TYPE_CHAT:
|
||||
elif type_ in ('printed_chat', 'chat'):
|
||||
if self.msg_win_mgr.has_window(fjid, account):
|
||||
w = self.msg_win_mgr.get_window(fjid, account)
|
||||
else:
|
||||
|
@ -1717,30 +1743,30 @@ class Interface:
|
|||
self.roster.new_chat(contact, account, resource = resource)
|
||||
w = self.msg_win_mgr.get_window(fjid, account)
|
||||
gajim.last_message_time[account][jid] = 0 # long time ago
|
||||
elif typ == message_control.TYPE_PM:
|
||||
elif type_ in ('printed_pm', 'pm'):
|
||||
if self.msg_win_mgr.has_window(fjid, account):
|
||||
w = self.msg_win_mgr.get_window(fjid, account)
|
||||
else:
|
||||
room_jid = jid
|
||||
nick = resource
|
||||
gc_contact = gajim.contacts.get_gc_contact(account, room_jid,
|
||||
nick)
|
||||
nick)
|
||||
if gc_contact:
|
||||
show = gc_contact.show
|
||||
else:
|
||||
show = 'offline'
|
||||
gc_contact = gajim.contacts.create_gc_contact(room_jid = room_jid,
|
||||
name = nick, show = show)
|
||||
gc_contact = gajim.contacts.create_gc_contact(
|
||||
room_jid = room_jid, name = nick, show = show)
|
||||
c = gajim.contacts.contact_from_gc_contact(gc_contact)
|
||||
self.roster.new_chat(c, account, private_chat = True)
|
||||
w = self.msg_win_mgr.get_window(fjid, account)
|
||||
elif typ in ('normal', 'file-request', 'file-request-error',
|
||||
'file-send-error', 'file-error', 'file-stopped', 'file-completed'):
|
||||
elif type_ in ('normal', 'file-request', 'file-request-error',
|
||||
'file-send-error', 'file-error', 'file-stopped', 'file-completed'):
|
||||
# Get the first single message event
|
||||
ev = gajim.get_first_event(account, jid, typ)
|
||||
event = gajim.events.get_first_event(account, jid, type_)
|
||||
# Open the window
|
||||
self.roster.open_event(account, jid, ev)
|
||||
elif typ == 'gmail':
|
||||
self.roster.open_event(account, jid, event)
|
||||
elif type_ == 'gmail':
|
||||
if gajim.config.get_per('accounts', account, 'savepass'):
|
||||
url = ('http://www.google.com/accounts/ServiceLoginAuth?service=mail&Email=%s&Passwd=%s&continue=https://mail.google.com/mail') %\
|
||||
(urllib.quote(gajim.config.get_per('accounts', account, 'name')),
|
||||
|
@ -1748,12 +1774,12 @@ class Interface:
|
|||
else:
|
||||
url = ('http://mail.google.com/')
|
||||
helpers.launch_browser_mailer('url', url)
|
||||
elif typ == 'gc-invitation':
|
||||
ev = gajim.get_first_event(account, jid, typ)
|
||||
data = ev[1]
|
||||
elif type_ == 'gc-invitation':
|
||||
event = gajim.events.get_first_event(account, jid, type_)
|
||||
data = event.parameters
|
||||
dialogs.InvitationReceivedDialog(account, data[0], jid, data[2],
|
||||
data[1])
|
||||
self.remove_first_event(account, jid, typ)
|
||||
gajim.events.remove_events(account, jid, event)
|
||||
if w:
|
||||
w.set_active_tab(fjid, account)
|
||||
w.window.present()
|
||||
|
@ -1840,14 +1866,13 @@ class Interface:
|
|||
self.instances = {'logs': {}}
|
||||
|
||||
for a in gajim.connections:
|
||||
self.instances[a] = {'infos': {}, 'disco': {}, 'chats': {},
|
||||
'gc': {}, 'gc_config': {}}
|
||||
self.instances[a] = {'infos': {}, 'disco': {}, 'gc_config': {}}
|
||||
gajim.contacts.add_account(a)
|
||||
gajim.groups[a] = {}
|
||||
gajim.gc_connected[a] = {}
|
||||
gajim.automatic_rooms[a] = {}
|
||||
gajim.newly_added[a] = []
|
||||
gajim.to_be_removed[a] = []
|
||||
gajim.awaiting_events[a] = {}
|
||||
gajim.nicks[a] = gajim.config.get_per('accounts', a, 'name')
|
||||
gajim.block_signed_in_notifications[a] = True
|
||||
gajim.sleeper_state[a] = 0
|
||||
|
@ -1901,6 +1926,25 @@ class Interface:
|
|||
# get instances for windows/dialogs that will show_all()/hide()
|
||||
self.instances['file_transfers'] = dialogs.FileTransfersWindow()
|
||||
|
||||
# get transports type from DB
|
||||
gajim.transport_type = gajim.logger.get_transports_type()
|
||||
|
||||
# test is dictionnary is present for speller
|
||||
if gajim.config.get('use_speller'):
|
||||
lang = gajim.config.get('speller_language')
|
||||
if not lang:
|
||||
lang = gajim.LANG
|
||||
tv = gtk.TextView()
|
||||
try:
|
||||
import gtkspell
|
||||
spell = gtkspell.Spell(tv, lang)
|
||||
except:
|
||||
dialogs.ErrorDialog(
|
||||
_('Dictionary for lang %s not available') % lang,
|
||||
_('You have to install %s dictionary to use spellchecking, or '
|
||||
'choose another language by setting the speller_language option.'
|
||||
) % lang)
|
||||
gajim.config.set('use_speller', False)
|
||||
gobject.timeout_add(100, self.autoconnect)
|
||||
gobject.timeout_add(200, self.process_connections)
|
||||
gobject.timeout_add(500, self.read_sleepy)
|
||||
|
@ -1938,30 +1982,6 @@ if __name__ == '__main__':
|
|||
|
||||
gtkgui_helpers.possibly_set_gajim_as_xmpp_handler()
|
||||
|
||||
# Migrate old logs if we have such olds logs
|
||||
from common import logger
|
||||
from migrate_logs_to_dot9_db import PATH_TO_LOGS_BASE_DIR
|
||||
LOG_DB_PATH = logger.LOG_DB_PATH
|
||||
if not os.path.exists(LOG_DB_PATH) and os.path.isdir(PATH_TO_LOGS_BASE_DIR):
|
||||
import Queue
|
||||
q = Queue.Queue(100)
|
||||
dialog = dialogs.ProgressDialog(_('Migrating Logs...'),
|
||||
_('Please wait while logs are being migrated...'), q)
|
||||
if os.name == 'nt' and gtk.pygtk_version > (2, 8, 0):
|
||||
idlequeue = idlequeue.SelectIdleQueue()
|
||||
else:
|
||||
idlequeue = GlibIdleQueue()
|
||||
def on_result(*arg):
|
||||
dialog.dialog.destroy()
|
||||
dialog.dialog = None
|
||||
gobject.source_remove(dialog.update_progressbar_timeout_id)
|
||||
gajim.logger.init_vars()
|
||||
check_paths.check_and_possibly_create_paths()
|
||||
Interface()
|
||||
m = MigrateCommand(on_result)
|
||||
m.set_idlequeue(idlequeue)
|
||||
m.start()
|
||||
else:
|
||||
check_paths.check_and_possibly_create_paths()
|
||||
Interface()
|
||||
check_paths.check_and_possibly_create_paths()
|
||||
Interface()
|
||||
gtk.main()
|
||||
|
|
|
@ -36,6 +36,7 @@ class GajimThemesWindow:
|
|||
def __init__(self):
|
||||
self.xml = gtkgui_helpers.get_glade('gajim_themes_window.glade')
|
||||
self.window = self.xml.get_widget('gajim_themes_window')
|
||||
self.window.set_transient_for(gajim.interface.roster.window)
|
||||
|
||||
self.options = ['account', 'group', 'contact', 'banner']
|
||||
self.options_combobox = self.xml.get_widget('options_combobox')
|
||||
|
|
|
@ -119,6 +119,13 @@ class PrivateChatControl(ChatControl):
|
|||
return
|
||||
|
||||
ChatControl.send_message(self, message)
|
||||
|
||||
def update_ui(self):
|
||||
if self.contact.show == 'offline':
|
||||
self.got_disconnected()
|
||||
else:
|
||||
self.got_connected()
|
||||
ChatControl.update_ui(self)
|
||||
|
||||
|
||||
class GroupchatControl(ChatControlBase):
|
||||
|
@ -189,10 +196,6 @@ class GroupchatControl(ChatControlBase):
|
|||
|
||||
self.tooltip = tooltips.GCTooltip()
|
||||
|
||||
self.allow_focus_out_line = True
|
||||
# holds the iter's offset which points to the end of --- line
|
||||
self.focus_out_end_iter_offset = None
|
||||
|
||||
# connect the menuitems to their respective functions
|
||||
xm = gtkgui_helpers.get_glade('gc_control_popup_menu.glade')
|
||||
|
||||
|
@ -284,12 +287,9 @@ class GroupchatControl(ChatControlBase):
|
|||
column.set_visible(False)
|
||||
self.list_treeview.set_expander_column(column)
|
||||
|
||||
id = self.msg_textview.connect('populate_popup',
|
||||
self.on_msg_textview_populate_popup)
|
||||
self.handlers[id] = self.msg_textview
|
||||
# set an empty subject to show the room_jid
|
||||
self.set_subject('')
|
||||
self.got_disconnected() #init some variables
|
||||
self.got_disconnected() # init some variables
|
||||
|
||||
self.update_ui()
|
||||
self.conv_textview.tv.grab_focus()
|
||||
|
@ -298,20 +298,18 @@ class GroupchatControl(ChatControlBase):
|
|||
def on_msg_textview_populate_popup(self, textview, menu):
|
||||
'''we override the default context menu and we prepend Clear
|
||||
and the ability to insert a nick'''
|
||||
ChatControlBase.on_msg_textview_populate_popup(self, textview, menu)
|
||||
item = gtk.SeparatorMenuItem()
|
||||
menu.prepend(item)
|
||||
item = gtk.ImageMenuItem(gtk.STOCK_CLEAR)
|
||||
menu.prepend(item)
|
||||
id = item.connect('activate', self.msg_textview.clear)
|
||||
self.handlers[id] = item
|
||||
|
||||
item = gtk.MenuItem(_('Insert Nickname'))
|
||||
menu.prepend(item)
|
||||
submenu = gtk.Menu()
|
||||
item.set_submenu(submenu)
|
||||
|
||||
for nick in gajim.contacts.get_nick_list(self.account, self.room_jid):
|
||||
item = gtk.MenuItem(nick)
|
||||
for nick in sorted(gajim.contacts.get_nick_list(self.account,
|
||||
self.room_jid)):
|
||||
item = gtk.MenuItem(nick, use_underline = False)
|
||||
submenu.append(item)
|
||||
id = item.connect('activate', self.append_nick_in_msg_textview, nick)
|
||||
self.handlers[id] = item
|
||||
|
@ -325,7 +323,7 @@ class GroupchatControl(ChatControlBase):
|
|||
def _on_window_focus_in_event(self, widget, event):
|
||||
'''When window gets focus'''
|
||||
if self.parent_win.get_active_jid() == self.room_jid:
|
||||
self.allow_focus_out_line = True
|
||||
self.conv_textview.allow_focus_out_line = True
|
||||
|
||||
def on_treeview_size_allocate(self, widget, allocation):
|
||||
'''The MUC treeview has resized. Move the hpaned in all tabs to match'''
|
||||
|
@ -443,10 +441,7 @@ class GroupchatControl(ChatControlBase):
|
|||
def on_private_message(self, nick, msg, tim):
|
||||
# Do we have a queue?
|
||||
fjid = self.room_jid + '/' + nick
|
||||
qs = gajim.awaiting_events[self.account]
|
||||
no_queue = True
|
||||
if qs.has_key(fjid):
|
||||
no_queue = False
|
||||
no_queue = len(gajim.events.get_events(self.account, fjid)) == 0
|
||||
|
||||
# We print if window is opened
|
||||
pm_control = gajim.interface.msg_win_mgr.get_control(fjid, self.account)
|
||||
|
@ -454,9 +449,9 @@ class GroupchatControl(ChatControlBase):
|
|||
pm_control.print_conversation(msg, tim = tim)
|
||||
return
|
||||
|
||||
if no_queue:
|
||||
qs[fjid] = []
|
||||
qs[fjid].append(('chat', (msg, '', 'incoming', tim, False, '')))
|
||||
event = gajim.events.create_event('pm', (msg, '', 'incoming', tim,
|
||||
False, '', None))
|
||||
gajim.events.add_event(self.account, fjid, event)
|
||||
|
||||
autopopup = gajim.config.get('autopopup')
|
||||
autopopupaway = gajim.config.get('autopopupaway')
|
||||
|
@ -471,8 +466,6 @@ class GroupchatControl(ChatControlBase):
|
|||
self.room_jid, icon_name = 'message')
|
||||
image = state_images['message']
|
||||
model[iter][C_IMG] = image
|
||||
if gajim.interface.systray_enabled:
|
||||
gajim.interface.systray.add_jid(fjid, self.account, 'pm')
|
||||
self.parent_win.show_title()
|
||||
else:
|
||||
self._start_private_message(nick)
|
||||
|
@ -531,18 +524,19 @@ class GroupchatControl(ChatControlBase):
|
|||
if kind == 'incoming': # it's a message NOT from us
|
||||
# highlighting and sounds
|
||||
(highlight, sound) = self.highlighting_for_message(text, tim)
|
||||
gc_class=self.__class__
|
||||
if gc_class.gc_custom_colors.has_key(contact):
|
||||
if self.gc_custom_colors.has_key(contact):
|
||||
other_tags_for_name.append('gc_nickname_color_' + \
|
||||
str(gc_class.gc_custom_colors[contact]))
|
||||
str(self.gc_custom_colors[contact]))
|
||||
else:
|
||||
gc_class.gc_count_nicknames_colors += 1
|
||||
gc_class.gc_custom_colors[contact] = gc_class.gc_count_nicknames_colors
|
||||
self.gc_count_nicknames_colors += 1
|
||||
number_of_colors = len(gajim.config.get('gc_nicknames_colors').\
|
||||
split(':'))
|
||||
if self.gc_count_nicknames_colors == number_of_colors:
|
||||
self.gc_count_nicknames_colors = 0
|
||||
self.gc_custom_colors[contact] = \
|
||||
self.gc_count_nicknames_colors
|
||||
other_tags_for_name.append('gc_nickname_color_' + \
|
||||
str(gc_class.gc_count_nicknames_colors))
|
||||
number_of_colors = len(gajim.config.get('gc_nicknames_colors').split(':'))
|
||||
if gc_class.gc_count_nicknames_colors == number_of_colors:
|
||||
gc_class.gc_count_nicknames_colors = 0
|
||||
str(self.gc_count_nicknames_colors))
|
||||
if highlight:
|
||||
# muc-specific chatstate
|
||||
self.parent_win.redraw_tab(self, 'attention')
|
||||
|
@ -552,12 +546,23 @@ class GroupchatControl(ChatControlBase):
|
|||
helpers.play_sound('muc_message_received')
|
||||
elif sound == 'highlight':
|
||||
helpers.play_sound('muc_message_highlight')
|
||||
if text.startswith('/me ') or text.startswith('/me\n'):
|
||||
other_tags_for_text.append('gc_nickname_color_' + \
|
||||
str(self.gc_custom_colors[contact]))
|
||||
|
||||
self.check_and_possibly_add_focus_out_line()
|
||||
|
||||
ChatControlBase.print_conversation_line(self, text, kind, contact, tim,
|
||||
other_tags_for_name, [], other_tags_for_text)
|
||||
|
||||
def get_nb_unread(self):
|
||||
nb = len(gajim.events.get_events(self.account, self.room_jid,
|
||||
['printed_gc_msg']))
|
||||
for nick in gajim.contacts.get_nick_list(self.account, self.room_jid):
|
||||
nb += len(gajim.events.get_events(self.account, self.room_jid + '/' + \
|
||||
nick, ['pm']))
|
||||
return nb
|
||||
|
||||
def highlighting_for_message(self, text, tim):
|
||||
'''Returns a 2-Tuple. The first says whether or not to highlight the
|
||||
text, the second, what sound to play.'''
|
||||
|
@ -594,64 +599,7 @@ class GroupchatControl(ChatControlBase):
|
|||
# we have full focus (we are reading it!)
|
||||
return
|
||||
|
||||
if not self.allow_focus_out_line:
|
||||
# if room did not receive focus-in from the last time we added
|
||||
# --- line then do not readd
|
||||
return
|
||||
|
||||
print_focus_out_line = False
|
||||
buffer = self.conv_textview.tv.get_buffer()
|
||||
|
||||
if self.focus_out_end_iter_offset is None:
|
||||
# this happens only first time we focus out on this room
|
||||
print_focus_out_line = True
|
||||
|
||||
else:
|
||||
if self.focus_out_end_iter_offset != buffer.get_end_iter().get_offset():
|
||||
# this means after last-focus something was printed
|
||||
# (else end_iter's offset is the same as before)
|
||||
# only then print ---- line (eg. we avoid printing many following
|
||||
# ---- lines)
|
||||
print_focus_out_line = True
|
||||
|
||||
if print_focus_out_line and buffer.get_char_count() > 0:
|
||||
buffer.begin_user_action()
|
||||
|
||||
# remove previous focus out line if such focus out line exists
|
||||
if self.focus_out_end_iter_offset is not None:
|
||||
end_iter_for_previous_line = buffer.get_iter_at_offset(
|
||||
self.focus_out_end_iter_offset)
|
||||
begin_iter_for_previous_line = end_iter_for_previous_line.copy()
|
||||
begin_iter_for_previous_line.backward_chars(2) # img_char+1 (the '\n')
|
||||
|
||||
# remove focus out line
|
||||
buffer.delete(begin_iter_for_previous_line,
|
||||
end_iter_for_previous_line)
|
||||
|
||||
# add the new focus out line
|
||||
# FIXME: Why is this loaded from disk everytime
|
||||
path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps', 'muc_separator.png')
|
||||
focus_out_line_pixbuf = gtk.gdk.pixbuf_new_from_file(path_to_file)
|
||||
end_iter = buffer.get_end_iter()
|
||||
buffer.insert(end_iter, '\n')
|
||||
buffer.insert_pixbuf(end_iter, focus_out_line_pixbuf)
|
||||
|
||||
end_iter = buffer.get_end_iter()
|
||||
before_img_iter = end_iter.copy()
|
||||
before_img_iter.backward_char() # one char back (an image also takes one char)
|
||||
buffer.apply_tag_by_name('focus-out-line', before_img_iter, end_iter)
|
||||
#FIXME: remove this workaround when bug is fixed
|
||||
# c http://bugzilla.gnome.org/show_bug.cgi?id=318569
|
||||
|
||||
self.allow_focus_out_line = False
|
||||
|
||||
# update the iter we hold to make comparison the next time
|
||||
self.focus_out_end_iter_offset = buffer.get_end_iter().get_offset()
|
||||
|
||||
buffer.end_user_action()
|
||||
|
||||
# scroll to the end (via idle in case the scrollbar has appeared)
|
||||
gobject.idle_add(self.conv_textview.scroll_to_end)
|
||||
self.conv_textview.show_focus_out_line()
|
||||
|
||||
def needs_visual_notification(self, text):
|
||||
'''checks text to see whether any of the words in (muc_highlight_words
|
||||
|
@ -747,7 +695,7 @@ class GroupchatControl(ChatControlBase):
|
|||
model = self.list_treeview.get_model()
|
||||
gc_contact = gajim.contacts.get_gc_contact(self.account, self.room_jid, nick)
|
||||
state_images = gajim.interface.roster.jabber_state_images['16']
|
||||
if gajim.awaiting_events[self.account].has_key(self.room_jid + '/' + nick):
|
||||
if len(gajim.events.get_events(self.account, self.room_jid + '/' + nick)):
|
||||
image = state_images['message']
|
||||
else:
|
||||
image = state_images[gc_contact.show]
|
||||
|
@ -830,6 +778,9 @@ class GroupchatControl(ChatControlBase):
|
|||
# after that, but that doesn't hurt
|
||||
self.add_contact_to_roster(new_nick, show, role, affiliation,
|
||||
status, jid)
|
||||
# keep nickname color
|
||||
if nick in self.gc_custom_colors:
|
||||
self.gc_custom_colors[new_nick] = self.gc_custom_colors[nick]
|
||||
# rename vcard / avatar
|
||||
puny_jid = helpers.sanitize_filename(self.room_jid)
|
||||
puny_nick = helpers.sanitize_filename(nick)
|
||||
|
@ -848,7 +799,8 @@ class GroupchatControl(ChatControlBase):
|
|||
os.rename(old_file, files[old_file])
|
||||
self.print_conversation(s, 'info')
|
||||
|
||||
if not gajim.awaiting_events[self.account].has_key(self.room_jid + '/' + nick):
|
||||
if len(gajim.events.get_events(self.account,
|
||||
self.room_jid + '/' + nick)) == 0:
|
||||
self.remove_contact(nick)
|
||||
else:
|
||||
c = gajim.contacts.get_gc_contact(self.account, self.room_jid, nick)
|
||||
|
@ -893,15 +845,18 @@ class GroupchatControl(ChatControlBase):
|
|||
break
|
||||
if print_status is None:
|
||||
print_status = gajim.config.get('print_status_in_muc')
|
||||
nick_jid = nick
|
||||
if jid:
|
||||
nick_jid += ' (%s)' % jid
|
||||
if show == 'offline' and print_status in ('all', 'in_and_out'):
|
||||
st = _('%s has left') % nick
|
||||
st = _('%s has left') % nick_jid
|
||||
if reason:
|
||||
st += ' [%s]' % reason
|
||||
else:
|
||||
if newly_created and print_status in ('all', 'in_and_out'):
|
||||
st = _('%s has joined the room') % nick
|
||||
st = _('%s has joined the room') % nick_jid
|
||||
elif print_status == 'all':
|
||||
st = _('%s is now %s') % (nick, helpers.get_uf_show(show))
|
||||
st = _('%s is now %s') % (nick_jid, helpers.get_uf_show(show))
|
||||
if st:
|
||||
if status:
|
||||
st += ' (' + status + ')'
|
||||
|
@ -1030,7 +985,8 @@ class GroupchatControl(ChatControlBase):
|
|||
if len(message_array):
|
||||
message_array = message_array[0].split()
|
||||
nick = message_array.pop(0)
|
||||
room_nicks = gajim.contacts.get_nick_list(self.account, self.room_jid)
|
||||
room_nicks = gajim.contacts.get_nick_list(self.account,
|
||||
self.room_jid)
|
||||
if nick in room_nicks:
|
||||
privmsg = ' '.join(message_array)
|
||||
self.on_send_pm(nick=nick, msg=privmsg)
|
||||
|
@ -1334,9 +1290,8 @@ class GroupchatControl(ChatControlBase):
|
|||
nb = 0
|
||||
for nick in gajim.contacts.get_nick_list(self.account, self.room_jid):
|
||||
fjid = self.room_jid + '/' + nick
|
||||
if gajim.awaiting_events[self.account].has_key(fjid):
|
||||
# gc can only have messages as event
|
||||
nb += len(gajim.awaiting_events[self.account][fjid])
|
||||
nb += len(gajim.events.get_events(self.account, fjid))
|
||||
# gc can only have messages as event
|
||||
return nb
|
||||
|
||||
def _on_change_subject_menuitem_activate(self, widget):
|
||||
|
|
|
@ -126,8 +126,8 @@ def get_default_font():
|
|||
# in try because daemon may not be there
|
||||
client = gconf.client_get_default()
|
||||
|
||||
return helpers.ensure_unicode_string(
|
||||
client.get_string('/desktop/gnome/interface/font_name'))
|
||||
return client.get_string('/desktop/gnome/interface/font_name'
|
||||
).decode('utf-8')
|
||||
except:
|
||||
pass
|
||||
|
||||
|
@ -147,8 +147,7 @@ def get_default_font():
|
|||
for line in file(xfce_config_file):
|
||||
if line.find('name="Gtk/FontName"') != -1:
|
||||
start = line.find('value="') + 7
|
||||
return helpers.ensure_unicode_string(
|
||||
line[start:line.find('"', start)])
|
||||
return line[start:line.find('"', start)].decode('utf-8')
|
||||
except:
|
||||
#we talk about file
|
||||
print >> sys.stderr, _('Error: cannot open %s for reading') % xfce_config_file
|
||||
|
@ -163,7 +162,7 @@ def get_default_font():
|
|||
font_name = values[0]
|
||||
font_size = values[1]
|
||||
font_string = '%s %s' % (font_name, font_size) # Verdana 9
|
||||
return helpers.ensure_unicode_string(font_string)
|
||||
return font_string.decode('utf-8')
|
||||
except:
|
||||
#we talk about file
|
||||
print >> sys.stderr, _('Error: cannot open %s for reading') % kde_config_file
|
||||
|
@ -406,7 +405,7 @@ def possibly_move_window_in_current_desktop(window):
|
|||
if current_virtual_desktop_no != window_virtual_desktop:
|
||||
# we are in another VD that the window was
|
||||
# so show it in current VD
|
||||
window.show()
|
||||
window.present()
|
||||
|
||||
def file_is_locked(path_to_file):
|
||||
'''returns True if file is locked (WINDOWS ONLY)'''
|
||||
|
@ -458,7 +457,7 @@ def _get_fade_color(treeview, selected, focused):
|
|||
|
||||
def get_scaled_pixbuf(pixbuf, kind):
|
||||
'''returns scaled pixbuf, keeping ratio etc or None
|
||||
kind is either "chat" or "roster" or "notification" or "tooltip"'''
|
||||
kind is either "chat", "roster", "notification", "tooltip", "vcard"'''
|
||||
|
||||
# resize to a width / height for the avatar not to have distortion
|
||||
# (keep aspect ratio)
|
||||
|
|
|
@ -464,8 +464,8 @@ class HistoryManager:
|
|||
except ValueError:
|
||||
pass
|
||||
|
||||
file_.write(_('%(who)s on %(time)s said: %(message)s\n' % {'who': who,
|
||||
'time': time_, 'message': message}))
|
||||
file_.write(_('%(who)s on %(time)s said: %(message)s\n') % {'who': who,
|
||||
'time': time_, 'message': message})
|
||||
|
||||
def _delete_jid_logs(self, liststore, list_of_paths):
|
||||
paths_len = len(list_of_paths)
|
||||
|
|
|
@ -39,7 +39,6 @@ class MessageControl:
|
|||
self.account = account
|
||||
self.hide_chat_buttons_always = False
|
||||
self.hide_chat_buttons_current = False
|
||||
self.nb_unread = 0
|
||||
self.resource = resource
|
||||
|
||||
gajim.last_message_time[self.account][self.get_full_jid()] = 0
|
||||
|
@ -117,10 +116,7 @@ class MessageControl:
|
|||
pass
|
||||
|
||||
def get_specific_unread(self):
|
||||
n = 0
|
||||
if gajim.awaiting_events[self.account].has_key(self.contact.jid):
|
||||
n = len(gajim.awaiting_events[self.account][self.contact.jid])
|
||||
return n
|
||||
return len(gajim.events.get_events(self.account, self.contact.jid))
|
||||
|
||||
def send_message(self, message, keyID = '', type = 'chat',
|
||||
chatstate = None, msg_id = None, composing_jep = None, resource = None,
|
||||
|
|
|
@ -50,6 +50,8 @@ class MessageTextView(gtk.TextView):
|
|||
self.set_pixels_above_lines(2)
|
||||
self.set_pixels_below_lines(2)
|
||||
|
||||
self.lang = None # Lang used for spell checking
|
||||
|
||||
def destroy(self):
|
||||
import gc
|
||||
gobject.idle_add(lambda:gc.collect())
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
##
|
||||
|
||||
import gtk
|
||||
import gobject
|
||||
|
||||
import common
|
||||
import gtkgui_helpers
|
||||
|
@ -149,8 +150,17 @@ class MessageWindow:
|
|||
fjid = control.get_full_jid()
|
||||
self._controls[control.account][fjid] = control
|
||||
|
||||
if self.get_num_controls() > 1:
|
||||
if self.get_num_controls() == 2:
|
||||
# is first conversation_textview scrolled down ?
|
||||
scrolled = False
|
||||
first_widget = self.notebook.get_nth_page(0)
|
||||
ctrl = self._widget_to_control(first_widget)
|
||||
conv_textview = ctrl.conv_textview
|
||||
if conv_textview.at_the_end():
|
||||
scrolled = True
|
||||
self.notebook.set_show_tabs(True)
|
||||
if scrolled:
|
||||
gobject.idle_add(conv_textview.scroll_to_end_iter)
|
||||
self.alignment.set_property('top-padding', 2)
|
||||
|
||||
# Add notebook page and connect up to the tab's close button
|
||||
|
@ -214,7 +224,7 @@ class MessageWindow:
|
|||
gajim.config.get('notify_on_all_muc_messages') and not \
|
||||
ctrl.attention_flag:
|
||||
continue
|
||||
unread += ctrl.nb_unread
|
||||
unread += ctrl.get_nb_unread()
|
||||
|
||||
unread_str = ''
|
||||
if unread > 1:
|
||||
|
@ -270,9 +280,8 @@ class MessageWindow:
|
|||
ctrl.shutdown()
|
||||
|
||||
# Update external state
|
||||
if gajim.interface.systray_enabled:
|
||||
gajim.interface.systray.remove_jid(ctrl.get_full_jid(), ctrl.account,
|
||||
ctrl.type_id)
|
||||
gajim.events.remove_events(ctrl.account, ctrl.get_full_jid,
|
||||
types = ['printed_msg', 'chat', 'gc_msg'])
|
||||
del gajim.last_message_time[ctrl.account][ctrl.get_full_jid()]
|
||||
|
||||
self.disconnect_tab_dnd(ctrl.widget)
|
||||
|
@ -422,10 +431,10 @@ class MessageWindow:
|
|||
if ind < 0:
|
||||
ind = self.notebook.get_n_pages() - 1
|
||||
ctrl = self.get_control(ind, None)
|
||||
if ctrl.nb_unread > 0:
|
||||
if ctrl.get_nb_unread() > 0:
|
||||
found = True
|
||||
break # found
|
||||
else: # Search for a composing contact
|
||||
elif gajim.config.get('ctrl_tab_go_to_next_composing') : # Search for a composing contact
|
||||
contact = ctrl.contact
|
||||
if first_composing_ind == -1 and contact.chatstate == 'composing':
|
||||
# If no composing contact found yet, check if this one is composing
|
||||
|
|
|
@ -1,267 +0,0 @@
|
|||
#!/bin/sh
|
||||
''':'
|
||||
exec python -OOt "$0" ${1+"$@"}
|
||||
' '''
|
||||
## Contributors for this file:
|
||||
## - Yann Le Boulanger <asterix@lagaule.org>
|
||||
## - Nikos Kouremenos <kourem@gmail.com>
|
||||
##
|
||||
## Copyright (C) 2003-2004 Yann Le Boulanger <asterix@lagaule.org>
|
||||
## Vincent Hanquez <tab@snarc.org>
|
||||
## Copyright (C) 2005 Yann Le Boulanger <asterix@lagaule.org>
|
||||
## Vincent Hanquez <tab@snarc.org>
|
||||
## Nikos Kouremenos <nkour@jabber.org>
|
||||
## Dimitur Kirov <dkirov@gmail.com>
|
||||
## Travis Shirk <travis@pobox.com>
|
||||
## Norman Rasmussen <norman@rasmussen.co.za>
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published
|
||||
## by the Free Software Foundation; version 2 only.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
|
||||
import os
|
||||
import sre
|
||||
import sys
|
||||
import time
|
||||
from common import logger
|
||||
from common import i18n
|
||||
|
||||
try:
|
||||
PREFERRED_ENCODING = sys.getpreferredencoding()
|
||||
except:
|
||||
PREFERRED_ENCODING = 'utf-8'
|
||||
from common.helpers import from_one_line, decode_string
|
||||
|
||||
from pysqlite2 import dbapi2 as sqlite
|
||||
|
||||
if os.name == 'nt':
|
||||
try:
|
||||
PATH_TO_LOGS_BASE_DIR = os.path.join(os.environ['appdata'], 'Gajim', 'Logs')
|
||||
PATH_TO_DB = os.path.join(os.environ['appdata'], 'Gajim', 'logs.db') # database is called logs.db
|
||||
except KeyError:
|
||||
# win9x
|
||||
PATH_TO_LOGS_BASE_DIR = '../src/Logs'
|
||||
PATH_TO_DB = '../src/logs.db'
|
||||
else:
|
||||
PATH_TO_LOGS_BASE_DIR = os.path.expanduser('~/.gajim/logs')
|
||||
PATH_TO_DB = os.path.expanduser('~/.gajim/logs.db') # database is called logs.db
|
||||
|
||||
|
||||
|
||||
class Migration:
|
||||
def __init__(self):
|
||||
self.constants = logger.Constants()
|
||||
self.DONE = False
|
||||
self.PROCESSING = False
|
||||
|
||||
if os.path.exists(PATH_TO_DB):
|
||||
print '%s already exists. Exiting..' % PATH_TO_DB
|
||||
sys.exit()
|
||||
|
||||
self.jids_already_in = [] # jid we already put in DB
|
||||
|
||||
def get_jid(self, dirname, filename):
|
||||
# jids.jid text column will be JID if TC-related, room_jid if GC-related,
|
||||
# ROOM_JID/nick if pm-related. Here I get names from filenames
|
||||
if dirname.endswith('logs') or dirname.endswith('Logs'):
|
||||
# we have file (not dir) in logs base dir, so it's TC
|
||||
jid = filename # file is JID
|
||||
else:
|
||||
# we are in a room folder (so it can be either pm or message in room)
|
||||
if filename == os.path.basename(dirname): # room/room
|
||||
jid = dirname # filename is ROOM_JID
|
||||
else: #room/nick it's pm
|
||||
jid = dirname + '/' + filename
|
||||
|
||||
if jid.startswith('/'):
|
||||
p = len(PATH_TO_LOGS_BASE_DIR)
|
||||
jid = jid[p+1:]
|
||||
jid = jid.lower()
|
||||
return jid
|
||||
|
||||
def decode_jid(self, string):
|
||||
'''try to decode (to make it Unicode instance) given jid'''
|
||||
string = decode_string(string)
|
||||
if isinstance(string, str):
|
||||
return None # decode failed
|
||||
return string
|
||||
|
||||
def visit(self, arg, dirname, filenames):
|
||||
s = _('Visiting %s') % dirname
|
||||
if self.queue:
|
||||
self.queue.put(s)
|
||||
else:
|
||||
print s
|
||||
for filename in filenames:
|
||||
# Don't take this file into account, this is dup info
|
||||
# notifications are also in contact log file
|
||||
if filename in ('notify.log', 'README'):
|
||||
continue
|
||||
path_to_text_file = os.path.join(dirname, filename)
|
||||
if os.path.isdir(path_to_text_file):
|
||||
continue
|
||||
|
||||
jid = self.get_jid(dirname, filename)
|
||||
|
||||
jid = self.decode_jid(jid)
|
||||
if not jid:
|
||||
continue
|
||||
|
||||
if filename == os.path.basename(dirname): # gajim@conf/gajim@conf then gajim@conf is type room
|
||||
jid_type = self.constants.JID_ROOM_TYPE
|
||||
#Type of log
|
||||
typ = 'room'
|
||||
else:
|
||||
jid_type = self.constants.JID_NORMAL_TYPE
|
||||
#Type of log
|
||||
typ = _('normal')
|
||||
s = _('Processing %s of type %s') % (jid, typ)
|
||||
if self.queue:
|
||||
self.queue.put(s.encode(PREFERRED_ENCODING))
|
||||
else:
|
||||
print s.encode(PREFERRED_ENCODING)
|
||||
|
||||
JID_ID = None
|
||||
f = open(path_to_text_file, 'r')
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
line = from_one_line(line)
|
||||
splitted_line = line.split(':')
|
||||
if len(splitted_line) > 2:
|
||||
# type in logs is one of
|
||||
# 'gc', 'gcstatus', 'recv', 'sent' and if nothing of those
|
||||
# it is status
|
||||
# new db has:
|
||||
# status, gcstatus, gc_msg, (we only recv those 3),
|
||||
# single_msg_recv, chat_msg_recv, chat_msg_sent, single_msg_sent
|
||||
# to meet all our needs
|
||||
# here I convert
|
||||
# gc ==> gc_msg, gcstatus ==> gcstatus, recv ==> chat_msg_recv
|
||||
# sent ==> chat_msg_sent, status ==> status
|
||||
typ = splitted_line[1] # line[1] has type of logged message
|
||||
message_data = splitted_line[2:] # line[2:] has message data
|
||||
# line[0] is date,
|
||||
# some lines can be fucked up, just drop them
|
||||
try:
|
||||
tim = int(float(splitted_line[0]))
|
||||
except:
|
||||
continue
|
||||
|
||||
contact_name = None
|
||||
show = None
|
||||
if typ == 'gc':
|
||||
contact_name = message_data[0]
|
||||
message = ':'.join(message_data[1:])
|
||||
kind = self.constants.KIND_GC_MSG
|
||||
elif typ == 'gcstatus':
|
||||
contact_name = message_data[0]
|
||||
show = message_data[1]
|
||||
message = ':'.join(message_data[2:]) # status msg
|
||||
kind = self.constants.KIND_GCSTATUS
|
||||
elif typ == 'recv':
|
||||
message = ':'.join(message_data[0:])
|
||||
kind = self.constants.KIND_CHAT_MSG_RECV
|
||||
elif typ == 'sent':
|
||||
message = ':'.join(message_data[0:])
|
||||
kind = self.constants.KIND_CHAT_MSG_SENT
|
||||
else: # status
|
||||
kind = self.constants.KIND_STATUS
|
||||
show = message_data[0]
|
||||
message = ':'.join(message_data[1:]) # status msg
|
||||
|
||||
message = message[:-1] # remove last \n
|
||||
if not message:
|
||||
continue
|
||||
|
||||
# jid is already in the DB, don't create a new row, just get his jid_id
|
||||
if not JID_ID:
|
||||
if jid in self.jids_already_in:
|
||||
self.cur.execute('SELECT jid_id FROM jids WHERE jid = "%s"' % jid)
|
||||
JID_ID = self.cur.fetchone()[0]
|
||||
else:
|
||||
self.jids_already_in.append(jid)
|
||||
self.cur.execute('INSERT INTO jids (jid, type) VALUES (?, ?)',
|
||||
(jid, jid_type))
|
||||
self.con.commit()
|
||||
JID_ID = self.cur.lastrowid
|
||||
|
||||
sql = 'INSERT INTO logs (jid_id, contact_name, time, kind, show, message) '\
|
||||
'VALUES (?, ?, ?, ?, ?, ?)'
|
||||
|
||||
values = (JID_ID, contact_name, tim, kind, show, message)
|
||||
self.cur.execute(sql, values)
|
||||
self.con.commit()
|
||||
|
||||
def migrate(self, queue = None):
|
||||
self.queue = queue
|
||||
self.con = sqlite.connect(PATH_TO_DB)
|
||||
os.chmod(PATH_TO_DB, 0600) # rw only for us
|
||||
self.cur = self.con.cursor()
|
||||
# create the tables
|
||||
# kind can be
|
||||
# status, gcstatus, gc_msg, (we only recv for those 3),
|
||||
# single_msg_recv, chat_msg_recv, chat_msg_sent, single_msg_sent
|
||||
# to meet all our needs
|
||||
# logs.jid_id --> jids.jid_id but Sqlite doesn't do FK etc so it's done in python code
|
||||
self.cur.executescript(
|
||||
'''
|
||||
CREATE TABLE jids(
|
||||
jid_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
jid TEXT UNIQUE,
|
||||
type INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE unread_messages(
|
||||
message_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
jid_id INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE logs(
|
||||
log_line_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
jid_id INTEGER,
|
||||
contact_name TEXT,
|
||||
time INTEGER,
|
||||
kind INTEGER,
|
||||
show INTEGER,
|
||||
message TEXT,
|
||||
subject TEXT
|
||||
);
|
||||
'''
|
||||
)
|
||||
|
||||
self.con.commit()
|
||||
|
||||
self.PROCESSING = True
|
||||
os.path.walk(PATH_TO_LOGS_BASE_DIR, self.visit, None)
|
||||
s = '''
|
||||
|
||||
We do not use plain-text files anymore, because they do not meet our needs.
|
||||
Those files here are logs for Gajim up until 0.8.2
|
||||
We now use an sqlite database called logs.db found in %s
|
||||
You can now safely remove your %s folder
|
||||
Thank you''' % (os.path.dirname(PATH_TO_LOGS_BASE_DIR), PATH_TO_LOGS_BASE_DIR)
|
||||
f = open(os.path.join(PATH_TO_LOGS_BASE_DIR, 'README'), 'w')
|
||||
f.write(s)
|
||||
f.close()
|
||||
if queue:
|
||||
queue.put(s)
|
||||
self.DONE = True
|
||||
|
||||
if __name__ == '__main__':
|
||||
# magic argumen 'dont_wait' tells us that script is run from Gajim
|
||||
if len(sys.argv) < 2 or sys.argv[1] != 'dont_wait':
|
||||
print 'IMPORTNANT: PLEASE READ http://trac.gajim.org/wiki/MigrateLogToDot9DB'
|
||||
print 'Migration will start in 40 seconds unless you press Ctrl+C'
|
||||
time.sleep(40) # give the user time to act
|
||||
print
|
||||
print 'Starting Logs Migration'
|
||||
print '======================='
|
||||
print 'Please do NOT run Gajim until this script is over'
|
||||
m = Migration()
|
||||
m.migrate()
|
135
src/notify.py
|
@ -32,12 +32,89 @@ if dbus_support.supported:
|
|||
import dbus.glib
|
||||
import dbus.service
|
||||
|
||||
def notify(event, jid, account, parameters):
|
||||
def get_show_in_roster(event, account, contact):
|
||||
'''Return True if this event must be shown in roster, else False'''
|
||||
num = get_advanced_notification(event, account, contact)
|
||||
if num != None:
|
||||
if gajim.config.get_per('notifications', str(num), 'roster') == 'yes':
|
||||
return True
|
||||
if gajim.config.get_per('notifications', str(num), 'roster') == 'no':
|
||||
return False
|
||||
if event == 'message_received':
|
||||
chat_control = helpers.get_chat_control(account, contact)
|
||||
if not chat_control:
|
||||
return True
|
||||
elif event == 'ft_request':
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_show_in_systray(event, account, contact):
|
||||
'''Return True if this event must be shown in roster, else False'''
|
||||
num = get_advanced_notification(event, account, contact)
|
||||
if num != None:
|
||||
if gajim.config.get_per('notifications', str(num), 'systray') == 'yes':
|
||||
return True
|
||||
if gajim.config.get_per('notifications', str(num), 'systray') == 'no':
|
||||
return False
|
||||
if event in ('message_received', 'ft_request', 'gc_msg_highlight',
|
||||
'ft_request'):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_advanced_notification(event, account, contact):
|
||||
'''Returns the number of the first advanced notification or None'''
|
||||
num = 0
|
||||
notif = gajim.config.get_per('notifications', str(num))
|
||||
while notif:
|
||||
recipient_ok = False
|
||||
status_ok = False
|
||||
tab_opened_ok = False
|
||||
# test event
|
||||
if gajim.config.get_per('notifications', str(num), 'event') == event:
|
||||
# test recipient
|
||||
recipient_type = gajim.config.get_per('notifications', str(num),
|
||||
'recipient_type')
|
||||
recipients = gajim.config.get_per('notifications', str(num),
|
||||
'recipients').split()
|
||||
if recipient_type == 'all':
|
||||
recipient_ok = True
|
||||
elif recipient_type == 'contact' and contact.jid in recipients:
|
||||
recipient_ok = True
|
||||
elif recipient_type == 'group':
|
||||
for group in contact.groups:
|
||||
if group in contact.groups:
|
||||
recipient_ok = True
|
||||
break
|
||||
if recipient_ok:
|
||||
# test status
|
||||
our_status = gajim.SHOW_LIST[gajim.connections[account].connected]
|
||||
status = gajim.config.get_per('notifications', str(num), 'status')
|
||||
if status == 'all' or our_status in status.split():
|
||||
status_ok = True
|
||||
if status_ok:
|
||||
# test window_opened
|
||||
tab_opened = gajim.config.get_per('notifications', str(num),
|
||||
'tab_opened')
|
||||
if tab_opened == 'both':
|
||||
tab_opened_ok = True
|
||||
else:
|
||||
chat_control = helper.get_chat_control(account, contact)
|
||||
if (chat_control and tab_opened == 'yes') or (not chat_control and \
|
||||
tab_opened == 'no'):
|
||||
tab_opened_ok = True
|
||||
if tab_opened_ok:
|
||||
return num
|
||||
|
||||
num += 1
|
||||
notif = gajim.config.get_per('notifications', str(num))
|
||||
|
||||
def notify(event, jid, account, parameters, advanced_notif_num = None):
|
||||
'''Check what type of notifications we want, depending on basic configuration
|
||||
of notifications and advanced one and do these notifications'''
|
||||
# First, find what notifications we want
|
||||
do_popup = False
|
||||
do_sound = False
|
||||
do_cmd = False
|
||||
if (event == 'status_change'):
|
||||
new_show = parameters[0]
|
||||
status_message = parameters[1]
|
||||
|
@ -51,9 +128,8 @@ def notify(event, jid, account, parameters):
|
|||
if account_server in gajim.block_signed_in_notifications and \
|
||||
gajim.block_signed_in_notifications[account_server]:
|
||||
block_transport = True
|
||||
if gajim.config.get('notify_on_signin') and \
|
||||
not gajim.block_signed_in_notifications[account] and not block_transport \
|
||||
and helpers.allow_showing_notification(account):
|
||||
if helpers.allow_showing_notification(account, 'notify_on_signin') and \
|
||||
not gajim.block_signed_in_notifications[account] and not block_transport:
|
||||
do_popup = True
|
||||
if gajim.config.get_per('soundevents', 'contact_connected',
|
||||
'enabled') and not gajim.block_signed_in_notifications[account] and \
|
||||
|
@ -61,8 +137,7 @@ def notify(event, jid, account, parameters):
|
|||
do_sound = True
|
||||
elif (event == 'contact_disconnected'):
|
||||
status_message = parameters
|
||||
if gajim.config.get('notify_on_signout') \
|
||||
and helpers.allow_showing_notification(account):
|
||||
if helpers.allow_showing_notification(account, 'notify_on_signout'):
|
||||
do_popup = True
|
||||
if gajim.config.get_per('soundevents', 'contact_disconnected',
|
||||
'enabled'):
|
||||
|
@ -72,17 +147,21 @@ def notify(event, jid, account, parameters):
|
|||
first = parameters[1]
|
||||
nickname = parameters[2]
|
||||
message = parameters[3]
|
||||
if gajim.config.get('notify_on_new_message') and \
|
||||
helpers.allow_showing_notification(account) and first:
|
||||
if helpers.allow_showing_notification(account, 'notify_on_new_message',
|
||||
advanced_notif_num, first):
|
||||
do_popup = True
|
||||
if first and gajim.config.get_per('soundevents', 'first_message_received',
|
||||
'enabled'):
|
||||
if first and helpers.allow_sound_notification('first_message_received',
|
||||
advanced_notif_num):
|
||||
do_sound = True
|
||||
elif not first and gajim.config.get_per('soundevents', 'next_message_received',
|
||||
'enabled'):
|
||||
elif not first and helpers.allow_sound_notification(
|
||||
'next_message_received', advanced_notif_num):
|
||||
do_sound = True
|
||||
else:
|
||||
print '*Event not implemeted yet*'
|
||||
|
||||
if advanced_notif_num != None and gajim.config.get_per('notifications',
|
||||
str(advanced_notif_num), 'run_command'):
|
||||
do_cmd = True
|
||||
|
||||
# Do the wanted notifications
|
||||
if (do_popup):
|
||||
|
@ -161,14 +240,34 @@ def notify(event, jid, account, parameters):
|
|||
path_to_image = path, title = title, text = text)
|
||||
|
||||
if (do_sound):
|
||||
snd_file = None
|
||||
snd_event = None # If not snd_file, play the event
|
||||
if (event == 'new_message'):
|
||||
if first:
|
||||
helpers.play_sound('first_message_received')
|
||||
if advanced_notif_num != None and gajim.config.get_per('notifications',
|
||||
str(advanced_notif_num), 'sound') == 'yes':
|
||||
snd_file = gajim.config.get_per('notifications',
|
||||
str(advanced_notif_num), 'sound_file')
|
||||
elif advanced_notif_num != None and gajim.config.get_per(
|
||||
'notifications', str(advanced_notif_num), 'sound') == 'no':
|
||||
pass # do not set snd_event
|
||||
elif first:
|
||||
snd_event = 'first_message_received'
|
||||
else:
|
||||
helpers.play_sound('next_message_received')
|
||||
snd_event = 'next_message_received'
|
||||
elif event in ('contact_connected', 'contact_disconnected'):
|
||||
helpers.play_sound(event)
|
||||
|
||||
snd_event = event
|
||||
if snd_file:
|
||||
helpers.play_sound_file(snd_file)
|
||||
if snd_event:
|
||||
helpers.play_sound(snd_event)
|
||||
|
||||
if do_cmd:
|
||||
command = gajim.config.get_per('notifications', str(advanced_notif_num),
|
||||
'command')
|
||||
try:
|
||||
helpers.exec_command(command)
|
||||
except:
|
||||
pass
|
||||
|
||||
def popup(event_type, jid, account, msg_type = '', path_to_image = None,
|
||||
title = None, text = None):
|
||||
|
@ -283,6 +382,8 @@ class DesktopNotification:
|
|||
ntype = 'im.invitation'
|
||||
elif event_type == _('Contact Changed Status'):
|
||||
ntype = 'presence.status'
|
||||
elif event_type == _('Connection Failed'):
|
||||
ntype = 'connection.failed'
|
||||
else:
|
||||
# default failsafe values
|
||||
self.path_to_image = os.path.abspath(
|
||||
|
|
283
src/profile_window.py
Normal file
|
@ -0,0 +1,283 @@
|
|||
## profile_window.py
|
||||
##
|
||||
## Copyright (C) 2003-2006 Yann Le Boulanger <asterix@lagaule.org>
|
||||
## Copyright (C) 2005-2006 Nikos Kouremenos <kourem@gmail.com>
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published
|
||||
## by the Free Software Foundation; version 2 only.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
|
||||
import gtk
|
||||
import gobject
|
||||
import base64
|
||||
import mimetypes
|
||||
import os
|
||||
import time
|
||||
import locale
|
||||
|
||||
import gtkgui_helpers
|
||||
import dialogs
|
||||
|
||||
from common import helpers
|
||||
from common import gajim
|
||||
from common.i18n import Q_
|
||||
|
||||
def get_avatar_pixbuf_encoded_mime(photo):
|
||||
'''return the pixbuf of the image
|
||||
photo is a dictionary containing PHOTO information'''
|
||||
if not isinstance(photo, dict):
|
||||
return None, None, None
|
||||
img_decoded = None
|
||||
avatar_encoded = None
|
||||
avatar_mime_type = None
|
||||
if photo.has_key('BINVAL'):
|
||||
img_encoded = photo['BINVAL']
|
||||
avatar_encoded = img_encoded
|
||||
try:
|
||||
img_decoded = base64.decodestring(img_encoded)
|
||||
except:
|
||||
pass
|
||||
if img_decoded:
|
||||
if photo.has_key('TYPE'):
|
||||
avatar_mime_type = photo['TYPE']
|
||||
pixbuf = gtkgui_helpers.get_pixbuf_from_data(img_decoded)
|
||||
else:
|
||||
pixbuf, avatar_mime_type = gtkgui_helpers.get_pixbuf_from_data(
|
||||
img_decoded, want_type=True)
|
||||
else:
|
||||
pixbuf = None
|
||||
return pixbuf, avatar_encoded, avatar_mime_type
|
||||
|
||||
class ProfileWindow:
|
||||
'''Class for our information window'''
|
||||
|
||||
def __init__(self, account):
|
||||
self.xml = gtkgui_helpers.get_glade('profile_window.glade')
|
||||
self.window = self.xml.get_widget('profile_window')
|
||||
|
||||
self.account = account
|
||||
self.jid = gajim.get_jid_from_account(account)
|
||||
|
||||
self.avatar_mime_type = None
|
||||
self.avatar_encoded = None
|
||||
|
||||
self.xml.signal_autoconnect(self)
|
||||
self.window.show_all()
|
||||
|
||||
def on_profile_window_destroy(self, widget):
|
||||
del gajim.interface.instances[self.account]['profile']
|
||||
|
||||
def on_profile_window_key_press_event(self, widget, event):
|
||||
if event.keyval == gtk.keysyms.Escape:
|
||||
self.window.destroy()
|
||||
|
||||
def on_clear_button_clicked(self, widget):
|
||||
# empty the image
|
||||
self.xml.get_widget('PHOTO_image').set_from_icon_name('stock_person',
|
||||
gtk.ICON_SIZE_DIALOG)
|
||||
self.avatar_encoded = None
|
||||
self.avatar_mime_type = None
|
||||
|
||||
def on_set_avatar_button_clicked(self, widget):
|
||||
f = None
|
||||
def on_ok(widget, path_to_file):
|
||||
filesize = os.path.getsize(path_to_file) # in bytes
|
||||
#FIXME: use messages for invalid file for 0.11
|
||||
invalid_file = False
|
||||
msg = ''
|
||||
if os.path.isfile(path_to_file):
|
||||
stat = os.stat(path_to_file)
|
||||
if stat[6] == 0:
|
||||
invalid_file = True
|
||||
else:
|
||||
invalid_file = True
|
||||
if not invalid_file and filesize > 16384: # 16 kb
|
||||
try:
|
||||
pixbuf = gtk.gdk.pixbuf_new_from_file(path_to_file)
|
||||
# get the image at 'notification size'
|
||||
# and use that user did not specify in ACE crazy size
|
||||
scaled_pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf,
|
||||
'tooltip')
|
||||
except gobject.GError, msg: # unknown format
|
||||
# msg should be string, not object instance
|
||||
msg = str(msg)
|
||||
invalid_file = True
|
||||
if invalid_file:
|
||||
if True: # keep identation
|
||||
dialogs.ErrorDialog(_('Could not load image'), msg)
|
||||
return
|
||||
if filesize > 16384:
|
||||
if scaled_pixbuf:
|
||||
path_to_file = os.path.join(gajim.TMP,
|
||||
'avatar_scaled.png')
|
||||
scaled_pixbuf.save(path_to_file, 'png')
|
||||
self.dialog.destroy()
|
||||
|
||||
fd = open(path_to_file, 'rb')
|
||||
data = fd.read()
|
||||
pixbuf = gtkgui_helpers.get_pixbuf_from_data(data)
|
||||
# rescale it
|
||||
pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf, 'vcard')
|
||||
image = self.xml.get_widget('PHOTO_image')
|
||||
image.set_from_pixbuf(pixbuf)
|
||||
self.avatar_encoded = base64.encodestring(data)
|
||||
# returns None if unknown type
|
||||
self.avatar_mime_type = mimetypes.guess_type(path_to_file)[0]
|
||||
|
||||
self.dialog = dialogs.ImageChooserDialog(on_response_ok = on_ok)
|
||||
|
||||
def on_PHOTO_button_press_event(self, widget, event):
|
||||
'''If right-clicked, show popup'''
|
||||
if event.button == 3 and self.avatar_encoded: # right click
|
||||
menu = gtk.Menu()
|
||||
nick = gajim.config.get_per('accounts', self.account, 'name')
|
||||
menuitem = gtk.ImageMenuItem(gtk.STOCK_SAVE_AS)
|
||||
menuitem.connect('activate',
|
||||
gtkgui_helpers.on_avatar_save_as_menuitem_activate,
|
||||
self.jid, None, nick + '.jpeg')
|
||||
menu.append(menuitem)
|
||||
# show clear
|
||||
menuitem = gtk.ImageMenuItem(gtk.STOCK_CLEAR)
|
||||
menuitem.connect('activate', self.on_clear_button_clicked)
|
||||
menu.append(menuitem)
|
||||
menu.connect('selection-done', lambda w:w.destroy())
|
||||
# show the menu
|
||||
menu.show_all()
|
||||
menu.popup(None, None, None, event.button, event.time)
|
||||
elif event.button == 1: # left click
|
||||
self.on_set_avatar_button_clicked(widget)
|
||||
|
||||
def set_value(self, entry_name, value):
|
||||
try:
|
||||
self.xml.get_widget(entry_name).set_text(value)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def set_values(self, vcard):
|
||||
if not 'PHOTO' in vcard:
|
||||
# set default image
|
||||
image = self.xml.get_widget('PHOTO_image')
|
||||
image.set_from_icon_name('stock_person', gtk.ICON_SIZE_DIALOG)
|
||||
for i in vcard.keys():
|
||||
if i == 'PHOTO':
|
||||
pixbuf, self.avatar_encoded, self.avatar_mime_type = \
|
||||
get_avatar_pixbuf_encoded_mime(vcard[i])
|
||||
image = self.xml.get_widget('PHOTO_image')
|
||||
if not pixbuf:
|
||||
image.set_from_icon_name('stock_person', gtk.ICON_SIZE_DIALOG)
|
||||
continue
|
||||
pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf, 'vcard')
|
||||
image.set_from_pixbuf(pixbuf)
|
||||
continue
|
||||
if i == 'ADR' or i == 'TEL' or i == 'EMAIL':
|
||||
for entry in vcard[i]:
|
||||
add_on = '_HOME'
|
||||
if 'WORK' in entry:
|
||||
add_on = '_WORK'
|
||||
for j in entry.keys():
|
||||
self.set_value(i + add_on + '_' + j + '_entry', entry[j])
|
||||
if isinstance(vcard[i], dict):
|
||||
for j in vcard[i].keys():
|
||||
self.set_value(i + '_' + j + '_entry', vcard[i][j])
|
||||
else:
|
||||
if i == 'DESC':
|
||||
self.xml.get_widget('DESC_textview').get_buffer().set_text(
|
||||
vcard[i], 0)
|
||||
else:
|
||||
self.set_value(i + '_entry', vcard[i])
|
||||
|
||||
def add_to_vcard(self, vcard, entry, txt):
|
||||
'''Add an information to the vCard dictionary'''
|
||||
entries = entry.split('_')
|
||||
loc = vcard
|
||||
if len(entries) == 3: # We need to use lists
|
||||
if not loc.has_key(entries[0]):
|
||||
loc[entries[0]] = []
|
||||
found = False
|
||||
for e in loc[entries[0]]:
|
||||
if entries[1] in e:
|
||||
found = True
|
||||
break
|
||||
if found:
|
||||
e[entries[2]] = txt
|
||||
else:
|
||||
loc[entries[0]].append({entries[1]: '', entries[2]: txt})
|
||||
return vcard
|
||||
while len(entries) > 1:
|
||||
if not loc.has_key(entries[0]):
|
||||
loc[entries[0]] = {}
|
||||
loc = loc[entries[0]]
|
||||
del entries[0]
|
||||
loc[entries[0]] = txt
|
||||
return vcard
|
||||
|
||||
def make_vcard(self):
|
||||
'''make the vCard dictionary'''
|
||||
entries = ['FN', 'NICKNAME', 'BDAY', 'EMAIL_HOME_USERID', 'URL',
|
||||
'TEL_HOME_NUMBER', 'N_FAMILY', 'N_GIVEN', 'N_MIDDLE', 'N_PREFIX',
|
||||
'N_SUFFIX', 'ADR_HOME_STREET', 'ADR_HOME_EXTADR', 'ADR_HOME_LOCALITY',
|
||||
'ADR_HOME_REGION', 'ADR_HOME_PCODE', 'ADR_HOME_CTRY', 'ORG_ORGNAME',
|
||||
'ORG_ORGUNIT', 'TITLE', 'ROLE', 'TEL_WORK_NUMBER', 'EMAIL_WORK_USERID',
|
||||
'ADR_WORK_STREET', 'ADR_WORK_EXTADR', 'ADR_WORK_LOCALITY',
|
||||
'ADR_WORK_REGION', 'ADR_WORK_PCODE', 'ADR_WORK_CTRY']
|
||||
vcard = {}
|
||||
for e in entries:
|
||||
txt = self.xml.get_widget(e + '_entry').get_text().decode('utf-8')
|
||||
if txt != '':
|
||||
vcard = self.add_to_vcard(vcard, e, txt)
|
||||
|
||||
# DESC textview
|
||||
buff = self.xml.get_widget('DESC_textview').get_buffer()
|
||||
start_iter = buff.get_start_iter()
|
||||
end_iter = buff.get_end_iter()
|
||||
txt = buff.get_text(start_iter, end_iter, 0)
|
||||
if txt != '':
|
||||
vcard['DESC'] = txt.decode('utf-8')
|
||||
|
||||
# Avatar
|
||||
if self.avatar_encoded:
|
||||
vcard['PHOTO'] = {'BINVAL': self.avatar_encoded}
|
||||
if self.avatar_mime_type:
|
||||
vcard['PHOTO']['TYPE'] = self.avatar_mime_type
|
||||
return vcard
|
||||
|
||||
def on_publish_button_clicked(self, widget):
|
||||
if gajim.connections[self.account].connected < 2:
|
||||
dialogs.ErrorDialog(_('You are not connected to the server'),
|
||||
_('Without a connection you can not publish your contact '
|
||||
'information.'))
|
||||
return
|
||||
vcard = self.make_vcard()
|
||||
nick = ''
|
||||
if vcard.has_key('NICKNAME'):
|
||||
nick = vcard['NICKNAME']
|
||||
if nick == '':
|
||||
nick = gajim.config.get_per('accounts', self.account, 'name')
|
||||
gajim.nicks[self.account] = nick
|
||||
gajim.connections[self.account].send_vcard(vcard)
|
||||
|
||||
def on_retrieve_button_clicked(self, widget):
|
||||
entries = ['FN', 'NICKNAME', 'BDAY', 'EMAIL_HOME_USERID', 'URL',
|
||||
'TEL_HOME_NUMBER', 'N_FAMILY', 'N_GIVEN', 'N_MIDDLE', 'N_PREFIX',
|
||||
'N_SUFFIX', 'ADR_HOME_STREET', 'ADR_HOME_EXTADR', 'ADR_HOME_LOCALITY',
|
||||
'ADR_HOME_REGION', 'ADR_HOME_PCODE', 'ADR_HOME_CTRY', 'ORG_ORGNAME',
|
||||
'ORG_ORGUNIT', 'TITLE', 'ROLE', 'ADR_WORK_STREET', 'ADR_WORK_EXTADR',
|
||||
'ADR_WORK_LOCALITY', 'ADR_WORK_REGION', 'ADR_WORK_PCODE',
|
||||
'ADR_WORK_CTRY']
|
||||
if gajim.connections[self.account].connected > 1:
|
||||
# clear all entries
|
||||
for e in entries:
|
||||
self.xml.get_widget(e + '_entry').set_text('')
|
||||
self.xml.get_widget('DESC_textview').get_buffer().set_text('')
|
||||
self.xml.get_widget('PHOTO_image').set_from_icon_name('stock_person',
|
||||
gtk.ICON_SIZE_DIALOG)
|
||||
gajim.connections[self.account].request_vcard(self.jid)
|
||||
else:
|
||||
dialogs.ErrorDialog(_('You are not connected to the server'),
|
||||
_('Without a connection, you can not get your contact information.'))
|
|
@ -54,7 +54,7 @@ ident = lambda e: e
|
|||
if dbus_support.version[1] >= 43:
|
||||
# in most cases it is a utf-8 string
|
||||
DBUS_STRING = dbus.String
|
||||
|
||||
|
||||
# general type (for use in dicts,
|
||||
# where all values should have the same type)
|
||||
DBUS_VARIANT = dbus.Variant
|
||||
|
@ -67,7 +67,7 @@ if dbus_support.version[1] >= 43:
|
|||
DBUS_DICT_SS = lambda : dbus.Dictionary({}, signature="ss")
|
||||
# empty type
|
||||
DBUS_NONE = lambda : dbus.Variant(0)
|
||||
|
||||
|
||||
else: # 33, 35, 36
|
||||
DBUS_DICT_SV = lambda : {}
|
||||
DBUS_DICT_SS = lambda : {}
|
||||
|
@ -122,7 +122,7 @@ class Remote:
|
|||
def __init__(self):
|
||||
self.signal_object = None
|
||||
session_bus = dbus_support.session_bus.SessionBus()
|
||||
|
||||
|
||||
if dbus_support.version[1] >= 41:
|
||||
service = dbus.service.BusName(SERVICE, bus=session_bus)
|
||||
self.signal_object = SignalObject(service)
|
||||
|
@ -139,7 +139,7 @@ class Remote:
|
|||
class SignalObject(DbusPrototype):
|
||||
''' Local object definition for /org/gajim/dbus/RemoteObject. This doc must
|
||||
not be visible, because the clients can access only the remote object. '''
|
||||
|
||||
|
||||
def __init__(self, service):
|
||||
self.first_show = True
|
||||
self.vcard_account = None
|
||||
|
@ -171,6 +171,7 @@ class SignalObject(DbusPrototype):
|
|||
self.get_status,
|
||||
self.get_status_message,
|
||||
self.start_chat,
|
||||
self.send_xml,
|
||||
])
|
||||
|
||||
def raise_signal(self, signal, arg):
|
||||
|
@ -180,7 +181,7 @@ class SignalObject(DbusPrototype):
|
|||
i = message.get_iter(True)
|
||||
i.append(arg)
|
||||
self._connection.send(message)
|
||||
|
||||
|
||||
def get_status(self, *args):
|
||||
'''get_status(account = None)
|
||||
returns status (show to be exact) which is the global one
|
||||
|
@ -193,7 +194,7 @@ class SignalObject(DbusPrototype):
|
|||
# return show for the given account
|
||||
index = gajim.connections[account].connected
|
||||
return DBUS_STRING(STATUS_LIST[index])
|
||||
|
||||
|
||||
def get_status_message(self, *args):
|
||||
'''get_status(account = None)
|
||||
returns status which is the global one
|
||||
|
@ -206,7 +207,7 @@ class SignalObject(DbusPrototype):
|
|||
# return show for the given account
|
||||
status = gajim.connections[account].status
|
||||
return DBUS_STRING(status)
|
||||
|
||||
|
||||
|
||||
def get_account_and_contact(self, account, jid):
|
||||
''' get the account (if not given) and contact instance from jid'''
|
||||
|
@ -232,7 +233,7 @@ class SignalObject(DbusPrototype):
|
|||
break
|
||||
if not contact:
|
||||
contact = jid
|
||||
|
||||
|
||||
return connected_account, contact
|
||||
|
||||
def send_file(self, *args):
|
||||
|
@ -240,6 +241,7 @@ class SignalObject(DbusPrototype):
|
|||
send file, located at 'file_path' to 'jid', using account
|
||||
(optional) 'account' '''
|
||||
file_path, jid, account = self._get_real_arguments(args, 3)
|
||||
jid = self._get_real_jid(jid, account)
|
||||
connected_account, contact = self.get_account_and_contact(account, jid)
|
||||
|
||||
if connected_account:
|
||||
|
@ -250,7 +252,7 @@ class SignalObject(DbusPrototype):
|
|||
connected_account, contact, file_path)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _send_message(self, jid, message, keyID, account, type = 'chat', subject = None):
|
||||
''' can be called from send_chat_message (default when send_message)
|
||||
or send_single_message'''
|
||||
|
@ -258,20 +260,21 @@ class SignalObject(DbusPrototype):
|
|||
return None # or raise error
|
||||
if not keyID:
|
||||
keyID = ''
|
||||
|
||||
|
||||
connected_account, contact = self.get_account_and_contact(account, jid)
|
||||
|
||||
|
||||
if connected_account:
|
||||
connection = gajim.connections[connected_account]
|
||||
res = connection.send_message(jid, message, keyID, type, subject)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def send_chat_message(self, *args):
|
||||
''' send_message(jid, message, keyID=None, account=None)
|
||||
send chat 'message' to 'jid', using account (optional) 'account'.
|
||||
if keyID is specified, encrypt the message with the pgp key '''
|
||||
jid, message, keyID, account = self._get_real_arguments(args, 4)
|
||||
jid = self._get_real_jid(jid, account)
|
||||
return self._send_message(jid, message, keyID, account)
|
||||
|
||||
def send_single_message(self, *args):
|
||||
|
@ -279,6 +282,7 @@ class SignalObject(DbusPrototype):
|
|||
send single 'message' to 'jid', using account (optional) 'account'.
|
||||
if keyID is specified, encrypt the message with the pgp key '''
|
||||
jid, subject, message, keyID, account = self._get_real_arguments(args, 5)
|
||||
jid = self._get_real_jid(jid, account)
|
||||
return self._send_message(jid, message, keyID, account, type, subject)
|
||||
|
||||
def open_chat(self, *args):
|
||||
|
@ -288,9 +292,8 @@ class SignalObject(DbusPrototype):
|
|||
if not jid:
|
||||
# FIXME: raise exception for missing argument (dbus0.35+)
|
||||
return None
|
||||
if jid.startswith('xmpp:'):
|
||||
jid = jid[5:] # len('xmpp:') = 5
|
||||
|
||||
jid = self._get_real_jid(jid, account)
|
||||
|
||||
if account:
|
||||
accounts = [account]
|
||||
else:
|
||||
|
@ -315,11 +318,11 @@ class SignalObject(DbusPrototype):
|
|||
connected_account = acct
|
||||
elif first_connected_acct is None:
|
||||
first_connected_acct = acct
|
||||
|
||||
|
||||
# if jid is not a conntact, open-chat with first connected account
|
||||
if connected_account is None and first_connected_acct:
|
||||
connected_account = first_connected_acct
|
||||
|
||||
|
||||
if connected_account:
|
||||
gajim.interface.roster.new_chat_from_jid(connected_account, jid)
|
||||
# preserve the 'steal focus preservation'
|
||||
|
@ -328,7 +331,7 @@ class SignalObject(DbusPrototype):
|
|||
win.window.focus()
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def change_status(self, *args, **keywords):
|
||||
''' change_status(status, message, account). account is optional -
|
||||
if not specified status is changed for all accounts. '''
|
||||
|
@ -346,13 +349,12 @@ class SignalObject(DbusPrototype):
|
|||
gobject.idle_add(gajim.interface.roster.send_status, acc,
|
||||
status, message)
|
||||
return None
|
||||
|
||||
|
||||
def show_next_unread(self, *args):
|
||||
''' Show the window(s) with next waiting messages in tabbed/group chats. '''
|
||||
#FIXME: when systray is disabled this method does nothing.
|
||||
if len(gajim.interface.systray.jids) != 0:
|
||||
if gajim.events.get_nb_events():
|
||||
gajim.interface.systray.handle_first_event()
|
||||
|
||||
|
||||
def contact_info(self, *args):
|
||||
''' get vcard info for a contact. Return cached value of the vcard.
|
||||
'''
|
||||
|
@ -362,14 +364,15 @@ class SignalObject(DbusPrototype):
|
|||
if not jid:
|
||||
# FIXME: raise exception for missing argument (0.3+)
|
||||
return None
|
||||
|
||||
jid = self._get_real_jid(jid, account)
|
||||
|
||||
cached_vcard = gajim.connections.values()[0].get_cached_vcard(jid)
|
||||
if cached_vcard:
|
||||
return get_dbus_struct(cached_vcard)
|
||||
|
||||
|
||||
# return empty dict
|
||||
return DBUS_DICT_SV()
|
||||
|
||||
|
||||
def list_accounts(self, *args):
|
||||
''' list register accounts '''
|
||||
result = gajim.contacts.get_accounts()
|
||||
|
@ -379,7 +382,7 @@ class SignalObject(DbusPrototype):
|
|||
result_array.append(DBUS_STRING(account))
|
||||
return result_array
|
||||
return None
|
||||
|
||||
|
||||
def account_info(self, *args):
|
||||
''' show info on account: resource, jid, nick, prio, message '''
|
||||
[for_account] = self._get_real_arguments(args, 1)
|
||||
|
@ -398,7 +401,7 @@ class SignalObject(DbusPrototype):
|
|||
result['resource'] = DBUS_STRING(unicode(gajim.config.get_per('accounts',
|
||||
account.name, 'resource')))
|
||||
return result
|
||||
|
||||
|
||||
def list_contacts(self, *args):
|
||||
''' list all contacts in the roster. If the first argument is specified,
|
||||
then return the contacts for the specified account '''
|
||||
|
@ -422,7 +425,7 @@ class SignalObject(DbusPrototype):
|
|||
if result == []:
|
||||
return None
|
||||
return result
|
||||
|
||||
|
||||
def toggle_roster_appearance(self, *args):
|
||||
''' shows/hides the roster window '''
|
||||
win = gajim.interface.roster.window
|
||||
|
@ -449,14 +452,14 @@ class SignalObject(DbusPrototype):
|
|||
prefs_dict[DBUS_STRING(key)] = DBUS_STRING(value[1])
|
||||
gajim.config.foreach(get_prefs)
|
||||
return prefs_dict
|
||||
|
||||
|
||||
def prefs_store(self, *args):
|
||||
try:
|
||||
gajim.interface.save_config()
|
||||
except Exception, e:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def prefs_del(self, *args):
|
||||
[key] = self._get_real_arguments(args, 1)
|
||||
if not key:
|
||||
|
@ -469,7 +472,7 @@ class SignalObject(DbusPrototype):
|
|||
else:
|
||||
gajim.config.del_per(key_path[0], key_path[1], key_path[2])
|
||||
return True
|
||||
|
||||
|
||||
def prefs_put(self, *args):
|
||||
[key] = self._get_real_arguments(args, 1)
|
||||
if not key:
|
||||
|
@ -482,7 +485,7 @@ class SignalObject(DbusPrototype):
|
|||
subname, value = key_path[2].split('=', 1)
|
||||
gajim.config.set_per(key_path[0], key_path[1], subname, value)
|
||||
return True
|
||||
|
||||
|
||||
def add_contact(self, *args):
|
||||
[jid, account] = self._get_real_arguments(args, 2)
|
||||
if account:
|
||||
|
@ -497,11 +500,12 @@ class SignalObject(DbusPrototype):
|
|||
# if account is not given, show account combobox
|
||||
AddNewContactWindow(account = None, jid = jid)
|
||||
return True
|
||||
|
||||
|
||||
def remove_contact(self, *args):
|
||||
[jid, account] = self._get_real_arguments(args, 2)
|
||||
jid = self._get_real_jid(jid, account)
|
||||
accounts = gajim.contacts.get_accounts()
|
||||
|
||||
|
||||
# if there is only one account in roster, take it as default
|
||||
if account:
|
||||
accounts = [account]
|
||||
|
@ -515,7 +519,7 @@ class SignalObject(DbusPrototype):
|
|||
gajim.contacts.remove_jid(account, jid)
|
||||
contact_exists = True
|
||||
return contact_exists
|
||||
|
||||
|
||||
def _is_first(self):
|
||||
if self.first_show:
|
||||
self.first_show = False
|
||||
|
@ -535,7 +539,35 @@ class SignalObject(DbusPrototype):
|
|||
args.extend([None] * (desired_length - len(args)))
|
||||
args = args[:desired_length]
|
||||
return args
|
||||
|
||||
|
||||
def _get_real_jid(self, jid, account = None):
|
||||
'''get the real jid from the given one: removes xmpp: or get jid from nick
|
||||
if account is specified, search only in this account
|
||||
'''
|
||||
if account:
|
||||
accounts = [account]
|
||||
else:
|
||||
accounts = gajim.connections.keys()
|
||||
if jid.startswith('xmpp:'):
|
||||
return jid[5:] # len('xmpp:') = 5
|
||||
nick_in_roster = None # Is jid a nick ?
|
||||
for account in accounts:
|
||||
# Does jid exists in roster of one account ?
|
||||
if gajim.contacts.get_contacts_from_jid(account, jid):
|
||||
return jid
|
||||
if not nick_in_roster:
|
||||
# look in all contact if one has jid as nick
|
||||
for jid_ in gajim.contacts.get_jid_list(account):
|
||||
c = gajim.contacts.get_contacts_from_jid(account, jid_)
|
||||
if c[0].name == jid:
|
||||
nick_in_roster = jid_
|
||||
break
|
||||
if nick_in_roster:
|
||||
# We have not found jid in roster, but we found is as a nick
|
||||
return nick_in_roster
|
||||
# We have not found it as jid nor as nick, probably a not in roster jid
|
||||
return jid
|
||||
|
||||
def _contacts_as_dbus_structure(self, contacts):
|
||||
''' get info from list of Contact objects and create dbus dict '''
|
||||
if not contacts:
|
||||
|
@ -564,7 +596,7 @@ class SignalObject(DbusPrototype):
|
|||
return contact_dict
|
||||
|
||||
def get_unread_msgs_number(self, *args):
|
||||
return str(gajim.interface.roster.nb_unread)
|
||||
return str(gajim.events.get_nb_events)
|
||||
|
||||
def start_chat(self, *args):
|
||||
[account] = self._get_real_arguments(args, 1)
|
||||
|
@ -574,13 +606,21 @@ class SignalObject(DbusPrototype):
|
|||
NewChatDialog(account)
|
||||
return True
|
||||
|
||||
def send_xml(self, *args):
|
||||
xml, account = self._get_real_arguments(args, 2)
|
||||
if account:
|
||||
gajim.connections[account[0]].send_stanza(xml)
|
||||
else:
|
||||
for acc in gajim.contacts.get_accounts():
|
||||
gajim.connections[acc].send_stanza(xml)
|
||||
|
||||
if dbus_support.version[1] >= 30 and dbus_support.version[1] <= 40:
|
||||
method = dbus.method
|
||||
signal = dbus.signal
|
||||
elif dbus_support.version[1] >= 41:
|
||||
method = dbus.service.method
|
||||
signal = dbus.service.signal
|
||||
|
||||
|
||||
# prevent using decorators, because they are not supported
|
||||
# on python < 2.4
|
||||
# FIXME: use decorators when python2.3 (and dbus 0.23) is OOOOOOLD
|
||||
|
@ -605,3 +645,4 @@ class SignalObject(DbusPrototype):
|
|||
account_info = method(INTERFACE)(account_info)
|
||||
get_unread_msgs_number = method(INTERFACE)(get_unread_msgs_number)
|
||||
start_chat = method(INTERFACE)(start_chat)
|
||||
send_xml = method(INTERFACE)(send_xml)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
##
|
||||
## Copyright (C) 2003-2006 Yann Le Boulanger <asterix@lagaule.org>
|
||||
## Copyright (C) 2003-2004 Vincent Hanquez <tab@snarc.org>
|
||||
## Copyright (C) 2005-2006 Nikos Kouremenos <nkour@jabber.org>
|
||||
## Copyright (C) 2005-2006 Nikos Kouremenos <kourem@gmail.com>
|
||||
## Copyright (C) 2005 Dimitur Kirov <dkirov@gmail.com>
|
||||
## Copyright (C) 2005-2006 Travis Shirk <travis@pobox.com>
|
||||
## Copyright (C) 2005 Norman Rasmussen <norman@rasmussen.co.za>
|
||||
|
@ -45,9 +45,8 @@ class Systray:
|
|||
'''Class for icon in the notification area
|
||||
This class is both base class (for systraywin32.py) and normal class
|
||||
for trayicon in GNU/Linux'''
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.jids = [] # Contain things like [account, jid, type_of_msg]
|
||||
self.single_message_handler_id = None
|
||||
self.new_chat_handler_id = None
|
||||
self.t = None
|
||||
|
@ -59,7 +58,9 @@ class Systray:
|
|||
self.popup_menus = []
|
||||
|
||||
def set_img(self):
|
||||
if len(self.jids) > 0:
|
||||
if not gajim.interface.systray_enabled:
|
||||
return
|
||||
if gajim.events.get_nb_systray_events():
|
||||
state = 'message'
|
||||
else:
|
||||
state = self.status
|
||||
|
@ -69,26 +70,13 @@ class Systray:
|
|||
elif image.get_storage_type() == gtk.IMAGE_PIXBUF:
|
||||
self.img_tray.set_from_pixbuf(image.get_pixbuf())
|
||||
|
||||
def add_jid(self, jid, account, typ):
|
||||
l = [account, jid, typ]
|
||||
# We can keep several single message 'cause we open them one by one
|
||||
if not l in self.jids or typ == 'normal':
|
||||
self.jids.append(l)
|
||||
self.set_img()
|
||||
|
||||
def remove_jid(self, jid, account, typ):
|
||||
l = [account, jid, typ]
|
||||
if l in self.jids:
|
||||
self.jids.remove(l)
|
||||
self.set_img()
|
||||
|
||||
def change_status(self, global_status):
|
||||
''' set tray image to 'global_status' '''
|
||||
# change image and status, only if it is different
|
||||
if global_status is not None and self.status != global_status:
|
||||
self.status = global_status
|
||||
self.set_img()
|
||||
|
||||
|
||||
def start_chat(self, widget, account, jid):
|
||||
contact = gajim.contacts.get_first_contact_from_jid(account, jid)
|
||||
if gajim.interface.msg_win_mgr.has_window(jid, account):
|
||||
|
@ -99,13 +87,13 @@ class Systray:
|
|||
gajim.interface.roster.new_chat(contact, account)
|
||||
gajim.interface.msg_win_mgr.get_window(jid, account).set_active_tab(
|
||||
jid, account)
|
||||
|
||||
|
||||
def on_single_message_menuitem_activate(self, widget, account):
|
||||
dialogs.SingleMessageWindow(account, action = 'send')
|
||||
|
||||
def on_new_chat(self, widget, account):
|
||||
dialogs.NewChatDialog(account)
|
||||
|
||||
|
||||
def make_menu(self, event = None):
|
||||
'''create chat with and new message (sub) menus/menuitems
|
||||
event is None when we're in Windows
|
||||
|
@ -118,7 +106,7 @@ class Systray:
|
|||
single_message_menuitem = self.xml.get_widget('single_message_menuitem')
|
||||
status_menuitem = self.xml.get_widget('status_menu')
|
||||
join_gc_menuitem = self.xml.get_widget('join_gc_menuitem')
|
||||
|
||||
|
||||
if self.single_message_handler_id:
|
||||
single_message_menuitem.handler_disconnect(
|
||||
self.single_message_handler_id)
|
||||
|
@ -130,7 +118,7 @@ class Systray:
|
|||
sub_menu = gtk.Menu()
|
||||
self.popup_menus.append(sub_menu)
|
||||
status_menuitem.set_submenu(sub_menu)
|
||||
|
||||
|
||||
gc_sub_menu = gtk.Menu() # gc is always a submenu
|
||||
join_gc_menuitem.set_submenu(gc_sub_menu)
|
||||
|
||||
|
@ -175,7 +163,7 @@ class Systray:
|
|||
chat_with_menuitem.set_sensitive(iskey)
|
||||
single_message_menuitem.set_sensitive(iskey)
|
||||
join_gc_menuitem.set_sensitive(iskey)
|
||||
|
||||
|
||||
if connected_accounts >= 2: # 2 or more connections? make submenus
|
||||
account_menu_for_chat_with = gtk.Menu()
|
||||
chat_with_menuitem.set_submenu(account_menu_for_chat_with)
|
||||
|
@ -184,7 +172,7 @@ class Systray:
|
|||
account_menu_for_single_message = gtk.Menu()
|
||||
single_message_menuitem.set_submenu(account_menu_for_single_message)
|
||||
self.popup_menus.append(account_menu_for_single_message)
|
||||
|
||||
|
||||
accounts_list = gajim.contacts.get_accounts()
|
||||
accounts_list.sort()
|
||||
for account in accounts_list:
|
||||
|
@ -208,7 +196,7 @@ class Systray:
|
|||
gc_item.add(label)
|
||||
gc_sub_menu.append(gc_item)
|
||||
gajim.interface.roster.add_bookmarks_list(gc_sub_menu, account)
|
||||
|
||||
|
||||
elif connected_accounts == 1: # one account
|
||||
# one account connected, no need to show 'as jid'
|
||||
for account in gajim.connections:
|
||||
|
@ -223,7 +211,7 @@ class Systray:
|
|||
# join gc
|
||||
gajim.interface.roster.add_bookmarks_list(gc_sub_menu, account)
|
||||
break # No other connected account
|
||||
|
||||
|
||||
if event is None:
|
||||
# None means windows (we explicitly popup in systraywin32.py)
|
||||
if self.added_hide_menuitem is False:
|
||||
|
@ -231,14 +219,18 @@ class Systray:
|
|||
item = gtk.MenuItem(_('Hide this menu'))
|
||||
self.systray_context_menu.prepend(item)
|
||||
self.added_hide_menuitem = True
|
||||
|
||||
|
||||
else: # GNU and Unices
|
||||
self.systray_context_menu.popup(None, None, None, event.button, event.time)
|
||||
self.systray_context_menu.popup(None, None, None, event.button,
|
||||
event.time)
|
||||
self.systray_context_menu.show_all()
|
||||
|
||||
def on_show_all_events_menuitem_activate(self, widget):
|
||||
for i in range(len(self.jids)):
|
||||
self.handle_first_event()
|
||||
events = gajim.events.get_systray_events()
|
||||
for account in events:
|
||||
for jid in events[account]:
|
||||
for event in events[account][jid]:
|
||||
gajim.interface.handle_event(account, jid, event.type_)
|
||||
|
||||
def on_show_roster_menuitem_activate(self, widget):
|
||||
win = gajim.interface.roster.window
|
||||
|
@ -255,11 +247,11 @@ class Systray:
|
|||
|
||||
def on_left_click(self):
|
||||
win = gajim.interface.roster.window
|
||||
if len(self.jids) == 0:
|
||||
if len(gajim.events.get_systray_events()) == 0:
|
||||
# no pending events, so toggle visible/hidden for roster window
|
||||
if win.get_property('visible'): # visible in ANY virtual desktop?
|
||||
win.hide() # we hide it from VD that was visible in
|
||||
|
||||
|
||||
# but we could be in another VD right now. eg vd2
|
||||
# and we want not only to hide it in vd1 but also show it in vd2
|
||||
gtkgui_helpers.possibly_move_window_in_current_desktop(win)
|
||||
|
@ -269,10 +261,8 @@ class Systray:
|
|||
self.handle_first_event()
|
||||
|
||||
def handle_first_event(self):
|
||||
account = self.jids[0][0]
|
||||
jid = self.jids[0][1]
|
||||
typ = self.jids[0][2]
|
||||
gajim.interface.handle_event(account, jid, typ)
|
||||
account, jid, event = gajim.events.get_first_systray_event()
|
||||
gajim.interface.handle_event(account, jid, event.type_)
|
||||
|
||||
def on_middle_click(self):
|
||||
'''middle click raises window to have complete focus (fe. get kbd events)
|
||||
|
@ -285,13 +275,13 @@ class Systray:
|
|||
|
||||
def on_clicked(self, widget, event):
|
||||
self.on_tray_leave_notify_event(widget, None)
|
||||
if event.button == 1: # Left click
|
||||
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1: # Left click
|
||||
self.on_left_click()
|
||||
elif event.button == 2: # middle click
|
||||
self.on_middle_click()
|
||||
elif event.button == 3: # right click
|
||||
self.make_menu(event)
|
||||
|
||||
|
||||
def on_show_menuitem_activate(self, widget, show):
|
||||
# we all add some fake (we cannot select those nor have them as show)
|
||||
# but this helps to align with roster's status_combobox index positions
|
||||
|
@ -320,7 +310,7 @@ class Systray:
|
|||
if self.tooltip.id == position:
|
||||
size = widget.window.get_size()
|
||||
self.tooltip.show_tooltip('', size[1], position[1])
|
||||
|
||||
|
||||
def on_tray_motion_notify_event(self, widget, event):
|
||||
wireq=widget.size_request()
|
||||
position = widget.window.get_origin()
|
||||
|
@ -332,16 +322,23 @@ class Systray:
|
|||
self.tooltip.id = position
|
||||
self.tooltip.timeout = gobject.timeout_add(500,
|
||||
self.show_tooltip, widget)
|
||||
|
||||
|
||||
def on_tray_leave_notify_event(self, widget, event):
|
||||
position = widget.window.get_origin()
|
||||
if self.tooltip.timeout > 0 and \
|
||||
self.tooltip.id == position:
|
||||
self.tooltip.hide_tooltip()
|
||||
|
||||
|
||||
def on_tray_destroyed(self, widget):
|
||||
'''re-add trayicon when systray is destroyed'''
|
||||
self.t = None
|
||||
if gajim.interface.systray_enabled:
|
||||
self.show_icon()
|
||||
|
||||
def show_icon(self):
|
||||
if not self.t:
|
||||
self.t = trayicon.TrayIcon('Gajim')
|
||||
self.t.connect('destroy', self.on_tray_destroyed)
|
||||
eb = gtk.EventBox()
|
||||
# avoid draw seperate bg color in some gtk themes
|
||||
eb.set_visible_window(False)
|
||||
|
@ -356,7 +353,7 @@ class Systray:
|
|||
self.t.add(eb)
|
||||
self.set_img()
|
||||
self.t.show_all()
|
||||
|
||||
|
||||
def hide_icon(self):
|
||||
if self.t:
|
||||
self.t.destroy()
|
||||
|
|
|
@ -245,36 +245,25 @@ class SystrayWin32(systray.Systray):
|
|||
elif lparam == win32con.WM_LBUTTONUP: # Left click
|
||||
self.on_left_click()
|
||||
|
||||
def add_jid(self, jid, account, typ):
|
||||
systray.Systray.add_jid(self, jid, account, typ)
|
||||
def set_img(self):
|
||||
self.tray_ico_imgs = self.load_icos() #FIXME: do not do this here
|
||||
# see gajim.interface.roster.reload_jabber_state_images() to merge
|
||||
|
||||
nb = gajim.interface.roster.nb_unread
|
||||
for acct in gajim.connections:
|
||||
# in chat / groupchat windows
|
||||
for kind in ('chats', 'gc'):
|
||||
jids = gajim.interface.instances[acct][kind]
|
||||
for jid in jids:
|
||||
if jid != 'tabbed':
|
||||
nb += jids[jid].nb_unread[jid]
|
||||
|
||||
text = i18n.ngettext(
|
||||
'Gajim - %d unread message',
|
||||
'Gajim - %d unread messages',
|
||||
nb, nb, nb)
|
||||
if len(self.jids) > 0:
|
||||
state = 'message'
|
||||
else:
|
||||
state = self.status
|
||||
hicon = self.tray_ico_imgs[state]
|
||||
if hicon is None:
|
||||
return
|
||||
|
||||
self.systray_winapi.notify_icon.set_tooltip(text)
|
||||
self.systray_winapi.remove_notify_icon()
|
||||
self.systray_winapi.add_notify_icon(self.systray_context_menu, hicon,
|
||||
'Gajim')
|
||||
self.systray_winapi.notify_icon.menu = self.systray_context_menu
|
||||
|
||||
def remove_jid(self, jid, account, typ):
|
||||
systray.Systray.remove_jid(self, jid, account, typ)
|
||||
nb = gajim.events.get_nb_systray_events()
|
||||
|
||||
nb = gajim.interface.roster.nb_unread
|
||||
for acct in gajim.connections:
|
||||
# in chat / groupchat windows
|
||||
for kind in ('chats', 'gc'):
|
||||
for jid in gajim.interface.instances[acct][kind]:
|
||||
if jid != 'tabbed':
|
||||
nb += gajim.interface.instances[acct][kind][jid].nb_unread[jid]
|
||||
|
||||
if nb > 0:
|
||||
text = i18n.ngettext(
|
||||
'Gajim - %d unread message',
|
||||
|
@ -284,23 +273,6 @@ class SystrayWin32(systray.Systray):
|
|||
text = 'Gajim'
|
||||
self.systray_winapi.notify_icon.set_tooltip(text)
|
||||
|
||||
def set_img(self):
|
||||
self.tray_ico_imgs = self.load_icos() #FIXME: do not do this here
|
||||
# see gajim.interface.roster.reload_jabber_state_images() to merge
|
||||
|
||||
if len(self.jids) > 0:
|
||||
state = 'message'
|
||||
else:
|
||||
state = self.status
|
||||
hicon = self.tray_ico_imgs[state]
|
||||
if hicon is None:
|
||||
return
|
||||
|
||||
self.systray_winapi.remove_notify_icon()
|
||||
self.systray_winapi.add_notify_icon(self.systray_context_menu, hicon,
|
||||
'Gajim')
|
||||
self.systray_winapi.notify_icon.menu = self.systray_context_menu
|
||||
|
||||
def load_icos(self):
|
||||
'''load .ico files and return them to a dic of SHOW --> img_obj'''
|
||||
iconset = str(gajim.config.get('iconset'))
|
||||
|
|
|
@ -282,34 +282,14 @@ class NotificationAreaTooltip(BaseTooltip, StatusTable):
|
|||
self.table.set_property('column-spacing', 1)
|
||||
text, single_line = '', ''
|
||||
|
||||
unread_chat = gajim.interface.roster.nb_unread
|
||||
unread_single_chat = 0
|
||||
unread_gc = 0
|
||||
unread_pm = 0
|
||||
unread_chat = gajim.events.get_nb_events(types = ['printed_chat', 'chat'])
|
||||
unread_single_chat = gajim.events.get_nb_events(types = ['normal'])
|
||||
unread_gc = gajim.events.get_nb_events(types = ['printed_gc_msg',
|
||||
'gc_msg'])
|
||||
unread_pm = gajim.events.get_nb_events(types = ['printed_pm', 'pm'])
|
||||
|
||||
accounts = self.get_accounts_info()
|
||||
|
||||
for acct in gajim.connections:
|
||||
# Count unread chat messages
|
||||
chat_t = message_control.TYPE_CHAT
|
||||
for ctrl in gajim.interface.msg_win_mgr.get_controls(chat_t, acct):
|
||||
unread_chat += ctrl.nb_unread
|
||||
|
||||
# Count unread PM messages for which we have a control
|
||||
chat_t = message_control.TYPE_PM
|
||||
for ctrl in gajim.interface.msg_win_mgr.get_controls(chat_t, acct):
|
||||
unread_pm += ctrl.nb_unread
|
||||
|
||||
# we count unread gc/pm messages
|
||||
chat_t = message_control.TYPE_GC
|
||||
for ctrl in gajim.interface.msg_win_mgr.get_controls(chat_t, acct):
|
||||
# These are PMs for which the PrivateChatControl has not yet been
|
||||
# created
|
||||
pm_msgs = ctrl.get_specific_unread()
|
||||
unread_gc += ctrl.nb_unread
|
||||
unread_gc -= pm_msgs
|
||||
unread_pm += pm_msgs
|
||||
|
||||
if unread_chat or unread_single_chat or unread_gc or unread_pm:
|
||||
text = 'Gajim '
|
||||
awaiting_events = unread_chat + unread_single_chat + unread_gc + unread_pm
|
||||
|
@ -508,8 +488,9 @@ class RosterTooltip(NotificationAreaTooltip):
|
|||
properties = []
|
||||
jid_markup = '<span weight="bold">' + prim_contact.jid + '</span>'
|
||||
properties.append((jid_markup, None))
|
||||
|
||||
properties.append((_('Name: '), gtkgui_helpers.escape_for_pango_markup(
|
||||
prim_contact.get_shown_name())))
|
||||
prim_contact.get_shown_name())))
|
||||
if prim_contact.sub:
|
||||
properties.append(( _('Subscription: '),
|
||||
gtkgui_helpers.escape_for_pango_markup(helpers.get_uf_sub(prim_contact.sub))))
|
||||
|
@ -532,10 +513,11 @@ class RosterTooltip(NotificationAreaTooltip):
|
|||
contacts_dict[contact.priority].append(contact)
|
||||
else:
|
||||
contacts_dict[contact.priority] = [contact]
|
||||
|
||||
if num_resources== 1 and contact.resource:
|
||||
properties.append((_('Resource: '), gtkgui_helpers.escape_for_pango_markup(
|
||||
contact.resource) + ' (' + unicode(contact.priority) + ')'))
|
||||
|
||||
if num_resources == 1 and contact.resource:
|
||||
properties.append((_('Resource: '),
|
||||
gtkgui_helpers.escape_for_pango_markup(contact.resource) + ' (' + \
|
||||
unicode(contact.priority) + ')'))
|
||||
if num_resources > 1:
|
||||
properties.append((_('Status: '), ' '))
|
||||
contact_keys = contacts_dict.keys()
|
||||
|
|
283
src/vcard.py
|
@ -57,51 +57,25 @@ def get_avatar_pixbuf_encoded_mime(photo):
|
|||
class VcardWindow:
|
||||
'''Class for contact's information window'''
|
||||
|
||||
def __init__(self, contact, account, vcard = False, is_fake = False):
|
||||
def __init__(self, contact, account, is_fake = False):
|
||||
# the contact variable is the jid if vcard is true
|
||||
self.xml = gtkgui_helpers.get_glade('vcard_information_window.glade')
|
||||
self.window = self.xml.get_widget('vcard_information_window')
|
||||
|
||||
self.publish_button = self.xml.get_widget('publish_button')
|
||||
self.retrieve_button = self.xml.get_widget('retrieve_button')
|
||||
self.nickname_entry = self.xml.get_widget('nickname_entry')
|
||||
if not vcard: # Maybe gc_vcard ?
|
||||
self.nickname_entry.set_property('editable', False)
|
||||
|
||||
self.publish_button.set_no_show_all(True)
|
||||
self.retrieve_button.set_no_show_all(True)
|
||||
self.xml.get_widget('photo_vbuttonbox').set_no_show_all(True)
|
||||
|
||||
self.contact = contact # don't use it if vcard is true
|
||||
self.contact = contact
|
||||
self.account = account
|
||||
self.vcard = vcard
|
||||
self.is_fake = is_fake
|
||||
|
||||
self.avatar_mime_type = None
|
||||
self.avatar_encoded = None
|
||||
self.avatar_save_as_id = None
|
||||
|
||||
if vcard: # we view/edit our own vcard
|
||||
self.jid = contact
|
||||
# remove Jabber tab & show publish/retrieve/close/set_avatar buttons
|
||||
# and make entries and textview editable
|
||||
self.change_to_vcard()
|
||||
else: # we see someone else's vcard
|
||||
self.publish_button.hide()
|
||||
self.retrieve_button.hide()
|
||||
self.jid = contact.jid
|
||||
self.fill_jabber_page()
|
||||
|
||||
# if we are editing our own vcard publish button should publish
|
||||
# vcard data we have typed including nickname, it's why we connect only
|
||||
# here (when we see someone else's vcard)
|
||||
self.nickname_entry.connect('focus-out-event',
|
||||
self.on_nickname_entry_focus_out_event)
|
||||
self.fill_jabber_page()
|
||||
|
||||
self.xml.signal_autoconnect(self)
|
||||
self.window.show_all()
|
||||
|
||||
def on_vcard_information_window_destroy(self, widget):
|
||||
del gajim.interface.instances[self.account]['infos'][self.jid]
|
||||
del gajim.interface.instances[self.account]['infos'][self.contact.jid]
|
||||
|
||||
def on_vcard_information_window_key_press_event(self, widget, event):
|
||||
if event.keyval == gtk.keysyms.Escape:
|
||||
|
@ -122,108 +96,16 @@ class VcardWindow:
|
|||
if oldlog != log:
|
||||
gajim.config.set_per('accounts', self.account, 'no_log_for',
|
||||
' '.join(no_log_for))
|
||||
|
||||
def on_nickname_entry_focus_out_event(self, widget, event):
|
||||
'''Save contact information and update
|
||||
the roster item on the Jabber server'''
|
||||
new_name = self.nickname_entry.get_text().decode('utf-8')
|
||||
# update contact.name with new nickname if that is not ''
|
||||
if new_name != self.contact.name and new_name != '':
|
||||
self.contact.name = new_name
|
||||
# update roster model
|
||||
model = gajim.interface.roster.tree.get_model()
|
||||
for iter_ in gajim.interface.roster.get_contact_iter(self.contact.jid,
|
||||
self.account):
|
||||
model[iter_][1] = new_name
|
||||
gajim.connections[self.account].update_contact(self.contact.jid,
|
||||
self.contact.name, self.contact.groups)
|
||||
# update opened chat window
|
||||
ctrl = gajim.interface.msg_win_mgr.get_control(self.contact.jid,
|
||||
self.account)
|
||||
if ctrl:
|
||||
ctrl.update_ui()
|
||||
win = gajim.interface.msg_win_mgr.get_window(self.contact.jid,
|
||||
self.account)
|
||||
win.redraw_tab(ctrl)
|
||||
win.show_title()
|
||||
|
||||
def on_close_button_clicked(self, widget):
|
||||
self.window.destroy()
|
||||
|
||||
def on_clear_button_clicked(self, widget):
|
||||
# empty the image
|
||||
self.xml.get_widget('PHOTO_image').set_from_pixbuf(None)
|
||||
self.avatar_encoded = None
|
||||
if self.avatar_save_as_id:
|
||||
self.xml.get_widget('PHOTO_eventbox').disconnect(
|
||||
self.avatar_save_as_id)
|
||||
self.avatar_save_as_id = None
|
||||
|
||||
def on_set_avatar_button_clicked(self, widget):
|
||||
f = None
|
||||
def on_ok(widget, path_to_file):
|
||||
filesize = os.path.getsize(path_to_file) # in bytes
|
||||
#FIXME: use messages for invalid file for 0.11
|
||||
invalid_file = False
|
||||
msg = ''
|
||||
if os.path.isfile(path_to_file):
|
||||
stat = os.stat(path_to_file)
|
||||
if stat[6] == 0:
|
||||
invalid_file = True
|
||||
else:
|
||||
invalid_file = True
|
||||
if not invalid_file and filesize > 16384: # 16 kb
|
||||
try:
|
||||
pixbuf = gtk.gdk.pixbuf_new_from_file(path_to_file)
|
||||
# get the image at 'notification size'
|
||||
# and use that user did not specify in ACE crazy size
|
||||
scaled_pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf,
|
||||
'tooltip')
|
||||
except gobject.GError, msg: # unknown format
|
||||
# msg should be string, not object instance
|
||||
msg = str(msg)
|
||||
invalid_file = True
|
||||
if invalid_file:
|
||||
if True: # keep identation
|
||||
dialogs.ErrorDialog(_('Could not load image'), msg)
|
||||
return
|
||||
if filesize > 16384:
|
||||
if scaled_pixbuf:
|
||||
path_to_file = os.path.join(gajim.TMP,
|
||||
'avatar_scaled.png')
|
||||
scaled_pixbuf.save(path_to_file, 'png')
|
||||
self.dialog.destroy()
|
||||
|
||||
fd = open(path_to_file, 'rb')
|
||||
data = fd.read()
|
||||
pixbuf = gtkgui_helpers.get_pixbuf_from_data(data)
|
||||
# rescale it
|
||||
pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf, 'vcard')
|
||||
image = self.xml.get_widget('PHOTO_image')
|
||||
image.set_from_pixbuf(pixbuf)
|
||||
self.avatar_encoded = base64.encodestring(data)
|
||||
# returns None if unknown type
|
||||
self.avatar_mime_type = mimetypes.guess_type(path_to_file)[0]
|
||||
|
||||
self.dialog = dialogs.ImageChooserDialog(on_response_ok = on_ok)
|
||||
|
||||
def on_PHOTO_eventbox_button_press_event(self, widget, event):
|
||||
'''If right-clicked, show popup'''
|
||||
if event.button == 3: # right click
|
||||
if self.vcard:
|
||||
# our own avatar
|
||||
account = None
|
||||
nick = gajim.config.get_per('accounts', self.account, 'name')
|
||||
else:
|
||||
account = self.account
|
||||
nick = self.contact.name
|
||||
menu = gtk.Menu()
|
||||
menuitem = gtk.ImageMenuItem(gtk.STOCK_SAVE_AS)
|
||||
menuitem.connect('activate',
|
||||
gtkgui_helpers.on_avatar_save_as_menuitem_activate,
|
||||
self.jid, account, nick + '.jpeg')
|
||||
self.contact.jid, self.account, self.contact.name + '.jpeg')
|
||||
menu.append(menuitem)
|
||||
menu.show_all()
|
||||
menu.connect('selection-done', lambda w:w.destroy())
|
||||
# show the menu
|
||||
menu.show_all()
|
||||
|
@ -240,14 +122,13 @@ class VcardWindow:
|
|||
if i == 'PHOTO':
|
||||
pixbuf, self.avatar_encoded, self.avatar_mime_type = \
|
||||
get_avatar_pixbuf_encoded_mime(vcard[i])
|
||||
if not pixbuf:
|
||||
continue
|
||||
image = self.xml.get_widget('PHOTO_image')
|
||||
if not pixbuf:
|
||||
image.set_from_icon_name('stock_person',
|
||||
gtk.ICON_SIZE_DIALOG)
|
||||
continue
|
||||
pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf, 'vcard')
|
||||
image.set_from_pixbuf(pixbuf)
|
||||
eventbox = self.xml.get_widget('PHOTO_eventbox')
|
||||
self.avatar_save_as_id = eventbox.connect('button-press-event',
|
||||
self.on_PHOTO_eventbox_button_press_event)
|
||||
continue
|
||||
if i == 'ADR' or i == 'TEL' or i == 'EMAIL':
|
||||
for entry in vcard[i]:
|
||||
|
@ -255,22 +136,22 @@ class VcardWindow:
|
|||
if 'WORK' in entry:
|
||||
add_on = '_WORK'
|
||||
for j in entry.keys():
|
||||
self.set_value(i + add_on + '_' + j + '_entry', entry[j])
|
||||
self.set_value(i + add_on + '_' + j + '_label', entry[j])
|
||||
if isinstance(vcard[i], dict):
|
||||
for j in vcard[i].keys():
|
||||
self.set_value(i + '_' + j + '_entry', vcard[i][j])
|
||||
self.set_value(i + '_' + j + '_label', vcard[i][j])
|
||||
else:
|
||||
if i == 'DESC':
|
||||
self.xml.get_widget('DESC_textview').get_buffer().set_text(
|
||||
vcard[i], 0)
|
||||
else:
|
||||
self.set_value(i + '_entry', vcard[i])
|
||||
self.set_value(i + '_label', vcard[i])
|
||||
|
||||
def set_last_status_time(self):
|
||||
self.fill_status_label()
|
||||
|
||||
def set_os_info(self, resource, client_info, os_info):
|
||||
if self.xml.get_widget('information_notebook').get_n_pages() < 5:
|
||||
if self.xml.get_widget('information_notebook').get_n_pages() < 4:
|
||||
return
|
||||
i = 0
|
||||
client = ''
|
||||
|
@ -295,7 +176,7 @@ class VcardWindow:
|
|||
self.xml.get_widget('os_label').set_text(os)
|
||||
|
||||
def fill_status_label(self):
|
||||
if self.xml.get_widget('information_notebook').get_n_pages() < 5:
|
||||
if self.xml.get_widget('information_notebook').get_n_pages() < 4:
|
||||
return
|
||||
contact_list = gajim.contacts.get_contact(self.account, self.contact.jid)
|
||||
# stats holds show and status message
|
||||
|
@ -312,7 +193,7 @@ class VcardWindow:
|
|||
stats += '\n' + _('since %s') % time.strftime('%c',
|
||||
c.last_status_time).decode(locale.getpreferredencoding())
|
||||
one = False
|
||||
elif not self.vcard: # Maybe gc_vcard ?
|
||||
else: # Maybe gc_vcard ?
|
||||
stats = helpers.get_uf_show(self.contact.show)
|
||||
if self.contact.status:
|
||||
stats += ': ' + self.contact.status
|
||||
|
@ -326,8 +207,10 @@ class VcardWindow:
|
|||
|
||||
def fill_jabber_page(self):
|
||||
tooltips = gtk.Tooltips()
|
||||
self.xml.get_widget('nickname_label').set_text(
|
||||
self.contact.get_shown_name())
|
||||
self.xml.get_widget('nickname_label').set_markup(
|
||||
'<b><span size="x-large">' +
|
||||
self.contact.get_shown_name() +
|
||||
'</span></b>')
|
||||
self.xml.get_widget('jid_label').set_text(self.contact.jid)
|
||||
uf_sub = helpers.get_uf_sub(self.contact.sub)
|
||||
self.xml.get_widget('subscription_label').set_text(uf_sub)
|
||||
|
@ -349,7 +232,6 @@ class VcardWindow:
|
|||
if self.contact.ask == 'subscribe':
|
||||
tooltips.set_tip(eb,
|
||||
_("You are waiting contact's answer about your subscription request"))
|
||||
self.nickname_entry.set_text(self.contact.name)
|
||||
log = True
|
||||
if self.contact.jid in gajim.config.get_per('accounts', self.account,
|
||||
'no_log_for').split(' '):
|
||||
|
@ -371,8 +253,8 @@ class VcardWindow:
|
|||
|
||||
# Request os info in contact is connected
|
||||
if self.contact.show not in ('offline', 'error'):
|
||||
gajim.connections[self.account].request_os_info(self.contact.jid,
|
||||
self.contact.resource)
|
||||
gobject.idle_add(gajim.connections[self.account].request_os_info,
|
||||
self.contact.jid, self.contact.resource)
|
||||
self.os_info = {0: {'resource': self.contact.resource, 'client': '',
|
||||
'os': ''}}
|
||||
i = 1
|
||||
|
@ -385,7 +267,8 @@ class VcardWindow:
|
|||
uf_resources += '\n' + c.resource + \
|
||||
_(' resource with priority ') + unicode(c.priority)
|
||||
if c.show not in ('offline', 'error'):
|
||||
gajim.connections[self.account].request_os_info(c.jid,
|
||||
gobject.idle_add(
|
||||
gajim.connections[self.account].request_os_info, c.jid,
|
||||
c.resource)
|
||||
gajim.connections[self.account].request_last_status_time(c.jid,
|
||||
c.resource)
|
||||
|
@ -400,121 +283,3 @@ class VcardWindow:
|
|||
self.fill_status_label()
|
||||
|
||||
gajim.connections[self.account].request_vcard(self.contact.jid, self.is_fake)
|
||||
|
||||
def add_to_vcard(self, vcard, entry, txt):
|
||||
'''Add an information to the vCard dictionary'''
|
||||
entries = entry.split('_')
|
||||
loc = vcard
|
||||
if len(entries) == 3: # We need to use lists
|
||||
if not loc.has_key(entries[0]):
|
||||
loc[entries[0]] = []
|
||||
found = False
|
||||
for e in loc[entries[0]]:
|
||||
if entries[1] in e:
|
||||
found = True
|
||||
break
|
||||
if found:
|
||||
e[entries[2]] = txt
|
||||
else:
|
||||
loc[entries[0]].append({entries[1]: '', entries[2]: txt})
|
||||
return vcard
|
||||
while len(entries) > 1:
|
||||
if not loc.has_key(entries[0]):
|
||||
loc[entries[0]] = {}
|
||||
loc = loc[entries[0]]
|
||||
del entries[0]
|
||||
loc[entries[0]] = txt
|
||||
return vcard
|
||||
|
||||
def make_vcard(self):
|
||||
'''make the vCard dictionary'''
|
||||
entries = ['FN', 'NICKNAME', 'BDAY', 'EMAIL_HOME_USERID', 'URL',
|
||||
'TEL_HOME_NUMBER', 'N_FAMILY', 'N_GIVEN', 'N_MIDDLE', 'N_PREFIX',
|
||||
'N_SUFFIX', 'ADR_HOME_STREET', 'ADR_HOME_EXTADR', 'ADR_HOME_LOCALITY',
|
||||
'ADR_HOME_REGION', 'ADR_HOME_PCODE', 'ADR_HOME_CTRY', 'ORG_ORGNAME',
|
||||
'ORG_ORGUNIT', 'TITLE', 'ROLE', 'TEL_WORK_NUMBER', 'EMAIL_WORK_USERID',
|
||||
'ADR_WORK_STREET', 'ADR_WORK_EXTADR', 'ADR_WORK_LOCALITY',
|
||||
'ADR_WORK_REGION', 'ADR_WORK_PCODE', 'ADR_WORK_CTRY']
|
||||
vcard = {}
|
||||
for e in entries:
|
||||
txt = self.xml.get_widget(e + '_entry').get_text().decode('utf-8')
|
||||
if txt != '':
|
||||
vcard = self.add_to_vcard(vcard, e, txt)
|
||||
|
||||
# DESC textview
|
||||
buff = self.xml.get_widget('DESC_textview').get_buffer()
|
||||
start_iter = buff.get_start_iter()
|
||||
end_iter = buff.get_end_iter()
|
||||
txt = buff.get_text(start_iter, end_iter, 0)
|
||||
if txt != '':
|
||||
vcard['DESC'] = txt.decode('utf-8')
|
||||
|
||||
# Avatar
|
||||
if self.avatar_encoded:
|
||||
vcard['PHOTO'] = {'BINVAL': self.avatar_encoded}
|
||||
if self.avatar_mime_type:
|
||||
vcard['PHOTO']['TYPE'] = self.avatar_mime_type
|
||||
return vcard
|
||||
|
||||
def on_publish_button_clicked(self, widget):
|
||||
if gajim.connections[self.account].connected < 2:
|
||||
dialogs.ErrorDialog(_('You are not connected to the server'),
|
||||
_('Without a connection you can not publish your contact '
|
||||
'information.'))
|
||||
return
|
||||
vcard = self.make_vcard()
|
||||
nick = ''
|
||||
if vcard.has_key('NICKNAME'):
|
||||
nick = vcard['NICKNAME']
|
||||
if nick == '':
|
||||
nick = gajim.config.get_per('accounts', self.account, 'name')
|
||||
gajim.nicks[self.account] = nick
|
||||
gajim.connections[self.account].send_vcard(vcard)
|
||||
|
||||
def on_retrieve_button_clicked(self, widget):
|
||||
entries = ['FN', 'NICKNAME', 'BDAY', 'EMAIL_HOME_USERID', 'URL',
|
||||
'TEL_HOME_NUMBER', 'N_FAMILY', 'N_GIVEN', 'N_MIDDLE', 'N_PREFIX',
|
||||
'N_SUFFIX', 'ADR_HOME_STREET', 'ADR_HOME_EXTADR', 'ADR_HOME_LOCALITY',
|
||||
'ADR_HOME_REGION', 'ADR_HOME_PCODE', 'ADR_HOME_CTRY', 'ORG_ORGNAME',
|
||||
'ORG_ORGUNIT', 'TITLE', 'ROLE', 'ADR_WORK_STREET', 'ADR_WORK_EXTADR',
|
||||
'ADR_WORK_LOCALITY', 'ADR_WORK_REGION', 'ADR_WORK_PCODE',
|
||||
'ADR_WORK_CTRY']
|
||||
if gajim.connections[self.account].connected > 1:
|
||||
# clear all entries
|
||||
for e in entries:
|
||||
self.xml.get_widget(e + '_entry').set_text('')
|
||||
self.xml.get_widget('DESC_textview').get_buffer().set_text('')
|
||||
self.xml.get_widget('PHOTO_image').set_from_pixbuf(None)
|
||||
if self.avatar_save_as_id:
|
||||
self.xml.get_widget('PHOTO_eventbox').disconnect(
|
||||
self.avatar_save_as_id)
|
||||
self.avatar_save_as_id = None
|
||||
gajim.connections[self.account].request_vcard(self.jid)
|
||||
else:
|
||||
dialogs.ErrorDialog(_('You are not connected to the server'),
|
||||
_('Without a connection, you can not get your contact information.'))
|
||||
|
||||
def change_to_vcard(self):
|
||||
self.xml.get_widget('information_notebook').remove_page(0)
|
||||
self.xml.get_widget('nickname_label').set_text(_('Personal details'))
|
||||
|
||||
self.publish_button.show()
|
||||
self.retrieve_button.show()
|
||||
|
||||
#photo_vbuttonbox visible
|
||||
self.xml.get_widget('photo_vbuttonbox').show()
|
||||
|
||||
#make all entries editable
|
||||
entries = ['FN', 'NICKNAME', 'BDAY', 'EMAIL_HOME_USERID', 'URL',
|
||||
'TEL_HOME_NUMBER', 'N_FAMILY', 'N_GIVEN', 'N_MIDDLE', 'N_PREFIX',
|
||||
'N_SUFFIX', 'ADR_HOME_STREET', 'ADR_HOME_EXTADR', 'ADR_HOME_LOCALITY',
|
||||
'ADR_HOME_REGION', 'ADR_HOME_PCODE', 'ADR_HOME_CTRY', 'ORG_ORGNAME',
|
||||
'ORG_ORGUNIT', 'TITLE', 'ROLE', 'TEL_WORK_NUMBER', 'EMAIL_WORK_USERID',
|
||||
'ADR_WORK_STREET', 'ADR_WORK_EXTADR', 'ADR_WORK_LOCALITY',
|
||||
'ADR_WORK_REGION', 'ADR_WORK_PCODE', 'ADR_WORK_CTRY']
|
||||
for e in entries:
|
||||
self.xml.get_widget(e + '_entry').set_property('editable', True)
|
||||
|
||||
description_textview = self.xml.get_widget('DESC_textview')
|
||||
description_textview.set_editable(True)
|
||||
description_textview.set_cursor_visible(True)
|
||||
|
|