merge diff from trunk to pep branch
2
AUTHORS
|
@ -3,10 +3,10 @@ CURRENT DEVELOPERS:
|
|||
Yann Le Boulanger (asterix AT lagaule.org)
|
||||
Nikos Kouremenos (kourem AT gmail.com)
|
||||
Travis Shirk (travis AT pobox.com)
|
||||
Jean-Marie Traissard (jim AT lapin.org)
|
||||
|
||||
PAST DEVELOPERS:
|
||||
|
||||
Jean-Marie Traissard (jim AT lapin.org)
|
||||
Stefan Bethge (stefan AT lanpartei.de)
|
||||
Dimitur Kirov (dkirov AT gmail.com)
|
||||
Vincent Hanquez (tab AT snarc.org)
|
||||
|
|
12
ChangeLog
|
@ -1,5 +1,15 @@
|
|||
Gajim 0.11.1 (XX February 2007)
|
||||
Gajim 0.11.1 (18 February 2007)
|
||||
* Fixes in gajim-remote and the way XMPP URI are handled
|
||||
* Fix Idle under Windows
|
||||
* Fix Gajim under non-ascii languages Windows
|
||||
* Fix International Domain Name usage
|
||||
* Fix when removing active privacy list
|
||||
* Fix problem with adhoc command and multi-step forms
|
||||
* Fixed avatars cache problems in group chats
|
||||
* KDE integration for XMPP URI
|
||||
* Support of Banshee Music player
|
||||
* Support of XEP-0202 (Entity Time)
|
||||
* Support of XEP-0199 (XMPP Ping)
|
||||
|
||||
Gajim 0.11 (19 December 2006)
|
||||
* New build system, using GNU autotools. See README.html
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
AC_INIT([Gajim - A Jabber Instant Messager],
|
||||
[0.11.1.0],[http://trac.gajim.org/],[gajim])
|
||||
[0.11.1.5],[http://trac.gajim.org/],[gajim])
|
||||
AC_PREREQ([2.59])
|
||||
AM_INIT_AUTOMAKE([1.8])
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
|
|
|
@ -1,177 +1,121 @@
|
|||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--*- mode: xml -*-->
|
||||
<glade-interface>
|
||||
|
||||
<widget class="GtkMenu" id="account_context_menu">
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="status_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Status</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1235">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-network</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="pep_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Personal Events</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1235">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-home</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="join_group_chat_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Group Chat</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1236">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-connect</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="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>
|
||||
<property name="label" translatable="yes">Send Single _Message...</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1237">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-new</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="add_contact_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Add Contact...</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1238">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-add</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="service_discovery_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Discover Services...</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1239">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-find</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="execute_command_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Execute Command...</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1246">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-execute</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="edit_account_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Modify Account...</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1240">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-preferences</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>
|
||||
</widget>
|
||||
|
||||
<widget class="GtkMenu" id="account_context_menu">
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="status_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Status</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1235">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-network</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="pep_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">_Personal Events</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="menu-item-image7">
|
||||
<property name="stock">gtk-home</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="seperator">
|
||||
<property name="visible">True</property>
|
||||
</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="join_group_chat_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Group Chat</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1236">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-connect</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="service_discovery_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Discover Services</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1239">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-find</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="execute_command_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Execute Command</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1246">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-execute</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="seperator">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="add_contact_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Add Contact</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1238">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-add</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="edit_account_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Modify Account...</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1240">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-preferences</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</glade-interface>
|
||||
|
|
|
@ -53,6 +53,7 @@ to the Jabber network.</property>
|
|||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">I already have an account I want to use</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
|
@ -66,6 +67,7 @@ to the Jabber network.</property>
|
|||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">I want to _register for a new account</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">use_existing_account_radiobutton</property>
|
||||
</widget>
|
||||
|
@ -142,96 +144,30 @@ to the Jabber network.</property>
|
|||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="jid_label">
|
||||
<widget class="GtkEntry" id="username_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="selectable">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label258">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Your JID:</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label262">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">_Username:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">username_entry</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="password_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="visibility">False</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="invisible_char">*</property>
|
||||
<property name="activates_default">True</property>
|
||||
<signal name="changed" handler="on_username_entry_changed"/>
|
||||
<signal name="key_press_event" handler="on_username_entry_key_press_event"/>
|
||||
</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="GtkCheckButton" id="save_password_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="tooltip" translatable="yes">If checked, Gajim will remember the password for this account</property>
|
||||
<property name="label" translatable="yes">Save pass_word</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_save_password_checkbutton_toggled"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label263">
|
||||
<widget class="GtkLabel" id="label267">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">_Password:</property>
|
||||
<property name="label" translatable="yes">_Server:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">password_entry</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
|
@ -255,31 +191,98 @@ to the Jabber network.</property>
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label267">
|
||||
<widget class="GtkLabel" id="label263">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">_Server:</property>
|
||||
<property name="label" translatable="yes">_Password:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">password_entry</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="username_entry">
|
||||
<widget class="GtkCheckButton" id="save_password_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="tooltip" translatable="yes">If checked, Gajim will remember the password for this account</property>
|
||||
<property name="label" translatable="yes">Save pass_word</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_save_password_checkbutton_toggled"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="password_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="visibility">False</property>
|
||||
<property name="invisible_char">*</property>
|
||||
<signal name="changed" handler="on_username_entry_changed"/>
|
||||
<signal name="key_press_event" handler="on_username_entry_key_press_event"/>
|
||||
<property name="activates_default">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="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label262">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">_Username:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">username_entry</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label258">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Your JID:</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="jid_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="selectable">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
@ -357,6 +360,7 @@ to the Jabber network.</property>
|
|||
<property name="tooltip" translatable="yes">Click to see features (like MSN, ICQ transports) of jabber servers</property>
|
||||
<property name="label" translatable="yes">Servers Features</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_register_server_features_button_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
|
@ -384,6 +388,62 @@ to the Jabber network.</property>
|
|||
<property name="n_columns">3</property>
|
||||
<property name="column_spacing">5</property>
|
||||
<property name="row_spacing">5</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label381">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Prox_y:</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkComboBox" id="proxies_combobox">
|
||||
<property name="visible">True</property>
|
||||
<property name="items">None</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="y_options">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="manage_proxies_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Manage...</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_manage_proxies_button_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="x_options"></property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="custom_host_port_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Use custom hostname/port</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_custom_host_port_checkbutton_toggled"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="custom_host_hbox">
|
||||
<property name="visible">True</property>
|
||||
|
@ -446,60 +506,6 @@ to the Jabber network.</property>
|
|||
<property name="y_options">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="custom_host_port_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Use custom hostname/port</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_custom_host_port_checkbutton_toggled"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="manage_proxies_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Manage...</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="clicked" handler="on_manage_proxies_button_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="x_options"></property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkComboBox" id="proxies_combobox">
|
||||
<property name="visible">True</property>
|
||||
<property name="items">None</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="y_options">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label381">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Prox_y:</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -637,6 +643,7 @@ Please wait...</property>
|
|||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Connect when I press Finish</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
|
@ -652,6 +659,7 @@ Please wait...</property>
|
|||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Set my profile when I connect</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
|
@ -692,6 +700,7 @@ Please wait...</property>
|
|||
<property name="can_default">True</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_cancel_button_clicked"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
@ -703,6 +712,7 @@ Please wait...</property>
|
|||
<property name="can_default">True</property>
|
||||
<property name="label">gtk-go-back</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_back_button_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
|
@ -717,6 +727,7 @@ Please wait...</property>
|
|||
<property name="has_default">True</property>
|
||||
<property name="label">gtk-go-forward</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_forward_button_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
|
@ -727,6 +738,8 @@ Please wait...</property>
|
|||
<widget class="GtkButton" id="advanced_button">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_advanced_button_clicked"/>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment96">
|
||||
|
@ -772,6 +785,8 @@ Please wait...</property>
|
|||
<widget class="GtkButton" id="finish_button">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_finish_button_clicked"/>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment87">
|
||||
|
|
|
@ -1,527 +1,335 @@
|
|||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--*- mode: xml -*-->
|
||||
<glade-interface>
|
||||
|
||||
<widget class="GtkWindow" id="add_new_contact_window">
|
||||
<property name="border_width">6</property>
|
||||
<property name="title" translatable="yes">Add New Contact</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="resizable">False</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<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">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="prompt_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"></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="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">3</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="GtkLabel" id="uid_label">
|
||||
<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">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEntry" id="uid_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>
|
||||
<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">0</property>
|
||||
<property name="bottom_attach">1</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">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></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">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"></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>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</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="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="message_scrolledwindow">
|
||||
<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_ETCHED_IN</property>
|
||||
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTextView" id="message_textview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="editable">True</property>
|
||||
<property name="overwrite">False</property>
|
||||
<property name="accepts_tab">True</property>
|
||||
<property name="justification">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap_mode">GTK_WRAP_WORD</property>
|
||||
<property name="cursor_visible">True</property>
|
||||
<property name="pixels_above_lines">0</property>
|
||||
<property name="pixels_below_lines">0</property>
|
||||
<property name="pixels_inside_wrap">0</property>
|
||||
<property name="left_margin">0</property>
|
||||
<property name="right_margin">0</property>
|
||||
<property name="indent">0</property>
|
||||
<property name="text" translatable="yes">I would like to add you to my contact list.</property>
|
||||
</widget>
|
||||
</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="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 with this transport
|
||||
<widget class="GtkWindow" id="add_new_contact_window">
|
||||
<property name="border_width">6</property>
|
||||
<property name="title" translatable="yes">Add New Contact</property>
|
||||
<property name="resizable">False</property>
|
||||
<signal name="key_press_event" handler="on_add_new_contact_window_key_press_event"/>
|
||||
<signal name="destroy" handler="on_add_new_contact_window_destroy"/>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox8">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="prompt_label">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="account_hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="account_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">A_ccount:</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<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>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="protocol_hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="protocol_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">_Protocol:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">uid_entry</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkComboBox" id="protocol_combobox">
|
||||
<property name="visible">True</property>
|
||||
<signal name="changed" handler="on_protocol_combobox_changed"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkComboBox" id="protocol_jid_combobox">
|
||||
<property name="visible">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="items" translatable="yes"></property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkTable" id="subscription_table">
|
||||
<property name="visible">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="border_width">6</property>
|
||||
<property name="n_rows">3</property>
|
||||
<property name="n_columns">2</property>
|
||||
<property name="column_spacing">6</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="uid_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">_User ID:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">uid_entry</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="uid_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">*</property>
|
||||
<property name="activates_default">True</property>
|
||||
<signal name="changed" handler="on_uid_entry_changed"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label188">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">_Nickname:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">nickname_entry</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="nickname_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">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="xalign">0</property>
|
||||
<property name="label" translatable="yes">_Group:</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">GTK_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>
|
||||
<child internal-child="entry">
|
||||
<widget class="GtkEntry" id="comboboxentry-entry1">
|
||||
</widget>
|
||||
</child>
|
||||
</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">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">3</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="response_id">0</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="message_scrolledwindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="border_width">6</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
|
||||
<child>
|
||||
<widget class="GtkTextView" id="message_textview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="wrap_mode">GTK_WRAP_WORD</property>
|
||||
<property name="text" translatable="yes">I would like to add you to my contact list.</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="register_hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label224">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">You have to register with 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
|
||||
<property name="wrap">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="register_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="label" translatable="yes">_Register</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_register_button_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="connected_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="no_show_all">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>
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<property name="spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancel_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-cancel</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_cancel_button_clicked" last_modification_time="Mon, 28 Feb 2005 22:46:06 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<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_add_button_clicked" last_modification_time="Thu, 03 Aug 2006 14:27:55 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">7</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHButtonBox" id="hbuttonbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="spacing">12</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancel_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_cancel_button_clicked"/>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="add_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="has_default">True</property>
|
||||
<property name="label">gtk-add</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_add_button_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">8</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</glade-interface>
|
||||
|
|
|
@ -65,16 +65,6 @@
|
|||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckMenuItem" id="compact_view_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Compact View Alt+C</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="active">False</property>
|
||||
<signal name="activate" handler="_on_compact_view_menuitem_activate" last_modification_time="Tue, 03 Jan 2006 04:26:30 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="add_to_roster_menuitem">
|
||||
<property name="visible">True</property>
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--Generated with glade3 3.2.2 on Sat Jul 7 01:08:57 2007 by stephan@ThinkPad-->
|
||||
<glade-interface>
|
||||
<widget class="GtkWindow" id="features_window">
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="border_width">12</property>
|
||||
<property name="title" translatable="yes">Features</property>
|
||||
<property name="default_width">300</property>
|
||||
<property name="default_height">530</property>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes"><b>List of possible features in Gajim:</b></property>
|
||||
<property name="use_markup">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="scrolledwindow1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="shadow_type">GTK_SHADOW_OUT</property>
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="features_treeview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="headers_clickable">True</property>
|
||||
<signal name="cursor_changed" handler="on_features_treeview_cursor_changed"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkFrame" id="frame2">
|
||||
<property name="visible">True</property>
|
||||
<property name="border_width">3</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">GTK_SHADOW_NONE</property>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment2">
|
||||
<property name="visible">True</property>
|
||||
<property name="border_width">6</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xscale">0.5</property>
|
||||
<property name="left_padding">12</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="feature_desc_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="wrap">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"><b>Description</b></property>
|
||||
<property name="use_markup">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="type">label_item</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHButtonBox" id="hbuttonbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="close_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">gtk-close</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_close_button_clicked"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</glade-interface>
|
|
@ -1,392 +1,281 @@
|
|||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--*- mode: xml -*-->
|
||||
<glade-interface>
|
||||
|
||||
<widget class="GtkWindow" id="file_transfers_window">
|
||||
<property name="border_width">12</property>
|
||||
<property name="title" translatable="yes">File Transfers</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<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>
|
||||
<accessibility>
|
||||
<atkproperty name="AtkObject::accessible_name" translatable="yes">File Transfers</atkproperty>
|
||||
<atkproperty name="AtkObject::accessible_description" translatable="yes">Shows a list of file transfers between you and others</atkproperty>
|
||||
</accessibility>
|
||||
<signal name="delete_event" handler="on_file_transfers_dialog_delete_event" last_modification_time="Wed, 31 Aug 2005 22:17:01 GMT"/>
|
||||
<signal name="key_press_event" handler="on_file_transfers_window_key_press_event" last_modification_time="Mon, 15 Aug 2005 12:42:20 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="transfers_scrolledwindow">
|
||||
<property name="width_request">460</property>
|
||||
<property name="height_request">150</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="transfers_list">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="headers_visible">True</property>
|
||||
<property name="rules_hint">True</property>
|
||||
<property name="reorderable">False</property>
|
||||
<property name="enable_search">False</property>
|
||||
<property name="fixed_height_mode">False</property>
|
||||
<property name="hover_selection">False</property>
|
||||
<property name="hover_expand">False</property>
|
||||
<accessibility>
|
||||
<atkproperty name="AtkObject::accessible_name" translatable="yes">file transfers list</atkproperty>
|
||||
<atkproperty name="AtkObject::accessible_description" translatable="yes">A list of active, completed and stopped file transfers</atkproperty>
|
||||
</accessibility>
|
||||
<signal name="row_activated" handler="on_transfers_list_row_activated" last_modification_time="Wed, 31 Aug 2005 22:32:25 GMT"/>
|
||||
<signal name="motion_notify_event" handler="on_transfers_list_motion_notify_event" last_modification_time="Wed, 31 Aug 2005 22:33:10 GMT"/>
|
||||
<signal name="leave_notify_event" handler="on_transfers_list_leave_notify_event" last_modification_time="Wed, 31 Aug 2005 22:33:23 GMT"/>
|
||||
<signal name="button_press_event" handler="on_transfers_list_button_press_event" last_modification_time="Wed, 31 Aug 2005 22:33:23 GMT"/>
|
||||
<signal name="button_release_event" handler="on_transfers_list_button_release_event" last_modification_time="Wed, 31 Aug 2005 22:33:23 GMT"/>
|
||||
<signal name="key_press_event" handler="on_transfers_list_key_press_event" last_modification_time="Wed, 31 Aug 2005 22:33:23 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHButtonBox" id="hbuttonbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="cleanup_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="tooltip" translatable="yes">Removes completed, cancelled and failed file transfers from the list</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<accessibility>
|
||||
<atkproperty name="AtkObject::accessible_name" translatable="yes">Remove file transfer from the list.</atkproperty>
|
||||
<atkproperty name="AtkObject::accessible_description" translatable="yes">This action removes single file transfer from the list. If the transfer is active, it is first stopped and then removed</atkproperty>
|
||||
</accessibility>
|
||||
<signal name="clicked" handler="on_cleanup_button_clicked" last_modification_time="Sat, 03 Sep 2005 14:03:13 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment91">
|
||||
<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="hbox2992">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">2</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImage" id="image1143">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-clear</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="label358">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Clean _up</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>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="pause_restore_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_pause_restore_button_clicked" last_modification_time="Wed, 31 Aug 2005 22:31:50 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment92">
|
||||
<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="hbox2993">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">2</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImage" id="image1147">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-media-pause</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="label359">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Pause</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>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancel_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="tooltip" translatable="yes">Cancels the selected file transfer and removes incomplete file</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<accessibility>
|
||||
<atkproperty name="AtkObject::accessible_name" translatable="yes">Cancel file transfer</atkproperty>
|
||||
<atkproperty name="AtkObject::accessible_description" translatable="yes">Cancels the selected file transfer</atkproperty>
|
||||
</accessibility>
|
||||
<signal name="clicked" handler="on_cancel_button_clicked" last_modification_time="Tue, 09 Aug 2005 17:07:31 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="close_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Hides the window</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="label">gtk-close</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_close_button_clicked" last_modification_time="Wed, 03 Aug 2005 15:51:45 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="notify_ft_complete_checkbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">_Notify me when a file transfer is complete</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">False</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<accessibility>
|
||||
<atkproperty name="AtkObject::accessible_description" translatable="yes">When a file transfer is complete show a popup notification</atkproperty>
|
||||
</accessibility>
|
||||
<signal name="toggled" handler="on_notify_ft_complete_checkbox_toggled" last_modification_time="Wed, 31 Aug 2005 22:52:01 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
<widget class="GtkMenu" id="file_transfers_menu">
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="remove_menuitem">
|
||||
<property name="label">gtk-remove</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_remove_menuitem_activate" last_modification_time="Fri, 09 Sep 2005 22:48:03 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="continue_menuitem">
|
||||
<property name="label" translatable="yes">_Continue</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_continue_menuitem_activate" last_modification_time="Fri, 09 Sep 2005 22:48:03 GMT"/>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1144">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-media-play</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="pause_menuitem">
|
||||
<property name="label" translatable="yes">_Pause</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_pause_menuitem_activate" last_modification_time="Fri, 09 Sep 2005 22:48:03 GMT"/>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1145">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-media-pause</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="cancel_menuitem">
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_cancel_menuitem_activate" last_modification_time="Wed, 10 Aug 2005 18:57:29 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="separator11">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="open_folder_menuitem">
|
||||
<property name="label" translatable="yes">_Open Containing Folder</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_open_folder_menuitem_activate" last_modification_time="Fri, 09 Sep 2005 22:48:03 GMT"/>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1146">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-directory</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>
|
||||
</widget>
|
||||
|
||||
<widget class="GtkWindow" id="file_transfers_window">
|
||||
<property name="border_width">12</property>
|
||||
<property name="title" translatable="yes">File Transfers</property>
|
||||
<accessibility>
|
||||
<atkproperty name="AtkObject::accessible_name" translatable="yes">File Transfers</atkproperty>
|
||||
<atkproperty name="AtkObject::accessible_description" translatable="yes">Shows a list of file transfers between you and others</atkproperty>
|
||||
</accessibility>
|
||||
<signal name="key_press_event" handler="on_file_transfers_window_key_press_event"/>
|
||||
<signal name="delete_event" handler="on_file_transfers_dialog_delete_event"/>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="transfers_scrolledwindow">
|
||||
<property name="width_request">460</property>
|
||||
<property name="height_request">150</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>
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="transfers_list">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="rules_hint">True</property>
|
||||
<property name="enable_search">False</property>
|
||||
<accessibility>
|
||||
<atkproperty name="AtkObject::accessible_name" translatable="yes">file transfers list</atkproperty>
|
||||
<atkproperty name="AtkObject::accessible_description" translatable="yes">A list of active, completed and stopped file transfers</atkproperty>
|
||||
</accessibility>
|
||||
<signal name="leave_notify_event" handler="on_transfers_list_leave_notify_event"/>
|
||||
<signal name="button_press_event" handler="on_transfers_list_button_press_event"/>
|
||||
<signal name="motion_notify_event" handler="on_transfers_list_motion_notify_event"/>
|
||||
<signal name="key_press_event" handler="on_transfers_list_key_press_event"/>
|
||||
<signal name="row_activated" handler="on_transfers_list_row_activated"/>
|
||||
<signal name="button_release_event" handler="on_transfers_list_button_release_event"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="notify_ft_complete_checkbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">_Notify me when a file transfer is complete</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<accessibility>
|
||||
<atkproperty name="AtkObject::accessible_description" translatable="yes">When a file transfer is complete show a popup notification</atkproperty>
|
||||
</accessibility>
|
||||
<signal name="toggled" handler="on_notify_ft_complete_checkbox_toggled"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHButtonBox" id="hbuttonbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="cleanup_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="tooltip" translatable="yes">Removes completed, cancelled and failed file transfers from the list</property>
|
||||
<property name="response_id">0</property>
|
||||
<accessibility>
|
||||
<atkproperty name="AtkObject::accessible_name" translatable="yes">Remove file transfer from the list.</atkproperty>
|
||||
<atkproperty name="AtkObject::accessible_description" translatable="yes">This action removes single file transfer from the list. If the transfer is active, it is first stopped and then removed</atkproperty>
|
||||
</accessibility>
|
||||
<signal name="clicked" handler="on_cleanup_button_clicked"/>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment91">
|
||||
<property name="visible">True</property>
|
||||
<property name="xscale">0</property>
|
||||
<property name="yscale">0</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox2992">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<widget class="GtkImage" id="image1143">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-clear</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label358">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Clean _up</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="pause_restore_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_pause_restore_button_clicked"/>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment92">
|
||||
<property name="visible">True</property>
|
||||
<property name="xscale">0</property>
|
||||
<property name="yscale">0</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox2993">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<widget class="GtkImage" id="image1147">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-media-pause</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label359">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Pause</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancel_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="tooltip" translatable="yes">Cancels the selected file transfer and removes incomplete file</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<accessibility>
|
||||
<atkproperty name="AtkObject::accessible_name" translatable="yes">Cancel file transfer</atkproperty>
|
||||
<atkproperty name="AtkObject::accessible_description" translatable="yes">Cancels the selected file transfer</atkproperty>
|
||||
</accessibility>
|
||||
<signal name="clicked" handler="on_cancel_button_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="close_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="tooltip" translatable="yes">Hides the window</property>
|
||||
<property name="label">gtk-close</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_close_button_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<widget class="GtkMenu" id="file_transfers_menu">
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="remove_menuitem">
|
||||
<property name="label">gtk-remove</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_remove_menuitem_activate"/>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="continue_menuitem">
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="label" translatable="yes">_Continue</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_continue_menuitem_activate"/>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1144">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-media-play</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="pause_menuitem">
|
||||
<property name="label" translatable="yes">_Pause</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_pause_menuitem_activate"/>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1145">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-media-pause</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="cancel_menuitem">
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_cancel_menuitem_activate"/>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="separator11">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="open_folder_menuitem">
|
||||
<property name="label" translatable="yes">_Open Containing Folder</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_open_folder_menuitem_activate"/>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1146">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</glade-interface>
|
||||
|
|
|
@ -408,7 +408,7 @@ Chat Banner</property>
|
|||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTable" id="table36">
|
||||
<widget class="GtkTable" id="theme_options_table">
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">9</property>
|
||||
<property name="n_columns">2</property>
|
||||
|
|
|
@ -10,17 +10,17 @@
|
|||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1409">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-redo</property>
|
||||
<property name="stock">gtk-edit</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="manage_room_menuitem">
|
||||
<widget class="GtkImageMenuItem" id="manage_room_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">_Manage room</property>
|
||||
<property name="label" translatable="yes">_Manage Room</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child>
|
||||
<widget class="GtkMenu" id="menu1">
|
||||
|
@ -60,7 +60,7 @@
|
|||
<child>
|
||||
<widget class="GtkImageMenuItem" id="destroy_room_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Destroy room</property>
|
||||
<property name="label" translatable="yes">_Destroy Room</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1407">
|
||||
|
@ -73,30 +73,25 @@
|
|||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkCheckMenuItem" id="compact_view_menuitem">
|
||||
<property name="label" translatable="yes">_Compact View Alt+C</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="minimize_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Minimize</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1411">
|
||||
<widget class="GtkImage" id="menu-item-image8">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-goto-bottom</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-properties</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="separatormenuitem2">
|
||||
<widget class="GtkCheckMenuItem" id="minimize_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Minimize on close</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="seperator">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
|
@ -113,6 +108,11 @@
|
|||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="seperator">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="history_menuitem">
|
||||
<property name="tooltip" translatable="yes">Click to see past conversation in this room</property>
|
||||
|
|
|
@ -17,20 +17,6 @@
|
|||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="add_to_roster_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Add to Roster</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1052">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-add</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="group_chat_actions_menuitem">
|
||||
<property name="visible">True</property>
|
||||
|
@ -101,6 +87,39 @@
|
|||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="send_file_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">Send _File</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="menu-item-image4">
|
||||
<property name="stock">gtk-save</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="separator6">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="add_to_roster_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Add to Roster</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1052">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-add</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="separator6">
|
||||
<property name="visible">True</property>
|
||||
|
|
|
@ -1,392 +1,249 @@
|
|||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--*- mode: xml -*-->
|
||||
<glade-interface>
|
||||
|
||||
<widget class="GtkWindow" id="history_manager_window">
|
||||
<property name="border_width">6</property>
|
||||
<property name="title" translatable="yes">Gajim History Logs Manager</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="default_width">650</property>
|
||||
<property name="default_height">500</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<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>
|
||||
<signal name="delete_event" handler="on_history_manager_window_delete_event" last_modification_time="Thu, 02 Feb 2006 21:52:04 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHPaned" id="hpaned">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="position">200</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="jids_scrolledwindow">
|
||||
<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="jids_listview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="headers_visible">True</property>
|
||||
<property name="rules_hint">True</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>
|
||||
<signal name="key_press_event" handler="on_jids_listview_key_press_event" last_modification_time="Sat, 04 Feb 2006 22:27:05 GMT"/>
|
||||
<signal name="button_press_event" handler="on_listview_button_press_event" last_modification_time="Fri, 10 Feb 2006 15:11:21 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="shrink">True</property>
|
||||
<property name="resize">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="welcome_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"><big><b>Welcome to Gajim History Logs Manager</b></big>
|
||||
<widget class="GtkWindow" id="history_manager_window">
|
||||
<property name="border_width">6</property>
|
||||
<property name="title" translatable="yes">Gajim History Logs Manager</property>
|
||||
<property name="default_width">650</property>
|
||||
<property name="default_height">500</property>
|
||||
<signal name="delete_event" handler="on_history_manager_window_delete_event"/>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkHPaned" id="hpaned">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="position">200</property>
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="jids_scrolledwindow">
|
||||
<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>
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="jids_listview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="rules_hint">True</property>
|
||||
<signal name="button_press_event" handler="on_listview_button_press_event"/>
|
||||
<signal name="key_press_event" handler="on_jids_listview_key_press_event"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="resize">False</property>
|
||||
<property name="shrink">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="welcome_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes"><big><b>Welcome to Gajim History Logs Manager</b></big>
|
||||
|
||||
You can select logs from the left and/or search database from below.
|
||||
|
||||
<b>WARNING:</b>
|
||||
If you plan to do massive deletions, please make sure Gajim is not running. Generally avoid deletions with contacts you currently chat with.</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">True</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="GtkScrolledWindow" id="logs_scrolledwindow">
|
||||
<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="logs_listview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="headers_visible">True</property>
|
||||
<property name="rules_hint">True</property>
|
||||
<property name="reorderable">False</property>
|
||||
<property name="enable_search">False</property>
|
||||
<property name="fixed_height_mode">False</property>
|
||||
<property name="hover_selection">False</property>
|
||||
<property name="hover_expand">False</property>
|
||||
<signal name="button_press_event" handler="on_listview_button_press_event" last_modification_time="Fri, 10 Feb 2006 15:11:21 GMT"/>
|
||||
<signal name="key_press_event" handler="on_logs_listview_key_press_event" last_modification_time="Sat, 04 Feb 2006 15:01:22 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="search_results_scrolledwindow">
|
||||
<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="search_results_listview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="headers_visible">True</property>
|
||||
<property name="rules_hint">True</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>
|
||||
<signal name="button_press_event" handler="on_listview_button_press_event" last_modification_time="Fri, 10 Feb 2006 15:11:21 GMT"/>
|
||||
<signal name="row_activated" handler="on_search_results_listview_row_activated" last_modification_time="Sat, 04 Feb 2006 23:48:46 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="shrink">True</property>
|
||||
<property name="resize">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="GtkHBox" id="hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEntry" id="search_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="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="search_db_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="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_search_db_button_clicked" last_modification_time="Thu, 02 Feb 2006 21:54:19 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment1">
|
||||
<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="hbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">2</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImage" id="image1">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-find</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="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Search Database</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>
|
||||
</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">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
<widget class="GtkMenu" id="context_menu">
|
||||
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="export_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Export</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_export_menuitem_activate" last_modification_time="Fri, 10 Feb 2006 15:15:30 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="delete_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Delete</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image2">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-remove</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>
|
||||
</widget>
|
||||
|
||||
<widget class="GtkFileChooserDialog" id="filechooserdialog">
|
||||
<property name="action">GTK_FILE_CHOOSER_ACTION_SAVE</property>
|
||||
<property name="local_only">True</property>
|
||||
<property name="select_multiple">False</property>
|
||||
<property name="show_hidden">False</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<property name="focus_on_map">True</property>
|
||||
|
||||
<child internal-child="vbox">
|
||||
<widget class="GtkVBox" id="dialog-vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">24</property>
|
||||
|
||||
<child internal-child="action_area">
|
||||
<widget class="GtkHButtonBox" id="dialog-action_area1">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancel_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">-6</property>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="save_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-save</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">-5</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
<property name="use_markup">True</property>
|
||||
<property name="wrap">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="logs_scrolledwindow">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="no_show_all">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>
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="logs_listview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="rules_hint">True</property>
|
||||
<property name="enable_search">False</property>
|
||||
<signal name="button_press_event" handler="on_listview_button_press_event"/>
|
||||
<signal name="key_press_event" handler="on_logs_listview_key_press_event"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="search_results_scrolledwindow">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="no_show_all">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>
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="search_results_listview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="rules_hint">True</property>
|
||||
<signal name="button_press_event" handler="on_listview_button_press_event"/>
|
||||
<signal name="row_activated" handler="on_search_results_listview_row_activated"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="resize">True</property>
|
||||
<property name="shrink">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="search_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">*</property>
|
||||
<property name="activates_default">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="search_db_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="has_default">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_search_db_button_clicked"/>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment1">
|
||||
<property name="visible">True</property>
|
||||
<property name="xscale">0</property>
|
||||
<property name="yscale">0</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<widget class="GtkImage" id="image1">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-find</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Search Database</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<widget class="GtkMenu" id="context_menu">
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="export_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Export</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_export_menuitem_activate"/>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="delete_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Delete</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image2">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-remove</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<widget class="GtkFileChooserDialog" id="filechooserdialog">
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||
<property name="action">GTK_FILE_CHOOSER_ACTION_SAVE</property>
|
||||
<child internal-child="vbox">
|
||||
<widget class="GtkVBox" id="dialog-vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">24</property>
|
||||
<child internal-child="action_area">
|
||||
<widget class="GtkHButtonBox" id="dialog-action_area1">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancel_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">-6</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="save_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="has_default">True</property>
|
||||
<property name="label">gtk-save</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">-5</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</glade-interface>
|
||||
|
|
|
@ -1,499 +1,323 @@
|
|||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--*- mode: xml -*-->
|
||||
<glade-interface>
|
||||
|
||||
<widget class="GtkWindow" id="manage_bookmarks_window">
|
||||
<property name="border_width">12</property>
|
||||
<property name="title" translatable="yes">Manage Bookmarks</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="default_width">550</property>
|
||||
<property name="default_height">300</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<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="button_press_event" handler="on_manage_bookmarks_window_button_press_event" last_modification_time="Sun, 12 Jun 2005 15:52:20 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox86">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox2965">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox94">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="scrolledwindow37">
|
||||
<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="bookmarks_treeview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="headers_visible">False</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>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHButtonBox" id="hbuttonbox25">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="add_bookmark_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_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_add_bookmark_button_clicked" last_modification_time="Wed, 08 Jun 2005 17:20:25 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="remove_bookmark_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-remove</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_remove_bookmark_button_clicked" last_modification_time="Wed, 08 Jun 2005 17:20:20 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</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="table33">
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">7</property>
|
||||
<property name="n_columns">2</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="autojoin_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">If checked, Gajim will join this group chat on startup</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Auto join</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">False</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_autojoin_checkbutton_toggled" last_modification_time="Wed, 08 Jun 2005 17:20:40 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</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>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label318">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Password:</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</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">4</property>
|
||||
<property name="bottom_attach">5</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEntry" id="pass_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="editable">True</property>
|
||||
<property name="visibility">False</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">4</property>
|
||||
<property name="bottom_attach">5</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEntry" id="server_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">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="label317">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Server:</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</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="label316">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Room:</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</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"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEntry" id="room_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">False</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="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEntry" id="nick_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">False</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="label315">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Nickname:</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</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">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label325">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Title:</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</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">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEntry" id="title_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">False</property>
|
||||
</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="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label326">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Print status:</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</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">6</property>
|
||||
<property name="bottom_attach">7</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkComboBox" id="print_status_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_print_status_combobox_changed" last_modification_time="Sun, 07 May 2006 20:44:46 GMT"/>
|
||||
</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">fill</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</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="GtkHButtonBox" id="hbuttonbox20">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<property name="spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancel_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-cancel</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_cancel_button_clicked" last_modification_time="Wed, 08 Jun 2005 17:18:48 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="ok_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-ok</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_ok_button_clicked" last_modification_time="Wed, 08 Jun 2005 17:18:52 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
<widget class="GtkWindow" id="manage_bookmarks_window">
|
||||
<property name="border_width">12</property>
|
||||
<property name="title" translatable="yes">Manage Bookmarks</property>
|
||||
<property name="default_width">550</property>
|
||||
<property name="default_height">300</property>
|
||||
<signal name="button_press_event" handler="on_manage_bookmarks_window_button_press_event"/>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox86">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox2965">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox94">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="scrolledwindow37">
|
||||
<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>
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="bookmarks_treeview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="headers_visible">False</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHButtonBox" id="hbuttonbox25">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="add_bookmark_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="label">gtk-add</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="clicked" handler="on_add_bookmark_button_clicked"/>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="remove_bookmark_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="label">gtk-remove</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="clicked" handler="on_remove_bookmark_button_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkTable" id="table33">
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">7</property>
|
||||
<property name="n_columns">2</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label318">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Password:</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="bottom_attach">5</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="pass_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="visibility">False</property>
|
||||
<property name="invisible_char">*</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="server_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">*</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="label317">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Server:</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label316">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Room:</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="room_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">*</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="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="nick_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">*</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="label315">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Nickname:</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label325">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Title:</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="title_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">*</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label326">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Print status:</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">6</property>
|
||||
<property name="bottom_attach">7</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkComboBox" id="print_status_combobox">
|
||||
<property name="visible">True</property>
|
||||
<property name="items" translatable="yes"></property>
|
||||
<signal name="changed" handler="on_print_status_combobox_changed"/>
|
||||
</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">GTK_FILL</property>
|
||||
<property name="y_options">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="autojoin_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="tooltip" translatable="yes">If checked, Gajim will join this group chat on startup</property>
|
||||
<property name="label" translatable="yes">Auto join</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_autojoin_checkbutton_toggled"/>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="minimize_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">Minimize on Auto Join</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_minimize_checkbutton_toggled"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">5</property>
|
||||
<property name="bottom_attach">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHButtonBox" id="hbuttonbox20">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">12</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancel_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="clicked" handler="on_cancel_button_clicked"/>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="ok_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="label">gtk-ok</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="clicked" handler="on_ok_button_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</glade-interface>
|
||||
|
|
|
@ -591,7 +591,7 @@ Status message</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="ellipsize">PANGO_ELLIPSIZE_END</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
|
|
|
@ -65,9 +65,9 @@
|
|||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="send_custom_status_menuitem">
|
||||
<widget class="GtkImageMenuItem" id="send_custom_status_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Send cus_tom status</property>
|
||||
<property name="label" translatable="yes">Send Cus_tom Status</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child>
|
||||
<widget class="GtkMenu" id="menu5">
|
||||
|
@ -95,7 +95,7 @@
|
|||
<widget class="GtkImageMenuItem" id="manage_contact">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">_Manage contact</property>
|
||||
<property name="label" translatable="yes">_Manage Contact</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child>
|
||||
<widget class="GtkMenu" id="menu2">
|
||||
|
@ -123,6 +123,7 @@
|
|||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-edit</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
@ -142,7 +143,7 @@
|
|||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="custom_avatar">
|
||||
<widget class="GtkImageMenuItem" id="set_custom_avatar_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">Set Custom _Avatar</property>
|
||||
|
@ -152,6 +153,7 @@
|
|||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-orientation-portrait</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
@ -159,6 +161,7 @@
|
|||
<child>
|
||||
<widget class="GtkImageMenuItem" id="add_special_notification_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="label" translatable="yes">Add Special _Notification</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
|
@ -244,7 +247,7 @@
|
|||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1715">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-yes</property>
|
||||
<property name="stock">gtk-stop</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
|
@ -298,6 +301,7 @@
|
|||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-properties</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
@ -309,7 +313,7 @@
|
|||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="information_menuitem">
|
||||
<property name="label">gtk-dialog-info</property>
|
||||
<property name="label">gtk-info</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</widget>
|
||||
|
|
|
@ -266,12 +266,40 @@
|
|||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="faq_menuitem">
|
||||
<widget class="GtkImageMenuItem" id="faq_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Frequently Asked Questions (online)</property>
|
||||
<property name="label" translatable="yes">_FAQ</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_faq_menuitem_activate"/>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image_faq">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-dialog-question</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="menuitem1">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="features_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">Fea_tures</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_features_menuitem_activate"/>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image_features">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-properties</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
|
|
|
@ -1,191 +1,215 @@
|
|||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--*- mode: xml -*-->
|
||||
<glade-interface>
|
||||
|
||||
<widget class="GtkWindow" id="search_window">
|
||||
<property name="border_width">12</property>
|
||||
<property name="title" translatable="yes">Search</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<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_search_window_key_press_event" last_modification_time="Wed, 04 Apr 2007 18:39:27 GMT"/>
|
||||
<signal name="destroy" handler="on_search_window_destroy" last_modification_time="Wed, 04 Apr 2007 18:39:35 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="search_vbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Please wait while retrieving search form...</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">True</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkProgressBar" id="progressbar">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">GTK_PROGRESS_LEFT_TO_RIGHT</property>
|
||||
<property name="fraction">0</property>
|
||||
<property name="pulse_step">0.10000000149</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</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="GtkHButtonBox" id="hbuttonbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="search_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_search_button_clicked" last_modification_time="Thu, 19 Apr 2007 09:43:28 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment1">
|
||||
<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="hbox5">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">2</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImage" id="image1">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-find</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="label58">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Search</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>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="close_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-close</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_close_button_clicked" last_modification_time="Mon, 25 Sep 2006 05:08:55 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
<widget class="GtkWindow" id="search_window">
|
||||
<property name="border_width">12</property>
|
||||
<property name="title" translatable="yes">Search</property>
|
||||
<signal name="key_press_event" handler="on_search_window_key_press_event"/>
|
||||
<signal name="destroy" handler="on_search_window_destroy"/>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="search_vbox">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Please wait while retrieving search form...</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkProgressBar" id="progressbar">
|
||||
<property name="visible">True</property>
|
||||
<property name="pulse_step">0.10000000149</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHButtonBox" id="hbuttonbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="add_contact_button">
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_add_contact_button_clicked"/>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment2">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<widget class="GtkImage" id="image2">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-add</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">_Add contact</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="information_button">
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_information_button_clicked"/>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment3">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<widget class="GtkImage" id="image3">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-info</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="label" translatable="yes">_Information</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="search_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_search_button_clicked"/>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment1">
|
||||
<property name="visible">True</property>
|
||||
<property name="xscale">0</property>
|
||||
<property name="yscale">0</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox5">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<widget class="GtkImage" id="image1">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-find</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label58">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Search</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="close_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="label">gtk-close</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_close_button_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</glade-interface>
|
||||
|
|
|
@ -1,421 +1,269 @@
|
|||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--*- mode: xml -*-->
|
||||
<glade-interface>
|
||||
|
||||
<widget class="GtkWindow" id="service_discovery_window">
|
||||
<property name="border_width">6</property>
|
||||
<property name="title" translatable="yes"></property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="default_width">450</property>
|
||||
<property name="default_height">420</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="role">Service Discovery</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<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="destroy" handler="on_service_discovery_window_destroy" last_modification_time="Sun, 27 Mar 2005 18:05:35 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox11">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEventBox" id="banner_agent_eventbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="visible_window">True</property>
|
||||
<property name="above_child">False</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="banner_agent_hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="banner_agent_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label"><span weight="heavy" size="large">Agent name</span>
|
||||
<widget class="GtkWindow" id="service_discovery_window">
|
||||
<property name="border_width">6</property>
|
||||
<property name="role">Service Discovery</property>
|
||||
<property name="default_width">450</property>
|
||||
<property name="default_height">420</property>
|
||||
<signal name="destroy" handler="on_service_discovery_window_destroy"/>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox11">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkEventBox" id="banner_agent_eventbox">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="banner_agent_hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="banner_agent_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0.05000000074505806</property>
|
||||
<property name="ypad">6</property>
|
||||
<property name="label"><span weight="heavy" size="large">Agent name</span>
|
||||
Agent JID - node</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.0500000007451</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">6</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="GtkImage" id="banner_agent_icon">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">6</property>
|
||||
<property name="ypad">6</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTable" id="address_table">
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">3</property>
|
||||
<property name="n_columns">3</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="row_spacing">0</property>
|
||||
<property name="column_spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkComboBoxEntry" id="address_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>
|
||||
<signal name="changed" handler="on_address_comboboxentry_changed" last_modification_time="Tue, 29 Mar 2005 17:24:11 GMT"/>
|
||||
<signal name="key_press_event" handler="on_address_comboboxentry_key_press_event" last_modification_time="Tue, 29 Mar 2005 17:41:10 GMT"/>
|
||||
</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">fill</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="browse_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="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_go_button_clicked" last_modification_time="Sun, 04 Sep 2005 20:37:26 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment93">
|
||||
<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="hbox2995">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">2</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImage" id="image1148">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-jump-to</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="label362">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">G_o</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>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">0</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="label224">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Address:</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="mnemonic_widget">address_comboboxentry</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">0</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="services_scrollwin">
|
||||
<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_ETCHED_IN</property>
|
||||
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="services_treeview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="headers_visible">False</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>
|
||||
<signal name="row_activated" handler="on_services_treeview_row_activated" last_modification_time="Mon, 28 Mar 2005 00:28:25 GMT"/>
|
||||
</widget>
|
||||
</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="filter_hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label361">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Filter:</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="mnemonic_widget">filter_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="GtkEntry" id="filter_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">False</property>
|
||||
<signal name="changed" handler="on_filter_entry_changed" last_modification_time="Sun, 04 Sep 2005 11:35:21 GMT"/>
|
||||
</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">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox2994">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkProgressBar" id="services_progressbar">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">GTK_PROGRESS_LEFT_TO_RIGHT</property>
|
||||
<property name="fraction">0</property>
|
||||
<property name="pulse_step">0.10000000149</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</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="label363">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"></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">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="action_buttonbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="close_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="label">gtk-close</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_close_button_clicked" last_modification_time="Sat, 26 Mar 2005 15:05:59 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">2</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
<property name="use_markup">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImage" id="banner_agent_icon">
|
||||
<property name="visible">True</property>
|
||||
<property name="xpad">6</property>
|
||||
<property name="ypad">6</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkTable" id="address_table">
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">3</property>
|
||||
<property name="n_columns">3</property>
|
||||
<property name="column_spacing">6</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label224">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Address:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">address_comboboxentry</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="browse_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="has_default">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_go_button_clicked"/>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment93">
|
||||
<property name="visible">True</property>
|
||||
<property name="xscale">0</property>
|
||||
<property name="yscale">0</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox2995">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<widget class="GtkImage" id="image1148">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-jump-to</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label362">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">G_o</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkComboBoxEntry" id="address_comboboxentry">
|
||||
<property name="visible">True</property>
|
||||
<property name="items" translatable="yes"></property>
|
||||
<signal name="changed" handler="on_address_comboboxentry_changed"/>
|
||||
<signal name="key_press_event" handler="on_address_comboboxentry_key_press_event"/>
|
||||
<child internal-child="entry">
|
||||
<widget class="GtkEntry" id="comboboxentry-entry1">
|
||||
</widget>
|
||||
</child>
|
||||
</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">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="services_scrollwin">
|
||||
<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_ETCHED_IN</property>
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="services_treeview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="headers_visible">False</property>
|
||||
<signal name="row_activated" handler="on_services_treeview_row_activated"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="filter_hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label361">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Filter:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">filter_entry</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="filter_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">*</property>
|
||||
<signal name="changed" handler="on_filter_entry_changed"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox2994">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<widget class="GtkProgressBar" id="services_progressbar">
|
||||
<property name="visible">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="pulse_step">0.10000000149</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label363">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="action_buttonbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="close_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="label">gtk-close</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_close_button_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="padding">2</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</glade-interface>
|
||||
|
|
|
@ -1,548 +1,346 @@
|
|||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--*- mode: xml -*-->
|
||||
<glade-interface>
|
||||
|
||||
<widget class="GtkWindow" id="single_message_window">
|
||||
<property name="border_width">6</property>
|
||||
<property name="title" translatable="yes"></property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="default_width">550</property>
|
||||
<property name="default_height">280</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<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>
|
||||
<signal name="key_press_event" handler="on_single_message_window_key_press_event" last_modification_time="Tue, 05 Jul 2005 22:02:15 GMT"/>
|
||||
<signal name="delete_event" handler="on_single_message_window_delete_event" last_modification_time="Mon, 17 Oct 2005 15:32:50 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox97">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTable" id="headers_table">
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">3</property>
|
||||
<property name="n_columns">3</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label335">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Subject:</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="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="GtkEntry" id="from_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">False</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEntry" id="subject_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">False</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="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="count_chars_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">0</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="left_attach">2</property>
|
||||
<property name="right_attach">3</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="GtkEntry" id="to_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">False</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">3</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="from_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">From:</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</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">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="to_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">To:</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</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">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="conversation_scrolledwindow">
|
||||
<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>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="message_scrolledwindow">
|
||||
<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="GtkTextView" id="message_textview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="editable">True</property>
|
||||
<property name="overwrite">False</property>
|
||||
<property name="accepts_tab">True</property>
|
||||
<property name="justification">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap_mode">GTK_WRAP_WORD</property>
|
||||
<property name="cursor_visible">True</property>
|
||||
<property name="pixels_above_lines">0</property>
|
||||
<property name="pixels_below_lines">0</property>
|
||||
<property name="pixels_inside_wrap">0</property>
|
||||
<property name="left_margin">0</property>
|
||||
<property name="right_margin">0</property>
|
||||
<property name="indent">0</property>
|
||||
<property name="text" translatable="yes"></property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHButtonBox" id="hbuttonbox26">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<property name="spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="close_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-close</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_close_button_clicked" last_modification_time="Thu, 08 Dec 2005 14:01:10 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancel_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-cancel</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_cancel_button_clicked" last_modification_time="Sat, 02 Jul 2005 15:27:45 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="send_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Send message</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_send_button_clicked" last_modification_time="Tue, 05 Jul 2005 18:37:42 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment98">
|
||||
<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="hbox3003">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">2</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImage" id="image1326">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-jump-to</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="label370">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Sen_d</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>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="reply_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Reply to this message</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_reply_button_clicked" last_modification_time="Tue, 05 Jul 2005 18:47:49 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment82">
|
||||
<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="hbox2982">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">2</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImage" id="image862">
|
||||
<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="label346">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Reply</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>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="send_and_close_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Send message and close window</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_send_and_close_button_clicked" last_modification_time="Tue, 05 Jul 2005 22:03:11 GMT"/>
|
||||
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment83">
|
||||
<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="hbox2983">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">2</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImage" id="image878">
|
||||
<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="label347">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Send & Close</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>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">6</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
<widget class="GtkWindow" id="single_message_window">
|
||||
<property name="border_width">6</property>
|
||||
<property name="default_width">550</property>
|
||||
<property name="default_height">280</property>
|
||||
<signal name="key_press_event" handler="on_single_message_window_key_press_event"/>
|
||||
<signal name="delete_event" handler="on_single_message_window_delete_event"/>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox97">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkTable" id="headers_table">
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">3</property>
|
||||
<property name="n_columns">3</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="to_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">To:</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="from_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">From:</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="to_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="invisible_char">*</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">3</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="count_chars_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="subject_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">*</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="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="from_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="invisible_char">*</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label335">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Subject:</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="conversation_scrolledwindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="no_show_all">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>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="message_scrolledwindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="no_show_all">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>
|
||||
<child>
|
||||
<widget class="GtkTextView" id="message_textview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="wrap_mode">GTK_WRAP_WORD</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHButtonBox" id="hbuttonbox26">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">12</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="close_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="label">gtk-close</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_close_button_clicked"/>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancel_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_cancel_button_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="send_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="tooltip" translatable="yes">Send message</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_send_button_clicked"/>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment98">
|
||||
<property name="visible">True</property>
|
||||
<property name="xscale">0</property>
|
||||
<property name="yscale">0</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox3003">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<widget class="GtkImage" id="image1326">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-jump-to</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label370">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Sen_d</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="reply_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="tooltip" translatable="yes">Reply to this message</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_reply_button_clicked"/>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment82">
|
||||
<property name="visible">True</property>
|
||||
<property name="xscale">0</property>
|
||||
<property name="yscale">0</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox2982">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<widget class="GtkImage" id="image862">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-ok</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label346">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Reply</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="send_and_close_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="tooltip" translatable="yes">Send message and close window</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_send_and_close_button_clicked"/>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment83">
|
||||
<property name="visible">True</property>
|
||||
<property name="xscale">0</property>
|
||||
<property name="yscale">0</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox2983">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<widget class="GtkImage" id="image878">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-ok</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label347">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Send & Close</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="padding">6</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</glade-interface>
|
||||
|
|
|
@ -181,8 +181,8 @@
|
|||
<widget class="GtkScrolledWindow" id="scrolledwindow42">
|
||||
<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="hscrollbar_policy">GTK_POLICY_NEVER</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_NEVER</property>
|
||||
<property name="shadow_type">GTK_SHADOW_IN</property>
|
||||
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||
|
||||
|
|
|
@ -1,153 +1,113 @@
|
|||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--*- mode: xml -*-->
|
||||
<glade-interface>
|
||||
|
||||
<widget class="GtkMenu" id="zeroconf_contact_context_menu">
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="start_chat_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Start _Chat</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1534">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-jump-to</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="image1535">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-refresh</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="GtkMenuItem" id="edit_groups_menuitem">
|
||||
<property name="label" translatable="yes">Edit _Groups</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="above_send_file_separator">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="send_file_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Send _File</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1536">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-file</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="assign_openpgp_key_menuitem">
|
||||
<property name="label" translatable="yes">Assign Open_PGP Key</property>
|
||||
<property name="use_underline">True</property>
|
||||
<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="image1537">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-dialog-authentication</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="add_special_notification_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Add Special _Notification</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1538">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-info</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="GtkSeparatorMenuItem" id="above_information_separator">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="information_menuitem">
|
||||
<property name="label">gtk-info</property>
|
||||
<property name="use_stock">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="history_menuitem">
|
||||
<property name="label" translatable="yes">_History</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1539">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-justify-fill</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>
|
||||
</widget>
|
||||
|
||||
<widget class="GtkMenu" id="zeroconf_contact_context_menu">
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="start_chat_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Start _Chat</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1534">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-jump-to</property>
|
||||
<property name="icon_size">1</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="image1535">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-refresh</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="edit_groups_menuitem">
|
||||
<property name="label" translatable="yes">Edit _Groups</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="above_send_file_separator">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="send_file_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Send _File</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1536">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="assign_openpgp_key_menuitem">
|
||||
<property name="label" translatable="yes">Assign Open_PGP Key</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_assign_openpgp_key_menuitem_activate"/>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1537">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="add_special_notification_menuitem">
|
||||
<property name="visible">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="label" translatable="yes">Add Special _Notification</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1538">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-info</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="above_information_separator">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="information_menuitem">
|
||||
<property name="label">gtk-info</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="history_menuitem">
|
||||
<property name="label" translatable="yes">_History</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="image1539">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-justify-fill</property>
|
||||
<property name="icon_size">1</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</glade-interface>
|
||||
|
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 541 B After Width: | Height: | Size: 541 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 428 B After Width: | Height: | Size: 428 B |
Before Width: | Height: | Size: 815 B After Width: | Height: | Size: 815 B |
Before Width: | Height: | Size: 523 B After Width: | Height: | Size: 523 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 308 B After Width: | Height: | Size: 308 B |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
60
po/de.po
|
@ -9,8 +9,8 @@ msgstr ""
|
|||
"Project-Id-Version: gajim 0.11\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-03-29 13:38+0200\n"
|
||||
"PO-Revision-Date: 2007-03-29 13:41+0100\n"
|
||||
"Last-Translator: Benjamin Drung <benjamin.drung@gmail.com>\n"
|
||||
"PO-Revision-Date: 2007-08-03 23:11+0100\n"
|
||||
"Last-Translator: Michael Skiba <michael@michael-skiba.de>\n"
|
||||
"Language-Team: German <translators@gajim.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
@ -204,9 +204,8 @@ msgid "Account Modification"
|
|||
msgstr "Kontoänderung"
|
||||
|
||||
#: ../data/glade/account_modification_window.glade.h:6
|
||||
#, fuzzy
|
||||
msgid "Administration operations"
|
||||
msgstr "Administratorliste"
|
||||
msgstr "Administrative Aktionen"
|
||||
|
||||
#: ../data/glade/account_modification_window.glade.h:7
|
||||
msgid "Auto-reconnect when connection is lost"
|
||||
|
@ -379,9 +378,8 @@ msgid "Synch_ronize account status with global status"
|
|||
msgstr "Konto-Status mit globalem _Status abgleichen"
|
||||
|
||||
#: ../data/glade/account_modification_window.glade.h:42
|
||||
#, fuzzy
|
||||
msgid "Synchronise contacts"
|
||||
msgstr "_Abgemeldete Kontakte anzeigen"
|
||||
msgstr "Synchronisiere Kontakte"
|
||||
|
||||
#: ../data/glade/account_modification_window.glade.h:43
|
||||
msgid "Use _SSL (legacy)"
|
||||
|
@ -1039,9 +1037,8 @@ msgid "_Bookmark This Room"
|
|||
msgstr "Raum zu _Lesezeichen hinzufügen"
|
||||
|
||||
#: ../data/glade/gc_control_popup_menu.glade.h:7
|
||||
#, fuzzy
|
||||
msgid "_Destroy room"
|
||||
msgstr "_Neuer Raum"
|
||||
msgstr "_Raum zerstören"
|
||||
|
||||
#: ../data/glade/gc_occupants_menu.glade.h:1
|
||||
msgid "Mo_derator"
|
||||
|
@ -2338,9 +2335,8 @@ msgid "Bulgarian"
|
|||
msgstr "Bulgarisch"
|
||||
|
||||
#: ../src/chat_control.py:52
|
||||
#, fuzzy
|
||||
msgid "Breton"
|
||||
msgstr "Briton"
|
||||
msgstr "Bretonisch"
|
||||
|
||||
#: ../src/chat_control.py:52
|
||||
msgid "Czech"
|
||||
|
@ -2367,7 +2363,6 @@ msgid "Spanish"
|
|||
msgstr "Spanisch"
|
||||
|
||||
#: ../src/chat_control.py:52
|
||||
#, fuzzy
|
||||
msgid "Basque"
|
||||
msgstr "Baskisch"
|
||||
|
||||
|
@ -2752,11 +2747,11 @@ msgstr "Sperrliste"
|
|||
|
||||
#: ../src/config.py:2180
|
||||
msgid "Member List"
|
||||
msgstr "Mitgliedsliste"
|
||||
msgstr "Mitgliederliste"
|
||||
|
||||
#: ../src/config.py:2181
|
||||
msgid "Owner List"
|
||||
msgstr "Listenbesitzer"
|
||||
msgstr "Besitzerliste"
|
||||
|
||||
#: ../src/config.py:2182
|
||||
msgid "Administrator List"
|
||||
|
@ -3203,23 +3198,20 @@ msgid "%s is not the name of a group chat."
|
|||
msgstr "%s ist kein Name eines Gruppenchats."
|
||||
|
||||
#: ../src/dialogs.py:1327
|
||||
#, fuzzy
|
||||
msgid "Without a connection, you can not synchronise your contacts."
|
||||
msgstr "Sie müssen verbunden sein, um Ihr Passwort zu ändern"
|
||||
msgstr "Sie müssen verbunden sein, um Ihre Kontakte zu Synchronisieren."
|
||||
|
||||
#: ../src/dialogs.py:1374
|
||||
#, fuzzy
|
||||
msgid "This account is not connected to the server"
|
||||
msgstr "Konto \"%s\" ist mit Server verbunden"
|
||||
msgstr "Konto \"%s\" ist nicht mit dem Server verbunden"
|
||||
|
||||
#: ../src/dialogs.py:1375
|
||||
#, fuzzy
|
||||
msgid "You cannot synchronize with an account unless it is connected."
|
||||
msgstr "Sie können einem Gruppenchat erst beitreten, wenn Sie verbunden sind."
|
||||
msgstr "Sie können nicht mit einem Konto Synchronisieren, solange es nicht verbunden ist."
|
||||
|
||||
#: ../src/dialogs.py:1399
|
||||
msgid "Synchronise"
|
||||
msgstr ""
|
||||
msgstr "Synchronisieren"
|
||||
|
||||
#: ../src/dialogs.py:1457
|
||||
#, python-format
|
||||
|
@ -4557,19 +4549,21 @@ msgstr "Bitte geben Sie an, welchen Spitznamen Sie verwenden möchten:"
|
|||
|
||||
#. Ask for a reason
|
||||
#: ../src/groupchat_control.py:1457
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid "Destroying %s"
|
||||
msgstr "Beschreibung: %s"
|
||||
msgstr "Zerstöre %s"
|
||||
|
||||
#: ../src/groupchat_control.py:1458
|
||||
msgid ""
|
||||
"You are going to definitively destroy this room.\n"
|
||||
"You may specify a reason below:"
|
||||
msgstr ""
|
||||
"Sie werden den Raum endgültig zerstören.\n"
|
||||
"Sie können hier einen Grund angeben:"
|
||||
|
||||
#: ../src/groupchat_control.py:1460
|
||||
msgid "You may also enter an alternate venue:"
|
||||
msgstr ""
|
||||
msgstr "Sie können auch einen alternativen Raum eintragen:"
|
||||
|
||||
#: ../src/groupchat_control.py:1490
|
||||
msgid "Bookmark already set"
|
||||
|
@ -5161,11 +5155,11 @@ msgid "Metacontacts are a way to regroup several contacts in one line. Generally
|
|||
msgstr "Metakontakte sind eine Möglichkeit, mehrere Kontakte in einer Zeile zu gruppieren. Normalerweise benutzt man Sie, wenn eine Person mehrere Jabber- oder Transport-Konten hat."
|
||||
|
||||
#: ../src/roster_window.py:4132
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid "Do you want to send that file to %s:"
|
||||
msgid_plural "Do you want to send those files to %s:"
|
||||
msgstr[0] "%s möchte ihnen eine Datei senden:"
|
||||
msgstr[1] "%s möchte ihnen eine Datei senden:"
|
||||
msgstr[1] "%s möchte ihnen diese Datei senden:"
|
||||
|
||||
#: ../src/roster_window.py:4237
|
||||
#, python-format
|
||||
|
@ -5722,7 +5716,7 @@ msgstr "Kann leer, 'chat' oder 'normal' sein. Wenn nicht leer, dann werden alle
|
|||
|
||||
#: ../src/common/config.py:227
|
||||
msgid "If True, Gajim will scroll and select the contact who sent you the last message, if chat window is not already opened."
|
||||
msgstr ""
|
||||
msgstr "Wenn aktiviert, wird Gajim automatisch zu der Person springen und auswählen, die die letzte Nachricht geschickt hat, falls das Chat Fenster nicht bereits offen ist."
|
||||
|
||||
#: ../src/common/config.py:238
|
||||
msgid "Priority will change automatically according to your status. Priorities are defined in autopriority_* options."
|
||||
|
@ -5874,13 +5868,13 @@ msgstr "Falscher Host"
|
|||
|
||||
#: ../src/common/connection_handlers.py:180
|
||||
#: ../src/common/zeroconf/connection_handlers_zeroconf.py:236
|
||||
#, fuzzy, python-format
|
||||
#, python-format
|
||||
msgid "The host %s you configured as the ft_add_hosts_to_send advanced option is not valid, so ignored."
|
||||
msgstr "Der Host, den Sie für die erweiterte Option ft_override_host_to_send angeben haben ist ungültig und wird ignoriert."
|
||||
msgstr "Der Host %s, den Sie für die erweiterte Option ft_override_host_to_send angeben haben ist ungültig und wird ignoriert."
|
||||
|
||||
#: ../src/common/connection_handlers.py:216
|
||||
msgid "Invalid local address? :-O"
|
||||
msgstr ""
|
||||
msgstr "Ungültige Lokale Adresse? :-O"
|
||||
|
||||
#: ../src/common/connection_handlers.py:607
|
||||
#, python-format
|
||||
|
@ -5940,14 +5934,13 @@ msgstr ""
|
|||
#. Room has been destroyed. see
|
||||
#. http://www.xmpp.org/extensions/xep-0045.html#destroyroom
|
||||
#: ../src/common/connection_handlers.py:1676
|
||||
#, fuzzy
|
||||
msgid "Room has been destroyed"
|
||||
msgstr "Autorisierung wurde entfernt"
|
||||
msgstr "Raum wurde zerstört"
|
||||
|
||||
#: ../src/common/connection_handlers.py:1683
|
||||
#, python-format
|
||||
msgid "You can join this room instead: %s"
|
||||
msgstr ""
|
||||
msgstr "Sie können stattdessen diesem Raum beitreten: %s"
|
||||
|
||||
#: ../src/common/connection_handlers.py:1709
|
||||
msgid "I would like to add you to my roster."
|
||||
|
@ -5996,9 +5989,8 @@ msgid "Invalid answer"
|
|||
msgstr "Ungültige Antwort"
|
||||
|
||||
#: ../src/common/connection.py:379
|
||||
#, fuzzy
|
||||
msgid "Connection to proxy failed"
|
||||
msgstr "Verbindung fehlgeschlagen"
|
||||
msgstr "Verbindung mit Proxy fehlgeschlagen"
|
||||
|
||||
#: ../src/common/connection.py:433
|
||||
#: ../src/common/connection.py:531
|
||||
|
|
|
@ -53,6 +53,7 @@ class CommandWindow:
|
|||
# retrieving widgets from xml
|
||||
self.xml = gtkgui_helpers.get_glade('adhoc_commands_window.glade')
|
||||
self.window = self.xml.get_widget('adhoc_commands_window')
|
||||
self.window.connect('delete-event', self.on_adhoc_commands_window_delete_event)
|
||||
for name in ('back_button', 'forward_button',
|
||||
'execute_button','close_button','stages_notebook',
|
||||
'retrieving_commands_stage_vbox',
|
||||
|
@ -101,7 +102,7 @@ class CommandWindow:
|
|||
self.remove_pulsing()
|
||||
|
||||
def on_adhoc_commands_window_delete_event(self, *anything):
|
||||
return self.stage_adhoc_commands_window_delete_event(self, *anything)
|
||||
return self.stage_adhoc_commands_window_delete_event(self.window)
|
||||
|
||||
def __del__(self):
|
||||
print "Object has been deleted."
|
||||
|
@ -171,7 +172,7 @@ class CommandWindow:
|
|||
for (commandnode, commandname) in self.commandlist:
|
||||
radio = gtk.RadioButton(first_radio, label=commandname)
|
||||
radio.connect("toggled", self.on_command_radiobutton_toggled, commandnode)
|
||||
if first_radio is None:
|
||||
if not first_radio:
|
||||
first_radio = radio
|
||||
self.commandnode = commandnode
|
||||
self.command_list_vbox.pack_start(radio, expand=False)
|
||||
|
@ -252,6 +253,7 @@ class CommandWindow:
|
|||
else:
|
||||
self.window.destroy()
|
||||
return False
|
||||
return True
|
||||
|
||||
def stage3_back_button_clicked(self, widget):
|
||||
self.stage3_submit_form('prev')
|
||||
|
@ -264,10 +266,10 @@ class CommandWindow:
|
|||
|
||||
def stage3_submit_form(self, action='execute'):
|
||||
self.data_form_widget.set_sensitive(False)
|
||||
if self.data_form_widget.get_data_form() is None:
|
||||
self.data_form_widget.hide()
|
||||
else:
|
||||
if self.data_form_widget.get_data_form():
|
||||
self.data_form_widget.data_form.type='submit'
|
||||
else:
|
||||
self.data_form_widget.hide()
|
||||
|
||||
self.close_button.set_sensitive(True)
|
||||
self.back_button.set_sensitive(False)
|
||||
|
@ -284,13 +286,13 @@ class CommandWindow:
|
|||
self.remove_pulsing()
|
||||
self.sending_form_progressbar.hide()
|
||||
|
||||
if self.sessionid is None:
|
||||
if not self.sessionid:
|
||||
self.sessionid = command.getAttr('sessionid')
|
||||
|
||||
self.form_status = command.getAttr('status')
|
||||
|
||||
self.commandnode = command.getAttr('node')
|
||||
if command.getTag('x') is not None:
|
||||
if command.getTag('x'):
|
||||
self.dataform = dataforms.ExtendForm(node=command.getTag('x'))
|
||||
|
||||
self.data_form_widget.set_sensitive(True)
|
||||
|
@ -307,18 +309,18 @@ class CommandWindow:
|
|||
else:
|
||||
self.data_form_widget.hide()
|
||||
|
||||
action = command.getTag('action')
|
||||
if action is None:
|
||||
actions = command.getTag('actions')
|
||||
if actions:
|
||||
# actions, actions, actions...
|
||||
self.close_button.set_sensitive(True)
|
||||
self.back_button.set_sensitive(actions.getTag('prev') is not None)
|
||||
self.forward_button.set_sensitive(actions.getTag('next') is not None)
|
||||
self.execute_button.set_sensitive(True)
|
||||
else:
|
||||
self.close_button.set_sensitive(True)
|
||||
self.back_button.set_sensitive(False)
|
||||
self.forward_button.set_sensitive(False)
|
||||
self.execute_button.set_sensitive(True)
|
||||
else:
|
||||
# actions, actions, actions...
|
||||
self.close_button.set_sensitive(True)
|
||||
self.back_button.set_sensitive(action.getTag('prev') is not None)
|
||||
self.forward_button.set_sensitive(action.getTag('next') is not None)
|
||||
self.execute_button.set_sensitive(True)
|
||||
|
||||
if self.form_status == 'completed':
|
||||
self.close_button.set_sensitive(True)
|
||||
|
@ -329,7 +331,7 @@ class CommandWindow:
|
|||
self.stage_adhoc_commands_window_delete_event = self.stage3_close_button_clicked
|
||||
|
||||
note = command.getTag('note')
|
||||
if note is not None:
|
||||
if note:
|
||||
self.notes_label.set_text(note.getData().decode('utf-8'))
|
||||
self.notes_label.set_no_show_all(False)
|
||||
self.notes_label.show()
|
||||
|
@ -369,9 +371,9 @@ class CommandWindow:
|
|||
# close old stage
|
||||
self.stage_finish()
|
||||
|
||||
assert errorid is not None or error is not None
|
||||
assert errorid or error
|
||||
|
||||
if errorid is not None:
|
||||
if errorid:
|
||||
# we've got error code, display appropriate message
|
||||
try:
|
||||
errorname = xmpp.NS_STANZAS + ' ' + str(errorid)
|
||||
|
@ -380,7 +382,7 @@ class CommandWindow:
|
|||
del errorname, errordesc
|
||||
except KeyError: # when stanza doesn't have error description
|
||||
error = 'Service returned an error.'
|
||||
elif error is not None:
|
||||
elif error:
|
||||
# we've got error message
|
||||
pass
|
||||
else:
|
||||
|
@ -409,7 +411,7 @@ class CommandWindow:
|
|||
def setup_pulsing(self, progressbar):
|
||||
'''Set the progressbar to pulse. Makes a custom
|
||||
function to repeatedly call progressbar.pulse() method.'''
|
||||
assert self.pulse_id is None
|
||||
assert not self.pulse_id
|
||||
assert isinstance(progressbar, gtk.ProgressBar)
|
||||
|
||||
def callback():
|
||||
|
@ -421,7 +423,7 @@ class CommandWindow:
|
|||
|
||||
def remove_pulsing(self):
|
||||
'''Stop pulsing, useful when especially when removing widget.'''
|
||||
if self.pulse_id is not None:
|
||||
if self.pulse_id:
|
||||
gobject.source_remove(self.pulse_id)
|
||||
self.pulse_id=None
|
||||
|
||||
|
@ -436,7 +438,7 @@ class CommandWindow:
|
|||
# FIXME: move to connection_handlers.py
|
||||
# is error => error stage
|
||||
error = response.getError()
|
||||
if error is not None:
|
||||
if error:
|
||||
# extracting error description from xmpp/protocol.py
|
||||
self.stage5(errorid = error)
|
||||
return
|
||||
|
@ -470,10 +472,10 @@ class CommandWindow:
|
|||
'action':action
|
||||
})
|
||||
|
||||
if self.sessionid is not None:
|
||||
if self.sessionid:
|
||||
cmdnode.setAttr('sessionid', self.sessionid)
|
||||
|
||||
if self.data_form_widget.data_form is not None:
|
||||
if self.data_form_widget.data_form:
|
||||
# cmdnode.addChild(node=dataforms.DataForm(tofill=self.data_form_widget.data_form))
|
||||
# FIXME: simplified form to send
|
||||
|
||||
|
@ -482,7 +484,7 @@ class CommandWindow:
|
|||
def callback(response):
|
||||
# FIXME: move to connection_handlers.py
|
||||
err = response.getError()
|
||||
if err is not None:
|
||||
if err:
|
||||
self.stage5(errorid = err)
|
||||
else:
|
||||
self.stage3_next_form(response.getTag('command'))
|
||||
|
@ -491,8 +493,8 @@ class CommandWindow:
|
|||
|
||||
def send_cancel(self):
|
||||
'''Send the command with action='cancel'. '''
|
||||
assert self.commandnode is not None
|
||||
if self.sessionid is not None and self.account.connection:
|
||||
assert self.commandnode
|
||||
if self.sessionid and self.account.connection:
|
||||
# we already have sessionid, so the service sent at least one reply.
|
||||
stanza = xmpp.Iq(typ='set', to=self.jid)
|
||||
stanza.addChild('command', attrs={
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
## Copyright (C) 2006-2007 Nikos Kouremenos <kourem@gmail.com>
|
||||
## Copyright (C) 2006 Travis Shirk <travis@pobox.com>
|
||||
## Copyright (C) 2006 Dimitur Kirov <dkirov@gmail.com>
|
||||
## Copyright (C) 2007 Lukas Petrovicky <lukas@petrovicky.net>
|
||||
## Copyright (C) 2007 Julien Pivotto <roidelapluie@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
|
||||
|
@ -129,13 +131,39 @@ class ChatControlBase(MessageControl):
|
|||
id = self.widget.connect('key_press_event', self._on_keypress_event)
|
||||
self.handlers[id] = self.widget
|
||||
|
||||
# Create banner and connect signals
|
||||
widget = self.xml.get_widget('banner_eventbox')
|
||||
widget.set_property('height-request', gajim.config.get('chat_avatar_height'))
|
||||
id = widget.connect('button-press-event',
|
||||
self._on_banner_eventbox_button_press_event)
|
||||
self.handlers[id] = widget
|
||||
# Init DND
|
||||
self.TARGET_TYPE_URI_LIST = 80
|
||||
self.dnd_list = [ ( 'text/uri-list', 0, self.TARGET_TYPE_URI_LIST ),
|
||||
('MY_TREE_MODEL_ROW', gtk.TARGET_SAME_APP, 0)]
|
||||
id = self.widget.connect('drag_data_received',
|
||||
self._on_drag_data_received)
|
||||
self.handlers[id] = self.widget
|
||||
self.widget.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
|
||||
gtk.DEST_DEFAULT_HIGHLIGHT |
|
||||
gtk.DEST_DEFAULT_DROP,
|
||||
self.dnd_list, gtk.gdk.ACTION_COPY)
|
||||
|
||||
# Create textviews and connect signals
|
||||
self.conv_textview = ConversationTextview(self.account)
|
||||
# FIXME: DND on non editable TextView, find a better way
|
||||
self.drag_entered = False
|
||||
id = self.conv_textview.tv.connect('drag_data_received',
|
||||
self._on_drag_data_received)
|
||||
self.handlers[id] = self.conv_textview.tv
|
||||
id = self.conv_textview.tv.connect('drag_motion', self._on_drag_motion)
|
||||
self.handlers[id] = self.conv_textview.tv
|
||||
id = self.conv_textview.tv.connect('drag_leave', self._on_drag_leave)
|
||||
self.handlers[id] = self.conv_textview.tv
|
||||
self.conv_textview.tv.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
|
||||
gtk.DEST_DEFAULT_HIGHLIGHT |
|
||||
gtk.DEST_DEFAULT_DROP,
|
||||
self.dnd_list, gtk.gdk.ACTION_COPY)
|
||||
|
||||
self.conv_scrolledwindow = self.xml.get_widget(
|
||||
'conversation_scrolledwindow')
|
||||
|
@ -149,6 +177,7 @@ class ChatControlBase(MessageControl):
|
|||
self.handlers[id] = widget
|
||||
self.scroll_to_end_id = None
|
||||
self.was_at_the_end = True
|
||||
|
||||
# add MessageTextView to UI and connect signals
|
||||
self.msg_scrolledwindow = self.xml.get_widget('message_scrolledwindow')
|
||||
self.msg_textview = MessageTextView()
|
||||
|
@ -164,6 +193,13 @@ class ChatControlBase(MessageControl):
|
|||
id = self.msg_textview.connect('populate_popup',
|
||||
self.on_msg_textview_populate_popup)
|
||||
self.handlers[id] = self.msg_textview
|
||||
# Setup DND
|
||||
id = self.msg_textview.connect('drag_data_received',
|
||||
self._on_drag_data_received)
|
||||
self.handlers[id] = self.msg_textview
|
||||
self.msg_textview.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
|
||||
gtk.DEST_DEFAULT_HIGHLIGHT,
|
||||
self.dnd_list, gtk.gdk.ACTION_COPY)
|
||||
|
||||
self.update_font()
|
||||
|
||||
|
@ -481,6 +517,22 @@ class ChatControlBase(MessageControl):
|
|||
self.handle_message_textview_mykey_press(widget, event_keyval,
|
||||
event_keymod)
|
||||
|
||||
def _on_drag_data_received(self, widget, context, x, y, selection,
|
||||
target_type, timestamp):
|
||||
pass # Derived classes SHOULD implement this method
|
||||
|
||||
def _on_drag_leave(self, widget, context, time):
|
||||
# FIXME: DND on non editable TextView, find a better way
|
||||
self.drag_entered = False
|
||||
self.conv_textview.tv.set_editable(False)
|
||||
|
||||
def _on_drag_motion(self, widget, context, x, y, time):
|
||||
# FIXME: DND on non editable TextView, find a better way
|
||||
if not self.drag_entered:
|
||||
# We drag new data over the TextView, make it editable to catch dnd
|
||||
self.drag_entered_conv = True
|
||||
self.conv_textview.tv.set_editable(True)
|
||||
|
||||
def _process_command(self, message):
|
||||
if not message or message[0] != '/':
|
||||
return False
|
||||
|
@ -496,23 +548,23 @@ class ChatControlBase(MessageControl):
|
|||
self.clear(self.msg_textview) # clear message textview too
|
||||
return True
|
||||
elif message == 'compact' and not len(message_array):
|
||||
self.chat_buttons_set_visible(not self.hide_chat_buttons_current)
|
||||
self.chat_buttons_set_visible(not self.hide_chat_buttons)
|
||||
self.clear(self.msg_textview)
|
||||
return True
|
||||
return False
|
||||
|
||||
def send_message(self, message, keyID = '', type = 'chat', chatstate = None,
|
||||
msg_id = None, composing_jep = None, resource = None):
|
||||
msg_id = None, composing_xep = None, resource = None,
|
||||
process_command = True):
|
||||
'''Send the given message to the active tab. Doesn't return None if error
|
||||
'''
|
||||
if not message or message == '\n':
|
||||
return 1
|
||||
|
||||
|
||||
if not self._process_command(message):
|
||||
if not process_command or not self._process_command(message):
|
||||
ret = MessageControl.send_message(self, message, keyID, type = type,
|
||||
chatstate = chatstate, msg_id = msg_id,
|
||||
composing_jep = composing_jep, resource = resource,
|
||||
composing_xep = composing_xep, resource = resource,
|
||||
user_nick = self.user_nick)
|
||||
if ret:
|
||||
return ret
|
||||
|
@ -569,7 +621,6 @@ class ChatControlBase(MessageControl):
|
|||
full_jid != self.parent_win.get_active_jid() or \
|
||||
not self.parent_win.is_active() or not end)) or \
|
||||
(gc_message and \
|
||||
gajim.interface.minimized_controls.has_key(self.account) and \
|
||||
jid in gajim.interface.minimized_controls[self.account])) and \
|
||||
kind in ('incoming', 'incoming_queue'):
|
||||
# we want to have save this message in events list
|
||||
|
@ -667,31 +718,21 @@ class ChatControlBase(MessageControl):
|
|||
gajim.interface.instances['logs'][jid] = \
|
||||
history_window.HistoryWindow(jid, self.account)
|
||||
|
||||
def _on_compact_view_menuitem_activate(self, widget):
|
||||
isactive = widget.get_active()
|
||||
self.chat_buttons_set_visible(isactive)
|
||||
|
||||
def _on_minimize_menuitem_activate(self, widget):
|
||||
def on_minimize_menuitem_toggled(self, widget):
|
||||
'''When a grouchat is minimized, unparent the tab, put it in roster etc'''
|
||||
win = gajim.interface.msg_win_mgr.get_window(self.contact.jid, self.account)
|
||||
ctrl = win.get_control(self.contact.jid, self.account)
|
||||
|
||||
ctrl_page = win.notebook.page_num(ctrl.widget)
|
||||
control = win.notebook.get_nth_page(ctrl_page)
|
||||
|
||||
win.notebook.remove_page(ctrl_page)
|
||||
control.unparent()
|
||||
ctrl.parent_win = None
|
||||
|
||||
if not gajim.interface.minimized_controls.has_key(self.account):
|
||||
gajim.interface.minimized_controls[self.account] = {}
|
||||
gajim.interface.minimized_controls[self.account][self.contact.jid] = ctrl
|
||||
|
||||
del win._controls[self.account][self.contact.jid]
|
||||
|
||||
win.check_tabs()
|
||||
gajim.interface.roster.add_groupchat_to_roster(self.account,
|
||||
self.contact.jid, status = self.subject)
|
||||
old_value = False
|
||||
minimized_gc = gajim.config.get_per('accounts', self.account,
|
||||
'minimized_gc').split()
|
||||
if self.contact.jid in minimized_gc:
|
||||
old_value = True
|
||||
minimize = widget.get_active()
|
||||
if minimize and not self.contact.jid in minimized_gc:
|
||||
minimized_gc.append(self.contact.jid)
|
||||
if not minimize and self.contact.jid in minimized_gc:
|
||||
minimized_gc.remove(self.contact.jid)
|
||||
if old_value != minimize:
|
||||
gajim.config.set_per('accounts', self.account, 'minimized_gc',
|
||||
' '.join(minimized_gc))
|
||||
|
||||
def set_control_active(self, state):
|
||||
if state:
|
||||
|
@ -825,11 +866,14 @@ class ChatControlBase(MessageControl):
|
|||
room_jid, nick = gajim.get_room_and_nick_from_fjid(jid)
|
||||
groupchat_control = gajim.interface.msg_win_mgr.get_control(
|
||||
room_jid, self.account)
|
||||
if not groupchat_control and \
|
||||
gajim.interface.minimized_controls.has_key(self.account) and \
|
||||
room_jid in gajim.interface.minimized_controls[self.account]:
|
||||
if room_jid in gajim.interface.minimized_controls[self.account]:
|
||||
groupchat_control = \
|
||||
gajim.interface.minimized_controls[self.account][room_jid]
|
||||
contact = \
|
||||
gajim.contacts.get_contact_with_highest_priority(self.account, \
|
||||
room_jid)
|
||||
if contact:
|
||||
gajim.interface.roster.draw_contact(room_jid, self.account)
|
||||
groupchat_control.draw_contact(nick)
|
||||
mw = gajim.interface.msg_win_mgr.get_window(room_jid, self.account)
|
||||
if mw:
|
||||
|
@ -903,7 +947,7 @@ class ChatControl(ChatControlBase):
|
|||
'''A control for standard 1-1 chat'''
|
||||
TYPE_ID = message_control.TYPE_CHAT
|
||||
old_msg_kind = None # last kind of the printed message
|
||||
CHAT_CMDS = ['clear', 'compact', 'help', 'ping']
|
||||
CHAT_CMDS = ['clear', 'compact', 'help', 'me', 'ping', 'say']
|
||||
|
||||
def __init__(self, parent_win, contact, acct, resource = None):
|
||||
ChatControlBase.__init__(self, self.TYPE_ID, parent_win,
|
||||
|
@ -915,21 +959,10 @@ class ChatControl(ChatControlBase):
|
|||
id = widget.connect('clicked', self.on_actions_button_clicked)
|
||||
self.handlers[id] = widget
|
||||
|
||||
hide_chat_buttons_always = gajim.config.get(
|
||||
'always_hide_chat_buttons')
|
||||
self.chat_buttons_set_visible(hide_chat_buttons_always)
|
||||
compact_view = gajim.config.get('compact_view')
|
||||
self.chat_buttons_set_visible(compact_view)
|
||||
self.widget_set_visible(self.xml.get_widget('banner_eventbox'),
|
||||
gajim.config.get('hide_chat_banner'))
|
||||
# Initialize drag-n-drop
|
||||
self.TARGET_TYPE_URI_LIST = 80
|
||||
self.dnd_list = [ ( 'text/uri-list', 0, self.TARGET_TYPE_URI_LIST ) ]
|
||||
id = self.widget.connect('drag_data_received',
|
||||
self._on_drag_data_received)
|
||||
self.handlers[id] = self.widget
|
||||
self.widget.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
|
||||
gtk.DEST_DEFAULT_HIGHLIGHT |
|
||||
gtk.DEST_DEFAULT_DROP,
|
||||
self.dnd_list, gtk.gdk.ACTION_COPY)
|
||||
|
||||
# keep timeout id and window obj for possible big avatar
|
||||
# it is on enter-notify and leave-notify so no need to be per jid
|
||||
|
@ -1085,6 +1118,8 @@ class ChatControl(ChatControlBase):
|
|||
jid = contact.jid
|
||||
|
||||
banner_name_label = self.xml.get_widget('banner_name_label')
|
||||
banner_eventbox = self.xml.get_widget('banner_eventbox')
|
||||
|
||||
name = contact.get_shown_name()
|
||||
if self.resource:
|
||||
name += '/' + self.resource
|
||||
|
@ -1111,8 +1146,10 @@ class ChatControl(ChatControlBase):
|
|||
|
||||
status = contact.status
|
||||
if status is not None:
|
||||
self.status_tooltip.set_tip(banner_eventbox, status)
|
||||
self.status_tooltip.enable()
|
||||
banner_name_label.set_ellipsize(pango.ELLIPSIZE_END)
|
||||
status = helpers.reduce_chars_newlines(status, max_lines = 2)
|
||||
status = helpers.reduce_chars_newlines(status, max_lines = 1)
|
||||
status_escaped = gobject.markup_escape_text(status)
|
||||
|
||||
font_attrs, font_attrs_small = self.get_font_attrs()
|
||||
|
@ -1121,12 +1158,12 @@ class ChatControl(ChatControlBase):
|
|||
if cs and st in ('composing_only', 'all'):
|
||||
if contact.show == 'offline':
|
||||
chatstate = ''
|
||||
elif contact.composing_jep == 'JEP-0085':
|
||||
elif contact.composing_xep == 'XEP-0085':
|
||||
if st == 'all' or cs == 'composing':
|
||||
chatstate = helpers.get_uf_chatstate(cs)
|
||||
else:
|
||||
chatstate = ''
|
||||
elif contact.composing_jep == 'JEP-0022':
|
||||
elif contact.composing_xep == 'XEP-0022':
|
||||
if cs in ('composing', 'paused'):
|
||||
# only print composing, paused
|
||||
chatstate = helpers.get_uf_chatstate(cs)
|
||||
|
@ -1145,9 +1182,6 @@ class ChatControl(ChatControlBase):
|
|||
if status_escaped:
|
||||
label_text += '\n<span %s>%s</span>' %\
|
||||
(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()
|
||||
else:
|
||||
self.status_tooltip.disable()
|
||||
# setup the label that holds name and jid
|
||||
|
@ -1196,6 +1230,9 @@ class ChatControl(ChatControlBase):
|
|||
if message_array == ['']:
|
||||
message_array = []
|
||||
|
||||
if command == 'me':
|
||||
return False # This is not really a command
|
||||
|
||||
if command == 'help':
|
||||
if len(message_array):
|
||||
subcommand = message_array.pop(0)
|
||||
|
@ -1204,10 +1241,19 @@ class ChatControl(ChatControlBase):
|
|||
self.get_command_help(command)
|
||||
self.clear(self.msg_textview)
|
||||
return True
|
||||
elif command == 'ping' and not len(message_array):
|
||||
gajim.connections[self.account].sendPing(self.contact)
|
||||
elif command == 'ping':
|
||||
if not len(message_array):
|
||||
gajim.connections[self.account].sendPing(self.contact)
|
||||
else:
|
||||
self.get_command_help(command)
|
||||
self.clear(self.msg_textview)
|
||||
return True
|
||||
elif command == 'say':
|
||||
return False
|
||||
else:
|
||||
self.print_conversation(_('No such command: /%s (if you want to send '
|
||||
'this, prefix it with /say)') % command, 'info')
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_command_help(self, command):
|
||||
|
@ -1215,13 +1261,21 @@ class ChatControl(ChatControlBase):
|
|||
self.print_conversation(_('Commands: %s') % ChatControl.CHAT_CMDS,
|
||||
'info')
|
||||
elif command == 'clear':
|
||||
self.print_conversation(_('Usage: /%s, clears the text window.'),
|
||||
'info')
|
||||
self.print_conversation(_('Usage: /%s, clears the text window.') % \
|
||||
command, 'info')
|
||||
elif command == 'compact':
|
||||
self.print_conversation(_('Usage: /%s, hide the chat buttons.'),
|
||||
'info')
|
||||
self.print_conversation(_('Usage: /%s, hide the chat buttons.') % \
|
||||
command, 'info')
|
||||
elif command == 'me':
|
||||
self.print_conversation(_('Usage: /%s <action>, sends action to the '
|
||||
'current group chat. Use third person. (e.g. /%s explodes.)') % \
|
||||
(command, command), 'info')
|
||||
elif command == 'ping':
|
||||
self.print_conversation(_(''), 'info')
|
||||
self.print_conversation(_('Usage: /%s, sends a ping to the contact') %\
|
||||
command, 'info')
|
||||
elif command == 'say':
|
||||
self.print_conversation(_('Usage: /%s, send the message to the contact') %\
|
||||
command, 'info')
|
||||
else:
|
||||
self.print_conversation(_('No help info for /%s') % command, 'info')
|
||||
|
||||
|
@ -1230,6 +1284,12 @@ class ChatControl(ChatControlBase):
|
|||
if message in ('', None, '\n') or self._process_command(message):
|
||||
return
|
||||
|
||||
# Do we need to process command for the message ?
|
||||
process_command = True
|
||||
if message.startswith('/say'):
|
||||
message = message[5:]
|
||||
process_command = False
|
||||
|
||||
# refresh timers
|
||||
self.reset_kbd_mouse_timeout_vars()
|
||||
|
||||
|
@ -1244,10 +1304,10 @@ class ChatControl(ChatControlBase):
|
|||
|
||||
chatstates_on = gajim.config.get('outgoing_chat_state_notifications') != \
|
||||
'disabled'
|
||||
composing_jep = contact.composing_jep
|
||||
composing_xep = contact.composing_xep
|
||||
chatstate_to_send = None
|
||||
if chatstates_on and contact is not None:
|
||||
if composing_jep is None:
|
||||
if composing_xep is None:
|
||||
# no info about peer
|
||||
# send active to discover chat state capabilities
|
||||
# this is here (and not in send_chatstate)
|
||||
|
@ -1256,13 +1316,13 @@ class ChatControl(ChatControlBase):
|
|||
|
||||
if contact.our_chatstate:
|
||||
# We already asked for xep 85, don't ask it twice
|
||||
composing_jep = 'asked_once'
|
||||
composing_xep = 'asked_once'
|
||||
|
||||
chatstate_to_send = 'active'
|
||||
contact.our_chatstate = 'ask' # pseudo state
|
||||
# if peer supports jep85 and we are not 'ask', send 'active'
|
||||
# NOTE: first active and 'ask' is set in gajim.py
|
||||
elif composing_jep is not False:
|
||||
elif composing_xep is not False:
|
||||
#send active chatstate on every message (as JEP says)
|
||||
chatstate_to_send = 'active'
|
||||
contact.our_chatstate = 'active'
|
||||
|
@ -1272,7 +1332,8 @@ class ChatControl(ChatControlBase):
|
|||
self._schedule_activity_timers()
|
||||
|
||||
if not ChatControlBase.send_message(self, message, keyID, type = 'chat',
|
||||
chatstate = chatstate_to_send, composing_jep = composing_jep):
|
||||
chatstate = chatstate_to_send, composing_xep = composing_xep,
|
||||
process_command = process_command):
|
||||
self.print_conversation(message, self.contact.jid,
|
||||
encrypted = encrypted)
|
||||
|
||||
|
@ -1441,13 +1502,13 @@ class ChatControl(ChatControlBase):
|
|||
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
|
||||
# Set tab image (always 16x16); unread messages show the 'event' image
|
||||
tab_img = None
|
||||
|
||||
if num_unread and gajim.config.get('show_unread_tab_icon'):
|
||||
img_16 = gajim.interface.roster.get_appropriate_state_images(
|
||||
self.contact.jid, icon_name = 'message')
|
||||
tab_img = img_16['message']
|
||||
self.contact.jid, icon_name = 'event')
|
||||
tab_img = img_16['event']
|
||||
else:
|
||||
contact = gajim.contacts.get_contact_with_highest_priority(
|
||||
self.account, self.contact.jid)
|
||||
|
@ -1474,7 +1535,6 @@ class ChatControl(ChatControlBase):
|
|||
toggle_gpg_menuitem = xml.get_widget('toggle_gpg_menuitem')
|
||||
add_to_roster_menuitem = xml.get_widget('add_to_roster_menuitem')
|
||||
send_file_menuitem = xml.get_widget('send_file_menuitem')
|
||||
compact_view_menuitem = xml.get_widget('compact_view_menuitem')
|
||||
information_menuitem = xml.get_widget('information_menuitem')
|
||||
|
||||
contact = self.parent_win.get_active_contact()
|
||||
|
@ -1493,14 +1553,14 @@ class ChatControl(ChatControlBase):
|
|||
|
||||
# If we don't have resource, we can't do file transfer
|
||||
# in transports, contact holds our info we need to disable it too
|
||||
if contact.resource and contact.jid.find('@') != -1:
|
||||
if self.TYPE_ID == message_control.TYPE_PM and self.gc_contact.jid and \
|
||||
self.gc_contact.resource:
|
||||
send_file_menuitem.set_sensitive(True)
|
||||
elif contact.resource and contact.jid.find('@') != -1:
|
||||
send_file_menuitem.set_sensitive(True)
|
||||
else:
|
||||
send_file_menuitem.set_sensitive(False)
|
||||
|
||||
# compact_view_menuitem
|
||||
compact_view_menuitem.set_active(self.hide_chat_buttons_current)
|
||||
|
||||
# add_to_roster_menuitem
|
||||
if _('Not in Roster') in contact.groups:
|
||||
add_to_roster_menuitem.show()
|
||||
|
@ -1517,9 +1577,6 @@ class ChatControl(ChatControlBase):
|
|||
id = send_file_menuitem.connect('activate',
|
||||
self._on_send_file_menuitem_activate)
|
||||
self.handlers[id] = send_file_menuitem
|
||||
id = compact_view_menuitem.connect('activate',
|
||||
self._on_compact_view_menuitem_activate)
|
||||
self.handlers[id] = compact_view_menuitem
|
||||
id = add_to_roster_menuitem.connect('activate',
|
||||
self._on_add_to_roster_menuitem_activate)
|
||||
self.handlers[id] = add_to_roster_menuitem
|
||||
|
@ -1565,7 +1622,7 @@ class ChatControl(ChatControlBase):
|
|||
if contact.show == 'offline':
|
||||
return
|
||||
|
||||
if contact.composing_jep is False: # jid cannot do jep85 nor jep22
|
||||
if contact.composing_xep is False: # jid cannot do xep85 nor xep22
|
||||
return
|
||||
|
||||
# if the new state we wanna send (state) equals
|
||||
|
@ -1573,7 +1630,7 @@ class ChatControl(ChatControlBase):
|
|||
if contact.our_chatstate == state:
|
||||
return
|
||||
|
||||
if contact.composing_jep is None:
|
||||
if contact.composing_xep is None:
|
||||
# we don't know anything about jid, so return
|
||||
# NOTE:
|
||||
# send 'active', set current state to 'ask' and return is done
|
||||
|
@ -1587,7 +1644,7 @@ class ChatControl(ChatControlBase):
|
|||
|
||||
# in JEP22, when we already sent stop composing
|
||||
# notification on paused, don't resend it
|
||||
if contact.composing_jep == 'JEP-0022' and \
|
||||
if contact.composing_xep == 'XEP-0022' and \
|
||||
contact.our_chatstate in ('paused', 'active', 'inactive') and \
|
||||
state is not 'composing': # not composing == in (active, inactive, gone)
|
||||
contact.our_chatstate = 'active'
|
||||
|
@ -1609,7 +1666,7 @@ class ChatControl(ChatControlBase):
|
|||
self.reset_kbd_mouse_timeout_vars()
|
||||
|
||||
MessageControl.send_message(self, None, chatstate = state,
|
||||
msg_id = contact.msg_id, composing_jep = contact.composing_jep)
|
||||
msg_id = contact.msg_id, composing_xep = contact.composing_xep)
|
||||
contact.our_chatstate = state
|
||||
if contact.our_chatstate == 'active':
|
||||
self.reset_kbd_mouse_timeout_vars()
|
||||
|
@ -1638,20 +1695,19 @@ class ChatControl(ChatControlBase):
|
|||
del self.handlers[i]
|
||||
self.conv_textview.del_handlers()
|
||||
self.msg_textview.destroy()
|
||||
|
||||
|
||||
def allow_shutdown(self, method):
|
||||
if time.time() - gajim.last_message_time[self.account]\
|
||||
[self.get_full_jid()] < 2:
|
||||
# 2 seconds
|
||||
dialog = dialogs.ConfirmationDialog(
|
||||
#%s is being replaced in the code with JID
|
||||
# %s is being replaced in the code with 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:
|
||||
return False #stop the propagation of the event
|
||||
return True
|
||||
return 'no' # stop the propagation of the event
|
||||
return 'yes'
|
||||
|
||||
def handle_incoming_chatstate(self):
|
||||
''' handle incoming chatstate that jid SENT TO us '''
|
||||
|
@ -1710,17 +1766,23 @@ class ChatControl(ChatControlBase):
|
|||
|
||||
def _on_drag_data_received(self, widget, context, x, y, selection,
|
||||
target_type, timestamp):
|
||||
# If not resource, we can't send file
|
||||
if not self.contact.resource:
|
||||
# If no resource is known, we can't send a file
|
||||
if self.TYPE_ID == message_control.TYPE_PM:
|
||||
c = self.gc_contact
|
||||
else:
|
||||
c = self.contact
|
||||
if not c.resource:
|
||||
return
|
||||
if target_type == self.TARGET_TYPE_URI_LIST:
|
||||
if not selection.data:
|
||||
return
|
||||
uri = selection.data.strip()
|
||||
uri_splitted = uri.split() # we may have more than one file dropped
|
||||
for uri in uri_splitted:
|
||||
path = helpers.get_file_path_from_dnd_dropped_uri(uri)
|
||||
if os.path.isfile(path): # is it file?
|
||||
ft = gajim.interface.instances['file_transfers']
|
||||
ft.send_file(self.account, self.contact, path)
|
||||
ft.send_file(self.account, c, path)
|
||||
|
||||
def _on_message_tv_buffer_changed(self, textbuffer):
|
||||
self.kbd_activity_in_last_5_secs = True
|
||||
|
@ -1833,7 +1895,7 @@ class ChatControl(ChatControlBase):
|
|||
show_transports = gajim.config.get('show_transports_group')
|
||||
if (not show_transports and gajim.jid_is_transport(jid)) or \
|
||||
(not show_offline and typ == 'chat' and \
|
||||
len(gajim.contacts.get_contact(self.account, jid)) < 2):
|
||||
len(gajim.contacts.get_contacts(self.account, jid)) < 2):
|
||||
gajim.interface.roster.really_remove_contact(self.contact,
|
||||
self.account)
|
||||
elif typ == 'pm':
|
||||
|
@ -1919,8 +1981,12 @@ class ChatControl(ChatControlBase):
|
|||
self.bigger_avatar_window.window.set_cursor(cursor)
|
||||
|
||||
def _on_send_file_menuitem_activate(self, widget):
|
||||
if self.TYPE_ID == message_control.TYPE_PM:
|
||||
c = self.gc_contact
|
||||
else:
|
||||
c = self.contact
|
||||
gajim.interface.instances['file_transfers'].show_file_send_request(
|
||||
self.account, self.contact)
|
||||
self.account, c)
|
||||
|
||||
def _on_add_to_roster_menuitem_activate(self, widget):
|
||||
dialogs.AddNewContactWindow(self.account, self.contact.jid)
|
||||
|
|
|
@ -63,10 +63,11 @@ class OldEntry(xmpp.Node, object):
|
|||
else:
|
||||
main_feed = None
|
||||
|
||||
if self.getTag('source-feed') is not None:
|
||||
source_feed = self.getTag('source-feed').getTagData('title')
|
||||
if self.getTag('feed') is not None:
|
||||
source_feed = self.getTag('feed').getTagData('title')
|
||||
else:
|
||||
source_feed = None
|
||||
|
||||
|
||||
if main_feed is not None and source_feed is not None:
|
||||
return u'%s: %s' % (main_feed, source_feed)
|
||||
|
@ -78,14 +79,13 @@ class OldEntry(xmpp.Node, object):
|
|||
return u''
|
||||
|
||||
feed_title = property(get_feed_title, None, None,
|
||||
''' Title of feed. It is built from entry's original feed title and title of feed
|
||||
''' Title of feed. It is built from entry''s original feed title and title of feed
|
||||
which delivered this entry. ''')
|
||||
|
||||
def get_feed_link(self):
|
||||
''' Get a link to main page of feed (in pubsub.com: second link of rel='alternate',
|
||||
first contains raw xml data). '''
|
||||
''' Get source link '''
|
||||
try:
|
||||
return self.getTag('source-feed').getTags('link', {'rel':'alternate'})[1].getData()
|
||||
return self.getTag('feed').getTags('link',{'rel':'alternate'})[1].getData()
|
||||
except:
|
||||
return None
|
||||
|
||||
|
|
|
@ -0,0 +1,259 @@
|
|||
##
|
||||
## Copyright (C) 2006 Gajim Team
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
|
||||
from itertools import *
|
||||
import xmpp
|
||||
import xmpp.features_nb
|
||||
import gajim
|
||||
|
||||
class CapsCache(object):
|
||||
''' This object keeps the mapping between caps data and real disco
|
||||
features they represent, and provides simple way to query that info.
|
||||
It is application-wide, that is there's one object for all
|
||||
connections.
|
||||
Goals:
|
||||
* handle storing/retrieving info from database
|
||||
* cache info in memory
|
||||
* expose simple interface
|
||||
Properties:
|
||||
* one object for all connections (move to logger.py?)
|
||||
* store info efficiently (a set() of urls -- we can assume there won't be
|
||||
too much of these, ensure that (X,Y,Z1) and (X,Y,Z2) has different
|
||||
features.
|
||||
|
||||
Connections with other objects: (TODO)
|
||||
|
||||
Interface:
|
||||
|
||||
# object creation
|
||||
>>> cc=CapsCache(logger_object)
|
||||
|
||||
>>> caps=('http://exodus.jabberstudio.org/caps', '0.9', None) # node, ver, ext
|
||||
>>> muc='http://jabber.org/protocol/muc'
|
||||
>>> chatstates='http://jabber.org/protocol/chatstates'
|
||||
|
||||
# retrieving data
|
||||
>>> muc in cc[caps].features
|
||||
True
|
||||
>>> muc in cc[caps]
|
||||
True
|
||||
>>> chatstates in cc[caps]
|
||||
False
|
||||
>>> cc[caps].identities
|
||||
set({'category':'client', 'type':'pc'})
|
||||
>>> x=cc[caps] # more efficient if making several queries for one set of caps
|
||||
ATypicalBlackBoxObject
|
||||
>>> muc in x
|
||||
True
|
||||
>>> x.node
|
||||
'http://exodus.jabberstudio.org/caps'
|
||||
|
||||
# retrieving data (multiple exts case)
|
||||
>>> caps=('http://gajim.org/caps', '0.9', ('csn', 'ft'))
|
||||
>>> muc in cc[caps]
|
||||
True
|
||||
|
||||
# setting data
|
||||
>>> newcaps=('http://exodus.jabberstudio.org/caps', '0.9a', None)
|
||||
>>> cc[newcaps].identities.add({'category':'client', 'type':'pc', 'name':'Gajim'})
|
||||
>>> cc[newcaps].features+=muc # same as:
|
||||
>>> cc[newcaps]+=muc
|
||||
>>> cc[newcaps]['csn']+=chatstates # adding data as if ext was 'csn'
|
||||
# warning: no feature removal!
|
||||
'''
|
||||
def __init__(self, logger=None):
|
||||
''' Create a cache for entity capabilities. '''
|
||||
# our containers:
|
||||
# __names is a string cache; every string long enough is given
|
||||
# another object, and we will have plenty of identical long
|
||||
# strings. therefore we can cache them
|
||||
# TODO: maybe put all known xmpp namespace strings here
|
||||
# (strings given in xmpppy)?
|
||||
# __cache is a dictionary mapping: pair of node and version maps
|
||||
# to CapsCacheItem object
|
||||
# __CacheItem is a class that stores data about particular
|
||||
# client (node/version pair)
|
||||
self.__names = {}
|
||||
self.__cache = {}
|
||||
|
||||
class CacheItem(object):
|
||||
''' TODO: logging data into db '''
|
||||
def __init__(ciself, node, version, ext=None):
|
||||
# cached into db
|
||||
ciself.node = node
|
||||
ciself.version = version
|
||||
ciself.features = set()
|
||||
ciself.ext = ext
|
||||
ciself.exts = {}
|
||||
|
||||
# set of tuples: (category, type, name)
|
||||
# (dictionaries are not hashable, so cannot be in sets)
|
||||
ciself.identities = set()
|
||||
|
||||
# not cached into db:
|
||||
# have we sent the query?
|
||||
# 0 == not queried
|
||||
# 1 == queried
|
||||
# 2 == got the answer
|
||||
ciself.queried = 0
|
||||
|
||||
class CacheQuery(object):
|
||||
def __init__(cqself, proxied):
|
||||
cqself.proxied=proxied
|
||||
|
||||
def __getattr__(cqself, obj):
|
||||
if obj!='exts': return getattr(cqself.proxied[0], obj)
|
||||
return set(chain(ci.features for ci in cqself.proxied))
|
||||
|
||||
def __getitem__(ciself, exts):
|
||||
if not exts: # (), [], None, False, whatever
|
||||
return ciself
|
||||
if isinstance(exts, basestring):
|
||||
exts=(exts,)
|
||||
if len(exts)==1:
|
||||
ext=exts[0]
|
||||
if ext in ciself.exts:
|
||||
return ciself.exts[ext]
|
||||
x=CacheItem(ciself.node, ciself.version, ext)
|
||||
ciself.exts[ext]=x
|
||||
return x
|
||||
proxied = [ciself]
|
||||
proxied.extend(ciself[(e,)] for e in exts)
|
||||
return ciself.CacheQuery(proxied)
|
||||
|
||||
def update(ciself, identities, features):
|
||||
# NOTE: self refers to CapsCache object, not to CacheItem
|
||||
self.identities=identities
|
||||
self.features=features
|
||||
self.logger.add_caps_entry(
|
||||
ciself.node, ciself.version, ciself.ext,
|
||||
identities, features)
|
||||
|
||||
self.__CacheItem = CacheItem
|
||||
|
||||
# prepopulate data which we are sure of; note: we do not log these info
|
||||
gajimnode = 'http://gajim.org/caps'
|
||||
|
||||
gajimcaps=self[(gajimnode, '0.11.1')]
|
||||
gajimcaps.category='client'
|
||||
gajimcaps.type='pc'
|
||||
gajimcaps.features=set((xmpp.NS_BYTESTREAM, xmpp.NS_SI,
|
||||
xmpp.NS_FILE, xmpp.NS_MUC, xmpp.NS_COMMANDS,
|
||||
xmpp.NS_DISCO_INFO, xmpp.NS_PING, xmpp.NS_TIME_REVISED))
|
||||
gajimcaps['cstates'].features=set((xmpp.NS_CHATSTATES,))
|
||||
gajimcaps['xhtml'].features=set((xmpp.NS_XHTML_IM,))
|
||||
|
||||
# TODO: older gajim versions
|
||||
|
||||
# start logging data from the net
|
||||
self.logger = logger
|
||||
|
||||
def load_from_db(self):
|
||||
# get data from logger...
|
||||
if self.logger is not None:
|
||||
for node, ver, ext, identities, features in self.logger.iter_caps_data():
|
||||
x=self[(node, ver, ext)]
|
||||
x.identities=identities
|
||||
x.features=features
|
||||
x.queried=2
|
||||
|
||||
def __getitem__(self, caps):
|
||||
node_version = caps[:2]
|
||||
if node_version in self.__cache:
|
||||
return self.__cache[node_version][caps[2]]
|
||||
node, version = self.__names.setdefault(caps[0], caps[0]), caps[1]
|
||||
x=self.__CacheItem(node, version)
|
||||
self.__cache[(node, version)]=x
|
||||
return x
|
||||
|
||||
def preload(self, account, jid, node, ver, exts):
|
||||
''' Preload data about (node, ver, exts) caps using disco
|
||||
query to jid using proper connection. Don't query if
|
||||
the data is already in cache. '''
|
||||
q=self[(node, ver, ())]
|
||||
qq=q
|
||||
|
||||
if q.queried==0:
|
||||
# do query for bare node+version pair
|
||||
# this will create proper object
|
||||
q.queried=1
|
||||
account.discoverInfo(jid, '%s#%s' % (node, ver))
|
||||
|
||||
for ext in exts:
|
||||
qq=q[ext]
|
||||
if qq.queried==0:
|
||||
# do query for node+version+ext triple
|
||||
qq.queried=1
|
||||
account.discoverInfo(jid, '%s#%s' % (node, ext))
|
||||
|
||||
gajim.capscache = CapsCache(gajim.logger)
|
||||
|
||||
class ConnectionCaps(object):
|
||||
''' This class highly depends on that it is a part of Connection class. '''
|
||||
def _capsPresenceCB(self, con, presence):
|
||||
''' Handle incoming presence stanzas... This is a callback
|
||||
for xmpp registered in connection_handlers.py'''
|
||||
|
||||
# get the caps element
|
||||
caps=presence.getTag('c')
|
||||
if not caps: return
|
||||
|
||||
node, ver=caps['node'], caps['ver']
|
||||
if node is None or ver is None:
|
||||
# improper caps in stanza, ignoring
|
||||
return
|
||||
|
||||
try:
|
||||
exts=caps['ext'].split(' ')
|
||||
except AttributeError:
|
||||
# no exts means no exts, a perfectly valid case
|
||||
exts=[]
|
||||
|
||||
# we will put these into proper Contact object and ask
|
||||
# for disco... so that disco will learn how to interpret
|
||||
# these caps
|
||||
|
||||
jid=str(presence.getFrom())
|
||||
|
||||
# start disco query...
|
||||
gajim.capscache.preload(self, jid, node, ver, exts)
|
||||
|
||||
contact=gajim.contacts.get_contact_from_full_jid(self.name, jid)
|
||||
if contact in [None, []]:
|
||||
return # TODO: a way to put contact not-in-roster into Contacts
|
||||
elif isinstance(contact, list):
|
||||
contact = contact[0]
|
||||
|
||||
# overwriting old data
|
||||
contact.caps_node=node
|
||||
contact.caps_ver=ver
|
||||
contact.caps_exts=exts
|
||||
|
||||
def _capsDiscoCB(self, jid, node, identities, features, data):
|
||||
contact=gajim.contacts.get_contact_from_full_jid(self.name, jid)
|
||||
if not contact: return
|
||||
if not contact.caps_node: return # we didn't asked for that?
|
||||
if not node.startswith(contact.caps_node+'#'): return
|
||||
node, ext = node.split('#')
|
||||
if ext==contact.caps_ver: # this can be also version (like '0.9')
|
||||
exts=None
|
||||
else:
|
||||
exts=(ext,)
|
||||
|
||||
# if we don't have this info already...
|
||||
caps=gajim.capscache[(node, contact.caps_ver, exts)]
|
||||
if caps.queried==2: return
|
||||
|
||||
identities=set((i['category'], i['type'], i.get('name')) for i in identities)
|
||||
caps.update(identities, features)
|
||||
|
|
@ -42,6 +42,7 @@ def create_log_db():
|
|||
# logs.jid_id --> jids.jid_id but Sqlite doesn't do FK etc so it's done in python code
|
||||
# jids.jid text column will be JID if TC-related, room_jid if GC-related,
|
||||
# ROOM_JID/nick if pm-related.
|
||||
# also check optparser.py, which updates databases on gajim updates
|
||||
cur.executescript(
|
||||
'''
|
||||
CREATE TABLE jids(
|
||||
|
@ -74,6 +75,12 @@ def create_log_db():
|
|||
);
|
||||
|
||||
CREATE INDEX idx_logs_jid_id_kind ON logs (jid_id, kind);
|
||||
|
||||
CREATE TABLE caps_cache (
|
||||
node TEXT,
|
||||
ver TEXT,
|
||||
ext TEXT,
|
||||
data BLOB);
|
||||
'''
|
||||
)
|
||||
|
||||
|
|
|
@ -236,12 +236,42 @@ class LeaveGroupchatsCommand(AdHocCommand):
|
|||
return False
|
||||
|
||||
|
||||
class ForwardMessagesCommand(AdHocCommand):
|
||||
# http://www.xmpp.org/extensions/xep-0146.html#forward
|
||||
commandnode = 'forward-messages'
|
||||
commandname = _('Forward unread messages')
|
||||
|
||||
@staticmethod
|
||||
def isVisibleFor(samejid):
|
||||
''' Change status is visible only if the entity has the same bare jid. '''
|
||||
return samejid
|
||||
|
||||
def execute(self, request):
|
||||
account = self.connection.name
|
||||
# Forward messages
|
||||
events = gajim.events.get_events(account, types=['chat', 'normal'])
|
||||
j, resource = gajim.get_room_and_nick_from_fjid(self.jid)
|
||||
for jid in events:
|
||||
for event in events[jid]:
|
||||
self.connection.send_message(j, event.parameters[0], '',
|
||||
type=event.type_, subject=event.parameters[1],
|
||||
resource=resource, forward_from=jid)
|
||||
|
||||
# Inform other client of completion
|
||||
response, cmd = self.buildResponse(request, status = 'completed')
|
||||
cmd.addChild('note', {}, _('All unread messages have been forwarded.'))
|
||||
|
||||
self.connection.connection.send(response)
|
||||
|
||||
return False # finish the session
|
||||
|
||||
class ConnectionCommands:
|
||||
''' This class depends on that it is a part of Connection() class. '''
|
||||
def __init__(self):
|
||||
# a list of all commands exposed: node -> command class
|
||||
self.__commands = {}
|
||||
for cmdobj in (ChangeStatusCommand, LeaveGroupchatsCommand):
|
||||
for cmdobj in (ChangeStatusCommand, ForwardMessagesCommand,
|
||||
LeaveGroupchatsCommand):
|
||||
self.__commands[cmdobj.commandnode] = cmdobj
|
||||
|
||||
# a list of sessions; keys are tuples (jid, sessionid, node)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
## Copyright (C) 2005 Travis Shirk <travis@pobox.com>
|
||||
## Copyright (C) 2005 Norman Rasmussen <norman@rasmussen.co.za>
|
||||
## Copyright (C) 2006 Stefan Bethge <stefan@lanpartei.de>
|
||||
## Copyright (C) 2007 Julien Pivotto <roidelapluie@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
|
||||
|
@ -81,7 +82,7 @@ class Config:
|
|||
'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 ],
|
||||
'roster_theme': [ opt_str, 'gtk+', '', True ],
|
||||
'roster_theme': [ opt_str, _('default'), '', True ],
|
||||
'saveposition': [ opt_bool, True ],
|
||||
'mergeaccounts': [ opt_bool, False, '', True ],
|
||||
'sort_by_show': [ opt_bool, True, '', True ],
|
||||
|
@ -182,12 +183,12 @@ class Config:
|
|||
'tooltip_avatar_height': [opt_int, 125],
|
||||
'vcard_avatar_width': [opt_int, 200],
|
||||
'vcard_avatar_height': [opt_int, 200],
|
||||
'notification_preview_message': [opt_bool, True, _('Preview new messages in notification popup?')],
|
||||
'notification_position_x': [opt_int, -1],
|
||||
'notification_position_y': [opt_int, -1],
|
||||
'notification_avatar_width': [opt_int, 48],
|
||||
'notification_avatar_height': [opt_int, 48],
|
||||
'muc_highlight_words': [opt_str, '', _('A semicolon-separated list of words that will be highlighted in group chats.')],
|
||||
'minimize_autojoined_rooms': [opt_bool, False, _('If True, autojoined bookmarked rooms will be minimized on startup.')],
|
||||
'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.')],
|
||||
'check_if_gajim_is_default': [opt_bool, True, _('If True, Gajim will check if it\'s the default jabber client 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.')],
|
||||
|
@ -211,8 +212,7 @@ class Config:
|
|||
_('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.')],
|
||||
'compact_view': [opt_bool, False, _('Hides the buttons in chat windows.')],
|
||||
'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 group chat occupants list in group chat window.')],
|
||||
|
@ -228,6 +228,7 @@ class Config:
|
|||
'scroll_roster_to_last_message': [opt_bool, True, _('If True, Gajim will scroll and select the contact who sent you the last message, if chat window is not already opened.')],
|
||||
'use_latex': [opt_bool, False, _('If True, Gajim will convert string between $$ and $$ to an image using dvips and convert before insterting it in chat window.')],
|
||||
'change_status_window_timeout': [opt_int, 15, _('Time of inactivity needed before the change status window closes down.')],
|
||||
'max_conversation_lines': [opt_int, 500, _('Maximum number of lines that are printed in conversations. Oldest lines are cleared.')],
|
||||
}
|
||||
|
||||
__options_per_key = {
|
||||
|
@ -260,6 +261,7 @@ class Config:
|
|||
'gpgpassword': [ opt_str, '' ],
|
||||
'sync_with_global_status': [ opt_bool, False, ],
|
||||
'no_log_for': [ opt_str, '' ],
|
||||
'minimized_gc': [ opt_str, '' ],
|
||||
'attached_gpg_keys': [ opt_str, '' ],
|
||||
'keep_alives_enabled': [ opt_bool, True],
|
||||
# send keepalive every N seconds of inactivity
|
||||
|
@ -387,8 +389,8 @@ class Config:
|
|||
|
||||
themes_default = {
|
||||
# sorted alphanum
|
||||
'gtk+': [ '', '', '', 'B', '', '','', 'I', '', '', '', '', '','', '',
|
||||
'B' ],
|
||||
_('default'): [ '', '', '', 'B', '', '','', 'I', '', '', '', '', '','',
|
||||
'', 'B' ],
|
||||
|
||||
_('green'): [ '', '#94aa8c', '', 'B', '#0000ff', '#eff3e7',
|
||||
'', 'I', '#000000', '', '', '', '',
|
||||
|
|
|
@ -25,6 +25,11 @@ def fse(s):
|
|||
'''Convert from filesystem encoding if not already Unicode'''
|
||||
return unicode(s, sys.getfilesystemencoding())
|
||||
|
||||
def windowsify(s):
|
||||
if os.name == 'nt':
|
||||
return s.capitalize()
|
||||
return s
|
||||
|
||||
class ConfigPaths:
|
||||
def __init__(self, root=None):
|
||||
self.root = root
|
||||
|
@ -68,51 +73,47 @@ class ConfigPaths:
|
|||
for key in self.paths.iterkeys():
|
||||
yield (key, self[key])
|
||||
|
||||
def windowsify(s):
|
||||
if os.name == 'nt':
|
||||
return s.capitalize()
|
||||
return s
|
||||
def init(self, root = None):
|
||||
if root is not None:
|
||||
self.root = root
|
||||
|
||||
def init():
|
||||
paths = ConfigPaths()
|
||||
# LOG is deprecated
|
||||
k = ( 'LOG', 'LOG_DB', 'VCARD', 'AVATAR', 'MY_EMOTS',
|
||||
'MY_ICONSETS' )
|
||||
v = (u'logs', u'logs.db', u'vcards', u'avatars', u'emoticons',
|
||||
u'iconsets')
|
||||
|
||||
# LOG is deprecated
|
||||
k = ( 'LOG', 'LOG_DB', 'VCARD', 'AVATAR', 'MY_EMOTS' )
|
||||
v = (u'logs', u'logs.db', u'vcards', u'avatars', u'emoticons')
|
||||
if os.name == 'nt':
|
||||
v = map(lambda x: x.capitalize(), v)
|
||||
|
||||
if os.name == 'nt':
|
||||
v = map(lambda x: x.capitalize(), v)
|
||||
for n, p in zip(k, v):
|
||||
self.add_from_root(n, p)
|
||||
|
||||
for n, p in zip(k, v):
|
||||
paths.add_from_root(n, p)
|
||||
self.add('DATA', os.path.join(u'..', windowsify(u'data')))
|
||||
self.add('HOME', fse(os.path.expanduser('~')))
|
||||
self.add('TMP', fse(tempfile.gettempdir()))
|
||||
|
||||
paths.add('DATA', os.path.join(u'..', windowsify(u'data')))
|
||||
paths.add('HOME', fse(os.path.expanduser('~')))
|
||||
paths.add('TMP', fse(tempfile.gettempdir()))
|
||||
try:
|
||||
import svn_config
|
||||
svn_config.configure(self)
|
||||
except (ImportError, AttributeError):
|
||||
pass
|
||||
|
||||
try:
|
||||
import svn_config
|
||||
svn_config.configure(paths)
|
||||
except (ImportError, AttributeError):
|
||||
pass
|
||||
# for k, v in paths.iteritems():
|
||||
# print "%s: %s" % (repr(k), repr(v))
|
||||
|
||||
# for k, v in paths.iteritems():
|
||||
# print "%s: %s" % (repr(k), repr(v))
|
||||
def init_profile(self, profile):
|
||||
conffile = windowsify(u'config')
|
||||
pidfile = windowsify(u'gajim')
|
||||
|
||||
return paths
|
||||
if len(profile) > 0:
|
||||
conffile += u'.' + profile
|
||||
pidfile += u'.' + profile
|
||||
pidfile += u'.pid'
|
||||
self.add_from_root('CONFIG_FILE', conffile)
|
||||
self.add_from_root('PID_FILE', pidfile)
|
||||
|
||||
gajimpaths = init()
|
||||
# for k, v in paths.iteritems():
|
||||
# print "%s: %s" % (repr(k), repr(v))
|
||||
|
||||
def init_profile(profile, paths=gajimpaths):
|
||||
conffile = windowsify(u'config')
|
||||
pidfile = windowsify(u'gajim')
|
||||
|
||||
if len(profile) > 0:
|
||||
conffile += u'.' + profile
|
||||
pidfile += u'.' + profile
|
||||
pidfile += u'.pid'
|
||||
paths.add_from_root('CONFIG_FILE', conffile)
|
||||
paths.add_from_root('PID_FILE', pidfile)
|
||||
|
||||
# for k, v in paths.iteritems():
|
||||
# print "%s: %s" % (repr(k), repr(v))
|
||||
gajimpaths = ConfigPaths()
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
## Copyright (C) 2005-2006 Nikos Kouremenos <kourem@gmail.com>
|
||||
## Copyright (C) 2005-2006 Dimitur Kirov <dkirov@gmail.com>
|
||||
## Copyright (C) 2005-2006 Travis Shirk <travis@pobox.com>
|
||||
## Copyright (C) 2007 Julien Pivotto <roidelapluie@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
|
||||
|
@ -36,6 +37,7 @@ from common import helpers
|
|||
from common import gajim
|
||||
from common import GnuPG
|
||||
from common import passwords
|
||||
from common import exceptions
|
||||
|
||||
from connection_handlers import *
|
||||
USE_GPG = GnuPG.USE_GPG
|
||||
|
@ -48,12 +50,50 @@ log = logging.getLogger('gajim.c.connection')
|
|||
|
||||
import gtkgui_helpers
|
||||
|
||||
ssl_error = {
|
||||
2: "Unable to get issuer certificate",
|
||||
3: "Unable to get certificate CRL",
|
||||
4: "Unable to decrypt certificate's signature",
|
||||
5: "Unable to decrypt CRL's signature",
|
||||
6: "Unable to decode issuer public key",
|
||||
7: "Certificate signature failure",
|
||||
8: "CRL signature failure",
|
||||
9: "Certificate is not yet valid",
|
||||
10: "Certificate has expired",
|
||||
11: "CRL is not yet valid",
|
||||
12: "CRL has expired",
|
||||
13: "Format error in certificate's notBefore field",
|
||||
14: "Format error in certificate's notAfter field",
|
||||
15: "Format error in CRL's lastUpdate field",
|
||||
16: "Format error in CRL's nextUpdate field",
|
||||
17: "Out of memory",
|
||||
18: "Self signed certificate in certificate chain",
|
||||
19: "Unable to get local issuer certificate",
|
||||
20: "Unable to verify the first certificate",
|
||||
21: "Unable to verify the first certificate",
|
||||
22: "Certificate chain too long",
|
||||
23: "Certificate revoked",
|
||||
24: "Invalid CA certificate",
|
||||
25: "Path length constraint exceeded",
|
||||
26: "Unsupported certificate purpose",
|
||||
27: "Certificate not trusted",
|
||||
28: "Certificate rejected",
|
||||
29: "Subject issuer mismatch",
|
||||
30: "Authority and subject key identifier mismatch",
|
||||
31: "Authority and issuer serial number mismatch",
|
||||
32: "Key usage does not include certificate signing",
|
||||
50: "Application verification failure"
|
||||
}
|
||||
class Connection(ConnectionHandlers):
|
||||
'''Connection class'''
|
||||
def __init__(self, name):
|
||||
ConnectionHandlers.__init__(self)
|
||||
self.name = name
|
||||
self.connected = 0 # offline
|
||||
# self.connected:
|
||||
# 0=>offline,
|
||||
# 1=>connection in progress,
|
||||
# 2=>authorised
|
||||
self.connected = 0
|
||||
self.connection = None # xmpppy ClientCommon instance
|
||||
# this property is used to prevent double connections
|
||||
self.last_connection = None # last ClientCommon instance
|
||||
|
@ -93,6 +133,10 @@ class Connection(ConnectionHandlers):
|
|||
self.pep_supported = False
|
||||
# Do we continue connection when we get roster (send presence,get vcard...)
|
||||
self.continue_connect_info = None
|
||||
# To know the groupchat jid associated with a sranza ID. Useful to
|
||||
# request vcard or os info... to a real JID but act as if it comes from
|
||||
# the fake jid
|
||||
self.groupchat_jids = {} # {ID : groupchat_jid}
|
||||
if USE_GPG:
|
||||
self.gpg = GnuPG.GnuPG(gajim.config.get('use_gpg_agent'))
|
||||
gajim.config.set('usegpg', True)
|
||||
|
@ -210,10 +254,7 @@ class Connection(ConnectionHandlers):
|
|||
% (data[0], data[3])))
|
||||
return
|
||||
is_form = data[2]
|
||||
if is_form:
|
||||
conf = data[1]
|
||||
else:
|
||||
conf = data[1].asDict()
|
||||
conf = data[1]
|
||||
self.dispatch('NEW_ACC_CONNECTED', (conf, is_form))
|
||||
return
|
||||
if not data[1]: # wrong answer
|
||||
|
@ -222,10 +263,7 @@ class Connection(ConnectionHandlers):
|
|||
(data[0], data[3])))
|
||||
return
|
||||
is_form = data[2]
|
||||
if is_form:
|
||||
conf = data[1]
|
||||
else:
|
||||
conf = data[1].asDict()
|
||||
conf = data[1]
|
||||
self.dispatch('REGISTER_AGENT_INFO', (data[0], conf, is_form))
|
||||
elif realm == common.xmpp.NS_PRIVACY:
|
||||
if event == common.xmpp.features_nb.PRIVACY_LISTS_RECEIVED:
|
||||
|
@ -262,6 +300,8 @@ class Connection(ConnectionHandlers):
|
|||
self.dispatch('STANZA_SENT', unicode(data))
|
||||
|
||||
def select_next_host(self, hosts):
|
||||
'''Chooses best 'real' host basing on the SRV priority and weight data;
|
||||
more info in RFC2782'''
|
||||
hosts_best_prio = []
|
||||
best_prio = 65535
|
||||
sum_weight = 0
|
||||
|
@ -440,72 +480,20 @@ class Connection(ConnectionHandlers):
|
|||
name = gajim.config.get_per('accounts', self.name, 'name')
|
||||
hostname = gajim.config.get_per('accounts', self.name, 'hostname')
|
||||
self.connection = con
|
||||
|
||||
fpr_good = self._check_fingerprint(con, con_type)
|
||||
if fpr_good == False:
|
||||
self.disconnect(on_purpose = True)
|
||||
self.dispatch('STATUS', 'offline')
|
||||
self.dispatch('CONNECTION_LOST',
|
||||
(_('Security error connecting to "%s"') % self._hostname,
|
||||
_("The server's key has changed, or someone is trying to hack your connection.")))
|
||||
if self.on_connect_auth:
|
||||
self.on_connect_auth(None)
|
||||
self.on_connect_auth = None
|
||||
return
|
||||
|
||||
if fpr_good == None:
|
||||
log.warning(_("Unable to check fingerprint for %s. Connection could be insecure."), hostname)
|
||||
|
||||
if fpr_good == True:
|
||||
log.info("Fingerprint found and matched for %s.", hostname)
|
||||
|
||||
try:
|
||||
errnum = con.Connection.ssl_errnum
|
||||
except AttributeError:
|
||||
errnum = -1 # we don't have an errnum
|
||||
if errnum > 0:
|
||||
# FIXME: tell the user that the certificat is untrusted, and ask him what to do
|
||||
try:
|
||||
log.warning("The authenticity of the "+hostname+" certificate could be unvalid.\nSSL Error: "+ssl_error[errnum])
|
||||
except KeyError:
|
||||
log.warning("Unknown SSL error: %d" % errnum)
|
||||
con.auth(name, self.password, self.server_resource, 1, self.__on_auth)
|
||||
|
||||
return True
|
||||
|
||||
def _check_fingerprint(self, con, con_type):
|
||||
fpr_good = None # None: Unable to check fpr, False: mismatch, True: match
|
||||
|
||||
# FIXME: not tidy
|
||||
if not common.xmpp.transports_nb.USE_PYOPENSSL: return None
|
||||
|
||||
# FIXME: find a more permanent place for loading servers.xml
|
||||
servers_xml = os.path.join(gajim.DATA_DIR, 'other', 'servers.xml')
|
||||
servers = gtkgui_helpers.parse_server_xml(servers_xml)
|
||||
servers = dict(map(lambda e: (e[0], e), servers))
|
||||
|
||||
hostname = gajim.config.get_per('accounts', self.name, 'hostname')
|
||||
|
||||
try:
|
||||
log.debug("con: %s", con)
|
||||
log.debug("con.Connection: %s", con.Connection)
|
||||
log.debug("con.Connection.serverDigestSHA1: %s", con.Connection.serverDigestSHA1)
|
||||
log.debug("con.Connection.serverDigestMD5: %s", con.Connection.serverDigestMD5)
|
||||
sha1 = gtkgui_helpers.HashDigest('sha1', con.Connection.serverDigestSHA1)
|
||||
md5 = gtkgui_helpers.HashDigest('md5', con.Connection.serverDigestMD5)
|
||||
log.debug("sha1: %s", repr(sha1))
|
||||
log.debug("md5: %s", repr(md5))
|
||||
|
||||
sv = servers.get(hostname)
|
||||
if sv:
|
||||
for got in (sha1, md5):
|
||||
expected = sv[2]['digest'].get(got.algo)
|
||||
if expected:
|
||||
fpr_good = (got == expected)
|
||||
break
|
||||
|
||||
except AttributeError:
|
||||
if con_type in ('ssl', 'tls'):
|
||||
log.error(_("Missing fingerprint in SSL connection to %s") + ':', hostname, exc_info=True)
|
||||
# fpr_good = False # FIXME: enable this when sequence is sorted
|
||||
else:
|
||||
log.debug("Connection to %s doesn't seem to have a fingerprint:", hostname, exc_info=True)
|
||||
|
||||
if fpr_good == False:
|
||||
log.error(_("Fingerprint mismatch for %s: Got %s, expected %s"), hostname, got, expected)
|
||||
|
||||
return fpr_good
|
||||
|
||||
def _register_handlers(self, con, con_type):
|
||||
self.peerhost = con.get_peerhost()
|
||||
# notify the gui about con_type
|
||||
|
@ -566,14 +554,14 @@ class Connection(ConnectionHandlers):
|
|||
iq = common.xmpp.Iq('get', to = pingTo.get_full_jid())
|
||||
iq.addChild(name = 'ping', namespace = common.xmpp.NS_PING)
|
||||
def _on_response(resp):
|
||||
timePong = time.time()
|
||||
timePong = time_time()
|
||||
if not common.xmpp.isResultNode(resp):
|
||||
self.dispatch('PING_ERROR', (pingTo))
|
||||
return
|
||||
timeDiff = round(timePong - timePing,2)
|
||||
self.dispatch('PING_REPLY', (pingTo, timeDiff))
|
||||
self.dispatch('PING_SENT', (pingTo))
|
||||
timePing = time.time()
|
||||
timePing = time_time()
|
||||
self.connection.SendAndCallForResponse(iq, _on_response)
|
||||
|
||||
def get_active_default_lists(self):
|
||||
|
@ -765,6 +753,12 @@ class Connection(ConnectionHandlers):
|
|||
self.on_purpose = False
|
||||
self.server_resource = gajim.config.get_per('accounts', self.name,
|
||||
'resource')
|
||||
# All valid resource substitution strings should be added to this hash.
|
||||
if self.server_resource:
|
||||
self.server_resource = Template(self.server_resource).\
|
||||
safe_substitute({
|
||||
'hostname': socket.gethostname()
|
||||
})
|
||||
self.connect_and_init(show, msg, signed)
|
||||
|
||||
elif show == 'offline':
|
||||
|
@ -825,8 +819,8 @@ class Connection(ConnectionHandlers):
|
|||
self.connection.send(msg_iq)
|
||||
|
||||
def send_message(self, jid, msg, keyID, type = 'chat', subject='',
|
||||
chatstate = None, msg_id = None, composing_jep = None, resource = None,
|
||||
user_nick = None, xhtml = None):
|
||||
chatstate = None, msg_id = None, composing_xep = None, resource = None,
|
||||
user_nick = None, xhtml = None, forward_from = None):
|
||||
if not self.connection:
|
||||
return 1
|
||||
if msg and not xhtml and gajim.config.get('rst_formatting_outgoing_messages'):
|
||||
|
@ -850,7 +844,7 @@ class Connection(ConnectionHandlers):
|
|||
' ([This message is *encrypted* (See :JEP:`27`])'
|
||||
else:
|
||||
# Encryption failed, do not send message
|
||||
tim = time.localtime()
|
||||
tim = localtime()
|
||||
self.dispatch('MSGNOTSENT', (jid, error, msgtxt, tim))
|
||||
return 3
|
||||
if msgtxt and not xhtml and gajim.config.get(
|
||||
|
@ -879,12 +873,12 @@ class Connection(ConnectionHandlers):
|
|||
# please note that the only valid tag inside a message containing a <body>
|
||||
# tag is the active event
|
||||
if chatstate is not None:
|
||||
if (composing_jep == 'JEP-0085' or not composing_jep) and \
|
||||
composing_jep != 'asked_once':
|
||||
# JEP-0085
|
||||
if (composing_xep == 'XEP-0085' or not composing_xep) and \
|
||||
composing_xep != 'asked_once':
|
||||
# XEP-0085
|
||||
msg_iq.setTag(chatstate, namespace = common.xmpp.NS_CHATSTATES)
|
||||
if composing_jep in ('JEP-0022', 'asked_once') or not composing_jep:
|
||||
# JEP-0022
|
||||
if composing_xep in ('XEP-0022', 'asked_once') or not composing_xep:
|
||||
# XEP-0022
|
||||
chatstate_node = msg_iq.setTag('x',
|
||||
namespace = common.xmpp.NS_EVENT)
|
||||
if not msgtxt: # when no <body>, add <id>
|
||||
|
@ -895,21 +889,30 @@ class Connection(ConnectionHandlers):
|
|||
if chatstate is 'composing' or msgtxt:
|
||||
chatstate_node.addChild(name = 'composing')
|
||||
|
||||
if forward_from:
|
||||
addresses = msg_iq.addChild('addresses',
|
||||
namespace=common.xmpp.NS_ADDRESS)
|
||||
addresses.addChild('address', attrs = {'type': 'ofrom',
|
||||
'jid': forward_from})
|
||||
self.connection.send(msg_iq)
|
||||
no_log_for = gajim.config.get_per('accounts', self.name, 'no_log_for')\
|
||||
.split()
|
||||
ji = gajim.get_jid_without_resource(jid)
|
||||
if self.name not in no_log_for and ji not in no_log_for:
|
||||
log_msg = msg
|
||||
if subject:
|
||||
log_msg = _('Subject: %s\n%s') % (subject, msg)
|
||||
if log_msg:
|
||||
if type == 'chat':
|
||||
kind = 'chat_msg_sent'
|
||||
else:
|
||||
kind = 'single_msg_sent'
|
||||
gajim.logger.write(kind, jid, log_msg)
|
||||
self.dispatch('MSGSENT', (jid, msg, keyID))
|
||||
if not forward_from:
|
||||
no_log_for = gajim.config.get_per('accounts', self.name, 'no_log_for')\
|
||||
.split()
|
||||
ji = gajim.get_jid_without_resource(jid)
|
||||
if self.name not in no_log_for and ji not in no_log_for:
|
||||
log_msg = msg
|
||||
if subject:
|
||||
log_msg = _('Subject: %s\n%s') % (subject, msg)
|
||||
if log_msg:
|
||||
if type == 'chat':
|
||||
kind = 'chat_msg_sent'
|
||||
else:
|
||||
kind = 'single_msg_sent'
|
||||
try:
|
||||
gajim.logger.write(kind, jid, log_msg)
|
||||
except exceptions.PysqliteOperationalError, e:
|
||||
self.dispatch('ERROR', (_('Disk Write Error'), str(e)))
|
||||
self.dispatch('MSGSENT', (jid, msg, keyID))
|
||||
|
||||
def send_stanza(self, stanza):
|
||||
''' send a stanza untouched '''
|
||||
|
@ -1059,7 +1062,9 @@ class Connection(ConnectionHandlers):
|
|||
def account_changed(self, new_name):
|
||||
self.name = new_name
|
||||
|
||||
def request_last_status_time(self, jid, resource):
|
||||
def request_last_status_time(self, jid, resource, groupchat_jid=None):
|
||||
'''groupchat_jid is used when we want to send a request to a real jid
|
||||
and act as if the answer comes from the groupchat_jid'''
|
||||
if not self.connection:
|
||||
return
|
||||
to_whom_jid = jid
|
||||
|
@ -1067,9 +1072,15 @@ class Connection(ConnectionHandlers):
|
|||
to_whom_jid += '/' + resource
|
||||
iq = common.xmpp.Iq(to = to_whom_jid, typ = 'get', queryNS =\
|
||||
common.xmpp.NS_LAST)
|
||||
id = self.connection.getAnID()
|
||||
iq.setID(id)
|
||||
if groupchat_jid:
|
||||
self.groupchat_jids[id] = groupchat_jid
|
||||
self.connection.send(iq)
|
||||
|
||||
def request_os_info(self, jid, resource):
|
||||
def request_os_info(self, jid, resource, groupchat_jid=None):
|
||||
'''groupchat_jid is used when we want to send a request to a real jid
|
||||
and act as if the answer comes from the groupchat_jid'''
|
||||
if not self.connection:
|
||||
return
|
||||
# If we are invisible, do not request
|
||||
|
@ -1081,6 +1092,10 @@ class Connection(ConnectionHandlers):
|
|||
to_whom_jid += '/' + resource
|
||||
iq = common.xmpp.Iq(to = to_whom_jid, typ = 'get', queryNS =\
|
||||
common.xmpp.NS_VERSION)
|
||||
id = self.connection.getAnID()
|
||||
iq.setID(id)
|
||||
if groupchat_jid:
|
||||
self.groupchat_jids[id] = groupchat_jid
|
||||
self.connection.send(iq)
|
||||
|
||||
def get_settings(self):
|
||||
|
@ -1088,7 +1103,7 @@ class Connection(ConnectionHandlers):
|
|||
if not self.connection:
|
||||
return
|
||||
iq = common.xmpp.Iq(typ='get')
|
||||
iq2 = iq.addChild(name='query', namespace='jabber:iq:private')
|
||||
iq2 = iq.addChild(name='query', namespace=common.xmpp.NS_PRIVATE)
|
||||
iq3 = iq2.addChild(name='gajim', namespace='gajim:prefs')
|
||||
self.connection.send(iq)
|
||||
|
||||
|
@ -1098,7 +1113,7 @@ class Connection(ConnectionHandlers):
|
|||
if not self.connection:
|
||||
return
|
||||
iq = common.xmpp.Iq(typ='get')
|
||||
iq2 = iq.addChild(name='query', namespace='jabber:iq:private')
|
||||
iq2 = iq.addChild(name='query', namespace=common.xmpp.NS_PRIVATE)
|
||||
iq2.addChild(name='storage', namespace='storage:bookmarks')
|
||||
self.connection.send(iq)
|
||||
|
||||
|
@ -1107,12 +1122,13 @@ class Connection(ConnectionHandlers):
|
|||
if not self.connection:
|
||||
return
|
||||
iq = common.xmpp.Iq(typ='set')
|
||||
iq2 = iq.addChild(name='query', namespace='jabber:iq:private')
|
||||
iq2 = iq.addChild(name='query', namespace=common.xmpp.NS_PRIVATE)
|
||||
iq3 = iq2.addChild(name='storage', namespace='storage:bookmarks')
|
||||
for bm in self.bookmarks:
|
||||
iq4 = iq3.addChild(name = "conference")
|
||||
iq4.setAttr('jid', bm['jid'])
|
||||
iq4.setAttr('autojoin', bm['autojoin'])
|
||||
iq4.setAttr('minimize', bm['minimize'])
|
||||
iq4.setAttr('name', bm['name'])
|
||||
# Only add optional elements if not empty
|
||||
# Note: need to handle both None and '' as empty
|
||||
|
@ -1131,7 +1147,7 @@ class Connection(ConnectionHandlers):
|
|||
if not self.connection:
|
||||
return
|
||||
iq = common.xmpp.Iq(typ='get')
|
||||
iq2 = iq.addChild(name='query', namespace='jabber:iq:private')
|
||||
iq2 = iq.addChild(name='query', namespace=common.xmpp.NS_PRIVATE)
|
||||
iq2.addChild(name='storage', namespace='storage:rosternotes')
|
||||
self.connection.send(iq)
|
||||
|
||||
|
@ -1140,7 +1156,7 @@ class Connection(ConnectionHandlers):
|
|||
if not self.connection:
|
||||
return
|
||||
iq = common.xmpp.Iq(typ='set')
|
||||
iq2 = iq.addChild(name='query', namespace='jabber:iq:private')
|
||||
iq2 = iq.addChild(name='query', namespace=common.xmpp.NS_PRIVATE)
|
||||
iq3 = iq2.addChild(name='storage', namespace='storage:rosternotes')
|
||||
for jid in self.annotations.keys():
|
||||
if self.annotations[jid]:
|
||||
|
@ -1155,7 +1171,7 @@ class Connection(ConnectionHandlers):
|
|||
if not self.connection:
|
||||
return
|
||||
iq = common.xmpp.Iq(typ='get')
|
||||
iq2 = iq.addChild(name='query', namespace='jabber:iq:private')
|
||||
iq2 = iq.addChild(name='query', namespace=common.xmpp.NS_PRIVATE)
|
||||
iq2.addChild(name='storage', namespace='storage:metacontacts')
|
||||
id = self.connection.getAnID()
|
||||
iq.setID(id)
|
||||
|
@ -1167,7 +1183,7 @@ class Connection(ConnectionHandlers):
|
|||
if not self.connection:
|
||||
return
|
||||
iq = common.xmpp.Iq(typ='set')
|
||||
iq2 = iq.addChild(name='query', namespace='jabber:iq:private')
|
||||
iq2 = iq.addChild(name='query', namespace=common.xmpp.NS_PRIVATE)
|
||||
iq3 = iq2.addChild(name='storage', namespace='storage:metacontacts')
|
||||
for tag in tags_list:
|
||||
for data in tags_list[tag]:
|
||||
|
@ -1264,7 +1280,7 @@ class Connection(ConnectionHandlers):
|
|||
self.connection.send(p)
|
||||
# Save the time we quit to avoid duplicate logs AND be faster than
|
||||
# get that date from DB
|
||||
self.last_history_line[jid] = time.time()
|
||||
self.last_history_line[jid] = time_time()
|
||||
|
||||
def gc_set_role(self, room_jid, nick, role, reason = ''):
|
||||
'''role is for all the life of the room so it's based on nick'''
|
||||
|
@ -1419,7 +1435,8 @@ class Connection(ConnectionHandlers):
|
|||
return
|
||||
df = []
|
||||
for item in tag.getTags('item'):
|
||||
f = {}
|
||||
# We also show attributes. jid is there
|
||||
f = item.attrs
|
||||
for i in item.getPayload():
|
||||
f[i.getName()] = i.getData()
|
||||
df.append(f)
|
||||
|
|
|
@ -18,13 +18,13 @@
|
|||
##
|
||||
|
||||
import os
|
||||
import time
|
||||
import base64
|
||||
import sha
|
||||
import socket
|
||||
import sys
|
||||
|
||||
from time import localtime, strftime, gmtime
|
||||
from time import (altzone, daylight, gmtime, localtime, mktime, strftime,
|
||||
time as time_time, timezone, tzname)
|
||||
from calendar import timegm
|
||||
|
||||
import socks5
|
||||
|
@ -35,8 +35,10 @@ from common import helpers
|
|||
from common import gajim
|
||||
from common import atom
|
||||
from common import pep
|
||||
from common import exceptions
|
||||
from common.commands import ConnectionCommands
|
||||
from common.pubsub import ConnectionPubSub
|
||||
from common.caps import ConnectionCaps
|
||||
|
||||
STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
|
||||
'invisible', 'error']
|
||||
|
@ -414,7 +416,7 @@ class ConnectionBytestream:
|
|||
|
||||
def _ResultCB(self, con, iq_obj):
|
||||
gajim.log.debug('_ResultCB')
|
||||
# if we want to respect jep-0065 we have to check for proxy
|
||||
# if we want to respect xep-0065 we have to check for proxy
|
||||
# activation result in any result iq
|
||||
real_id = unicode(iq_obj.getAttr('id'))
|
||||
if real_id[:3] != 'au_':
|
||||
|
@ -562,6 +564,7 @@ class ConnectionBytestream:
|
|||
file_props['sender'] = helpers.get_full_jid_from_iq(iq_obj)
|
||||
file_props['request-id'] = unicode(iq_obj.getAttr('id'))
|
||||
file_props['sid'] = unicode(si.getAttr('id'))
|
||||
file_props['transfered_size'] = []
|
||||
gajim.socks5queue.add_file_props(self.name, file_props)
|
||||
self.dispatch('FILE_REQUEST', (jid, file_props))
|
||||
raise common.xmpp.NodeProcessed
|
||||
|
@ -588,12 +591,12 @@ class ConnectionBytestream:
|
|||
class ConnectionDisco:
|
||||
''' hold xmpppy handlers and public methods for discover services'''
|
||||
def discoverItems(self, jid, node = None, id_prefix = None):
|
||||
'''According to JEP-0030: jid is mandatory,
|
||||
'''According to XEP-0030: jid is mandatory,
|
||||
name, node, action is optional.'''
|
||||
self._discover(common.xmpp.NS_DISCO_ITEMS, jid, node, id_prefix)
|
||||
|
||||
def discoverInfo(self, jid, node = None, id_prefix = None):
|
||||
'''According to JEP-0030:
|
||||
'''According to XEP-0030:
|
||||
For identity: category, type is mandatory, name is optional.
|
||||
For feature: var is mandatory'''
|
||||
self._discover(common.xmpp.NS_DISCO_INFO, jid, node, id_prefix)
|
||||
|
@ -702,6 +705,10 @@ class ConnectionDisco:
|
|||
def _DiscoverItemsGetCB(self, con, iq_obj):
|
||||
gajim.log.debug('DiscoverItemsGetCB')
|
||||
node = iq_obj.getTagAttr('query', 'node')
|
||||
if node is None:
|
||||
result = iq_obj.buildReply('result')
|
||||
self.connection.send(result)
|
||||
raise common.xmpp.NodeProcessed
|
||||
if node==common.xmpp.NS_COMMANDS:
|
||||
self.commandListQuery(con, iq_obj)
|
||||
raise common.xmpp.NodeProcessed
|
||||
|
@ -746,6 +753,10 @@ class ConnectionDisco:
|
|||
if (node is None or extension == 'xhtml') and not gajim.config.get('ignore_incoming_xhtml'):
|
||||
q.addChild('feature', attrs = {'var': common.xmpp.NS_XHTML_IM})
|
||||
|
||||
if node is None:
|
||||
q.addChild('feature', attrs = {'var': common.xmpp.NS_PING})
|
||||
q.addChild('feature', attrs = {'var': common.xmpp.NS_TIME_REVISED})
|
||||
|
||||
if q.getChildren():
|
||||
self.connection.send(iq)
|
||||
raise common.xmpp.NodeProcessed
|
||||
|
@ -757,7 +768,7 @@ class ConnectionDisco:
|
|||
|
||||
def _DiscoverInfoCB(self, con, iq_obj):
|
||||
gajim.log.debug('DiscoverInfoCB')
|
||||
# According to JEP-0030:
|
||||
# According to XEP-0030:
|
||||
# For identity: category, type is mandatory, name is optional.
|
||||
# For feature: var is mandatory
|
||||
identities, features, data = [], [], []
|
||||
|
@ -775,11 +786,13 @@ class ConnectionDisco:
|
|||
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'):
|
||||
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':
|
||||
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':
|
||||
|
@ -796,6 +809,9 @@ class ConnectionDisco:
|
|||
identities = [{'category': 'server', 'type': 'im', 'name': node}]
|
||||
if id[0] == 'p':
|
||||
if jid == gajim.config.get_per('accounts', self.name, 'hostname'):
|
||||
if features.__contains__(common.xmpp.NS_GMAILNOTIFY):
|
||||
gajim.gmail_domains.append(jid)
|
||||
self.request_gmail_notifications()
|
||||
for identity in identities:
|
||||
if identity['category'] == 'pubsub' and identity['type'] == \
|
||||
'pep':
|
||||
|
@ -811,16 +827,17 @@ class ConnectionDisco:
|
|||
self.available_transports[transport_type].append(jid)
|
||||
else:
|
||||
self.available_transports[transport_type] = [jid]
|
||||
|
||||
self.dispatch('AGENT_INFO_INFO', (jid, node, identities,
|
||||
features, data))
|
||||
self._capsDiscoCB(jid, node, identities, features, data)
|
||||
|
||||
class ConnectionVcard:
|
||||
def __init__(self):
|
||||
self.vcard_sha = None
|
||||
self.vcard_shas = {} # sha of contacts
|
||||
self.room_jids = [] # list of gc jids so that vcard are saved in a folder
|
||||
self.groupchat_jids = {} # {ID : groupchat_jid}
|
||||
|
||||
|
||||
def add_sha(self, p, send_caps = True):
|
||||
c = p.setTag('x', namespace = common.xmpp.NS_VCARD_UPDATE)
|
||||
if self.vcard_sha is not None:
|
||||
|
@ -830,7 +847,7 @@ class ConnectionVcard:
|
|||
return p
|
||||
|
||||
def add_caps(self, p):
|
||||
''' advertise our capabilities in presence stanza (jep-0115)'''
|
||||
''' advertise our capabilities in presence stanza (xep-0115)'''
|
||||
c = p.setTag('c', namespace = common.xmpp.NS_CAPS)
|
||||
c.setAttr('node', 'http://gajim.org/caps')
|
||||
ext = []
|
||||
|
@ -880,9 +897,12 @@ class ConnectionVcard:
|
|||
path_to_file = os.path.join(gajim.VCARD_PATH, puny_jid, puny_nick)
|
||||
else:
|
||||
path_to_file = path
|
||||
fil = open(path_to_file, 'w')
|
||||
fil.write(str(card))
|
||||
fil.close()
|
||||
try:
|
||||
fil = open(path_to_file, 'w')
|
||||
fil.write(str(card))
|
||||
fil.close()
|
||||
except IOError, e:
|
||||
self.dispatch('ERROR', (_('Disk Write Error'), str(e)))
|
||||
|
||||
def get_cached_vcard(self, fjid, is_fake_jid = False):
|
||||
'''return the vcard as a dict
|
||||
|
@ -1042,7 +1062,7 @@ class ConnectionVcard:
|
|||
elif self.awaiting_answers[id][0] == METACONTACTS_ARRIVED:
|
||||
if iq_obj.getType() == 'result':
|
||||
# Metacontact tags
|
||||
# http://www.jabber.org/jeps/jep-XXXX.html
|
||||
# http://www.xmpp.org/extensions/xep-0209.html
|
||||
meta_list = {}
|
||||
query = iq_obj.getTag('query')
|
||||
storage = query.getTag('storage')
|
||||
|
@ -1171,12 +1191,13 @@ class ConnectionVcard:
|
|||
#('VCARD', {entry1: data, entry2: {entry21: data, ...}, ...})
|
||||
self.dispatch('VCARD', vcard)
|
||||
|
||||
class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub):
|
||||
class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub, ConnectionCaps):
|
||||
def __init__(self):
|
||||
ConnectionVcard.__init__(self)
|
||||
ConnectionBytestream.__init__(self)
|
||||
ConnectionCommands.__init__(self)
|
||||
ConnectionPubSub.__init__(self)
|
||||
self.gmail_url=None
|
||||
# List of IDs we are waiting answers for {id: (type_of_request, data), }
|
||||
self.awaiting_answers = {}
|
||||
# List of IDs that will produce a timeout is answer doesn't arrive
|
||||
|
@ -1229,7 +1250,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
|
||||
def _PrivateCB(self, con, iq_obj):
|
||||
'''
|
||||
Private Data (JEP 048 and 049)
|
||||
Private Data (XEP 048 and 049)
|
||||
'''
|
||||
gajim.log.debug('PrivateCB')
|
||||
query = iq_obj.getTag('query')
|
||||
|
@ -1238,18 +1259,22 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
ns = storage.getNamespace()
|
||||
if ns == 'storage:bookmarks':
|
||||
# Bookmarked URLs and Conferences
|
||||
# http://www.jabber.org/jeps/jep-0048.html
|
||||
# http://www.xmpp.org/extensions/xep-0048.html
|
||||
confs = storage.getTags('conference')
|
||||
for conf in confs:
|
||||
autojoin_val = conf.getAttr('autojoin')
|
||||
if autojoin_val is None: # not there (it's optional)
|
||||
autojoin_val = False
|
||||
minimize_val = conf.getAttr('minimize')
|
||||
if minimize_val is None: # not there (it's optional)
|
||||
minimize_val = False
|
||||
print_status = conf.getTagData('print_status')
|
||||
if not print_status:
|
||||
print_status = conf.getTagData('show_status')
|
||||
bm = {'name': conf.getAttr('name'),
|
||||
'jid': conf.getAttr('jid'),
|
||||
'autojoin': autojoin_val,
|
||||
'minimize': minimize_val,
|
||||
'password': conf.getTagData('password'),
|
||||
'nick': conf.getTagData('nick'),
|
||||
'print_status': print_status}
|
||||
|
@ -1259,7 +1284,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
|
||||
elif ns == 'gajim:prefs':
|
||||
# Preferences data
|
||||
# http://www.jabber.org/jeps/jep-0049.html
|
||||
# http://www.xmpp.org/extensions/xep-0049.html
|
||||
#TODO: implement this
|
||||
pass
|
||||
elif ns == 'storage:rosternotes':
|
||||
|
@ -1279,7 +1304,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
ns = storage_tag.getNamespace()
|
||||
if ns == 'storage:metacontacts':
|
||||
self.metacontacts_supported = False
|
||||
# Private XML Storage (JEP49) is not supported by server
|
||||
# Private XML Storage (XEP49) is not supported by server
|
||||
# Continue connecting
|
||||
self.connection.initRoster()
|
||||
|
||||
|
@ -1329,7 +1354,12 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
seconds = int(seconds)
|
||||
except:
|
||||
return
|
||||
who = helpers.get_full_jid_from_iq(iq_obj)
|
||||
id = iq_obj.getID()
|
||||
if id in self.groupchat_jids:
|
||||
who = self.groupchat_jids[id]
|
||||
del self.groupchat_jids[id]
|
||||
else:
|
||||
who = helpers.get_full_jid_from_iq(iq_obj)
|
||||
jid_stripped, resource = gajim.get_room_and_nick_from_fjid(who)
|
||||
self.dispatch('LAST_STATUS_TIME', (jid_stripped, resource, seconds, status))
|
||||
|
||||
|
@ -1344,7 +1374,12 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
client_info += ' ' + qp.getTag('version').getData()
|
||||
if qp.getTag('os'):
|
||||
os_info += qp.getTag('os').getData()
|
||||
who = helpers.get_full_jid_from_iq(iq_obj)
|
||||
id = iq_obj.getID()
|
||||
if id in self.groupchat_jids:
|
||||
who = self.groupchat_jids[id]
|
||||
del self.groupchat_jids[id]
|
||||
else:
|
||||
who = helpers.get_full_jid_from_iq(iq_obj)
|
||||
jid_stripped, resource = gajim.get_room_and_nick_from_fjid(who)
|
||||
self.dispatch('OS_INFO', (jid_stripped, resource, client_info, os_info))
|
||||
|
||||
|
@ -1352,18 +1387,21 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
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()))
|
||||
qp.setTagData('utc', strftime('%Y%m%dT%T', gmtime()))
|
||||
qp.setTagData('tz', tzname[daylight])
|
||||
qp.setTagData('display', strftime('%c', localtime()))
|
||||
self.connection.send(iq_obj)
|
||||
raise common.xmpp.NodeProcessed
|
||||
|
||||
def _TimeRevisedCB(self, con, iq_obj):
|
||||
gajim.log.debug('TimeRevisedCB')
|
||||
iq_obj = iq_obj.buildReply('result')
|
||||
qp = iq_obj.setTag('time')
|
||||
qp.setTagData('utc', strftime("%Y-%m-%dT%TZ", gmtime()))
|
||||
qp.setTagData('tzo', "%+03d:00"% (-time.timezone/(60*60)))
|
||||
qp = iq_obj.setTag('time',
|
||||
namespace=common.xmpp.NS_TIME_REVISED)
|
||||
qp.setTagData('utc', strftime('%Y-%m-%dT%TZ', gmtime()))
|
||||
zone = -(timezone, altzone)[daylight] / 60
|
||||
tzo = (zone / 60, abs(zone % 60))
|
||||
qp.setTagData('tzo', '%+03d:%02d' % (tzo))
|
||||
self.connection.send(iq_obj)
|
||||
raise common.xmpp.NodeProcessed
|
||||
|
||||
|
@ -1386,6 +1424,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
'''Called when we receive results from Querying the server for mail messages in gmail account'''
|
||||
if not gm.getTag('mailbox'):
|
||||
return
|
||||
self.gmail_url = gm.getTag('mailbox').getAttr('url')
|
||||
if gm.getTag('mailbox').getNamespace() == common.xmpp.NS_GMAILNOTIFY:
|
||||
newmsgs = gm.getTag('mailbox').getAttr('total-matched')
|
||||
if newmsgs != '0':
|
||||
|
@ -1425,10 +1464,17 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
mtype = msg.getType()
|
||||
subject = msg.getSubject() # if not there, it's None
|
||||
tim = msg.getTimestamp()
|
||||
tim = time.strptime(tim, '%Y%m%dT%H:%M:%S')
|
||||
tim = time.localtime(timegm(tim))
|
||||
tim = helpers.datetime_tuple(tim)
|
||||
tim = localtime(timegm(tim))
|
||||
frm = helpers.get_full_jid_from_iq(msg)
|
||||
jid = helpers.get_jid_from_iq(msg)
|
||||
addressTag = msg.getTag('addresses', namespace = common.xmpp.NS_ADDRESS)
|
||||
# Be sure it comes from one of our resource, else ignore address element
|
||||
if addressTag and jid == gajim.get_jid_from_account(self.name):
|
||||
address = addressTag.getTag('address', attrs={'type': 'ofrom'})
|
||||
if address:
|
||||
frm = address.getAttr('jid')
|
||||
jid = gajim.get_jid_without_resource(frm)
|
||||
no_log_for = gajim.config.get_per('accounts', self.name,
|
||||
'no_log_for')
|
||||
if not no_log_for:
|
||||
|
@ -1446,10 +1492,10 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
invite = None
|
||||
delayed = msg.getTag('x', namespace = common.xmpp.NS_DELAY) != None
|
||||
msg_id = None
|
||||
composing_jep = None
|
||||
composing_xep = None
|
||||
# FIXME: Msn transport (CMSN1.2.1 and PyMSN0.10) do NOT RECOMMENDED
|
||||
# invitation
|
||||
# stanza (MUC JEP) remove in 2007, as we do not do NOT RECOMMENDED
|
||||
# stanza (MUC XEP) remove in 2007, as we do not do NOT RECOMMENDED
|
||||
xtags = msg.getTags('x')
|
||||
for xtag in xtags:
|
||||
if xtag.getNamespace() == common.xmpp.NS_CONFERENCE and not invite:
|
||||
|
@ -1458,22 +1504,22 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
return
|
||||
# chatstates - look for chatstate tags in a message if not delayed
|
||||
if not delayed:
|
||||
composing_jep = False
|
||||
composing_xep = False
|
||||
children = msg.getChildren()
|
||||
for child in children:
|
||||
if child.getNamespace() == 'http://jabber.org/protocol/chatstates':
|
||||
chatstate = child.getName()
|
||||
composing_jep = 'JEP-0085'
|
||||
composing_xep = 'XEP-0085'
|
||||
break
|
||||
# No JEP-0085 support, fallback to JEP-0022
|
||||
# No XEP-0085 support, fallback to XEP-0022
|
||||
if not chatstate:
|
||||
chatstate_child = msg.getTag('x', namespace = common.xmpp.NS_EVENT)
|
||||
if chatstate_child:
|
||||
chatstate = 'active'
|
||||
composing_jep = 'JEP-0022'
|
||||
composing_xep = 'XEP-0022'
|
||||
if not msgtxt and chatstate_child.getTag('composing'):
|
||||
chatstate = 'composing'
|
||||
# JEP-0172 User Nickname
|
||||
# XEP-0172 User Nickname
|
||||
user_nick = msg.getTagData('nick')
|
||||
if not user_nick:
|
||||
user_nick = ''
|
||||
|
@ -1494,8 +1540,11 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
error_msg = msgtxt
|
||||
msgtxt = None
|
||||
if self.name not in no_log_for:
|
||||
gajim.logger.write('error', frm, error_msg, tim = tim,
|
||||
subject = subject)
|
||||
try:
|
||||
gajim.logger.write('error', frm, error_msg, tim = tim,
|
||||
subject = subject)
|
||||
except exceptions.PysqliteOperationalError, e:
|
||||
self.dispatch('ERROR', (_('Disk Write Error'), str(e)))
|
||||
self.dispatch('MSGERROR', (frm, msg.getErrorCode(), error_msg, msgtxt,
|
||||
tim))
|
||||
return
|
||||
|
@ -1507,22 +1556,34 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
self.dispatch('GC_SUBJECT', (frm, subject, msgtxt, has_timestamp))
|
||||
else:
|
||||
if not msg.getTag('body'): #no <body>
|
||||
# It could be a config change. See
|
||||
# http://www.xmpp.org/extensions/xep-0045.html#roomconfig-notify
|
||||
if msg.getTag('x'):
|
||||
statusCode = msg.getStatusCode()
|
||||
if statusCode != []:
|
||||
self.dispatch('GC_CONFIG_CHANGE', (jid, statusCode))
|
||||
return
|
||||
# Ignore message from room in which we are not
|
||||
if not self.last_history_line.has_key(jid):
|
||||
return
|
||||
self.dispatch('GC_MSG', (frm, msgtxt, tim, has_timestamp, msghtml))
|
||||
if self.name not in no_log_for and not int(float(time.mktime(tim)))\
|
||||
if self.name not in no_log_for and not int(float(mktime(tim)))\
|
||||
<= self.last_history_line[jid] and msgtxt:
|
||||
gajim.logger.write('gc_msg', frm, msgtxt, tim = tim)
|
||||
try:
|
||||
gajim.logger.write('gc_msg', frm, msgtxt, tim = tim)
|
||||
except exceptions.PysqliteOperationalError, e:
|
||||
self.dispatch('ERROR', (_('Disk Write Error'), str(e)))
|
||||
return
|
||||
elif mtype == 'chat': # it's type 'chat'
|
||||
if not msg.getTag('body') and chatstate is None: #no <body>
|
||||
return
|
||||
if msg.getTag('body') and self.name not in no_log_for and jid not in\
|
||||
no_log_for and msgtxt:
|
||||
msg_id = gajim.logger.write('chat_msg_recv', frm, msgtxt, tim = tim,
|
||||
subject = subject)
|
||||
try:
|
||||
msg_id = gajim.logger.write('chat_msg_recv', frm, msgtxt,
|
||||
tim = tim, subject = subject)
|
||||
except exceptions.PysqliteOperationalError, e:
|
||||
self.dispatch('ERROR', (_('Disk Write Error'), str(e)))
|
||||
else: # it's single message
|
||||
if invite is not None:
|
||||
item = invite.getTag('invite')
|
||||
|
@ -1533,14 +1594,17 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
self.dispatch('GC_INVITATION',(frm, jid_from, reason, password))
|
||||
return
|
||||
if self.name not in no_log_for and jid not in no_log_for and msgtxt:
|
||||
gajim.logger.write('single_msg_recv', frm, msgtxt, tim = tim,
|
||||
subject = subject)
|
||||
try:
|
||||
gajim.logger.write('single_msg_recv', frm, msgtxt, tim = tim,
|
||||
subject = subject)
|
||||
except exceptions.PysqliteOperationalError, e:
|
||||
self.dispatch('ERROR', (_('Disk Write Error'), str(e)))
|
||||
mtype = 'normal'
|
||||
treat_as = gajim.config.get('treat_incoming_messages')
|
||||
if treat_as:
|
||||
mtype = treat_as
|
||||
self.dispatch('MSG', (frm, msgtxt, tim, encrypted, mtype,
|
||||
subject, chatstate, msg_id, composing_jep, user_nick, msghtml))
|
||||
subject, chatstate, msg_id, composing_xep, user_nick, msghtml))
|
||||
# END messageCB
|
||||
|
||||
def _pubsubEventCB(self, con, msg):
|
||||
|
@ -1567,20 +1631,13 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
if items is None: return
|
||||
|
||||
for item in items.getTags('item'):
|
||||
# check for event type (for now only one type supported: pubsub.com events)
|
||||
child = item.getTag('pubsub-message')
|
||||
if child is not None:
|
||||
# we have pubsub.com notification
|
||||
child = child.getTag('feed')
|
||||
if child is None: continue
|
||||
|
||||
for entry in child.getTags('entry'):
|
||||
# for each entry in feed (there shouldn't be more than one,
|
||||
# but to be sure...
|
||||
self.dispatch('ATOM_ENTRY', (atom.OldEntry(node=entry),))
|
||||
entry = item.getTag('entry')
|
||||
if entry is not None:
|
||||
# for each entry in feed (there shouldn't be more than one,
|
||||
# but to be sure...
|
||||
self.dispatch('ATOM_ENTRY', (atom.OldEntry(node=entry),))
|
||||
continue
|
||||
# unknown type... probably user has another client who understands that event
|
||||
|
||||
raise common.xmpp.NodeProcessed
|
||||
|
||||
def _presenceCB(self, con, prs):
|
||||
|
@ -1609,7 +1666,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
sigTag = None
|
||||
ns_muc_user_x = None
|
||||
avatar_sha = None
|
||||
# JEP-0172 User Nickname
|
||||
# XEP-0172 User Nickname
|
||||
user_nick = prs.getTagData('nick')
|
||||
if not user_nick:
|
||||
user_nick = ''
|
||||
|
@ -1628,10 +1685,10 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
avatar_sha = x.getTagData('photo')
|
||||
contact_nickname = x.getTagData('nickname')
|
||||
elif namespace == common.xmpp.NS_DELAY:
|
||||
# JEP-0091
|
||||
# XEP-0091
|
||||
tim = prs.getTimestamp()
|
||||
tim = time.strptime(tim, '%Y%m%dT%H:%M:%S')
|
||||
timestamp = time.localtime(timegm(tim))
|
||||
tim = helpers.datetime_tuple(tim)
|
||||
timestamp = localtime(timegm(tim))
|
||||
elif namespace == 'http://delx.cjb.net/protocol/roster-subsync':
|
||||
# see http://trac.gajim.org/ticket/326
|
||||
agent = gajim.get_server_from_jid(jid_stripped)
|
||||
|
@ -1664,27 +1721,29 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
if ptype == 'error':
|
||||
errmsg = prs.getError()
|
||||
errcode = prs.getErrorCode()
|
||||
room_jid, nick = gajim.get_room_and_nick_from_fjid(who)
|
||||
if errcode == '502': # Internal Timeout:
|
||||
self.dispatch('NOTIFY', (jid_stripped, 'error', errmsg, resource,
|
||||
prio, keyID, timestamp, None))
|
||||
elif errcode == '401': # password required to join
|
||||
self.dispatch('ERROR', (_('Unable to join group chat'),
|
||||
_('A password is required to join this group chat.')))
|
||||
self.dispatch('GC_PASSWORD_REQUIRED', (room_jid, nick))
|
||||
elif errcode == '403': # we are banned
|
||||
self.dispatch('ERROR', (_('Unable to join group chat'),
|
||||
_('You are banned from this group chat.')))
|
||||
_('You are banned from group chat %s.') % room_jid))
|
||||
elif errcode == '404': # group chat does not exist
|
||||
self.dispatch('ERROR', (_('Unable to join group chat'),
|
||||
_('Such group chat does not exist.')))
|
||||
_('Group chat %s does not exist.') % room_jid))
|
||||
elif errcode == '405':
|
||||
self.dispatch('ERROR', (_('Unable to join group chat'),
|
||||
_('Group chat creation is restricted.')))
|
||||
elif errcode == '406':
|
||||
self.dispatch('ERROR', (_('Unable to join group chat'),
|
||||
_('Your registered nickname must be used.')))
|
||||
_('Your registered nickname must be used in group chat %s.') \
|
||||
% room_jid))
|
||||
elif errcode == '407':
|
||||
self.dispatch('ERROR', (_('Unable to join group chat'),
|
||||
_('You are not in the members list.')))
|
||||
_('You are not in the members list in groupchat %s.') % \
|
||||
room_jid))
|
||||
elif errcode == '409': # nick conflict
|
||||
# the jid_from in this case is FAKE JID: room_jid/nick
|
||||
# resource holds the bad nick so propose a new one
|
||||
|
@ -1692,7 +1751,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
gajim.config.get('gc_proposed_nick_char')
|
||||
room_jid = gajim.get_room_from_fjid(who)
|
||||
self.dispatch('ASK_NEW_NICK', (room_jid, _('Unable to join group chat'),
|
||||
_('Your desired nickname is in use or registered by another occupant.\nPlease specify another nickname below:'), proposed_nickname))
|
||||
_('Your desired nickname in group chat %s is in use or registered by another occupant.\nPlease specify another nickname below:') % room_jid, proposed_nickname))
|
||||
else: # print in the window the error
|
||||
self.dispatch('ERROR_ANSWER', ('', jid_stripped,
|
||||
errmsg, errcode))
|
||||
|
@ -1709,7 +1768,10 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
if jid:
|
||||
# we know real jid, save it in db
|
||||
st += ' (%s)' % jid
|
||||
gajim.logger.write('gcstatus', who, st, show)
|
||||
try:
|
||||
gajim.logger.write('gcstatus', who, st, show)
|
||||
except exceptions.PysqliteOperationalError, e:
|
||||
self.dispatch('ERROR', (_('Disk Write Error'), str(e)))
|
||||
if avatar_sha or avatar_sha == '':
|
||||
if avatar_sha == '':
|
||||
# contact has no avatar
|
||||
|
@ -1728,7 +1790,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
jid = destroy.getAttr('jid')
|
||||
if jid:
|
||||
reason += '\n' + _('You can join this room instead: %s') % jid
|
||||
statusCode = 'destroyed'
|
||||
statusCode = ['destroyed']
|
||||
else:
|
||||
reason = prs.getReason()
|
||||
statusCode = prs.getStatusCode()
|
||||
|
@ -1763,10 +1825,10 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
# 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())
|
||||
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:
|
||||
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:
|
||||
|
@ -1783,10 +1845,10 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
# 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())
|
||||
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:
|
||||
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:
|
||||
|
@ -1816,9 +1878,12 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
# avatar has been updated
|
||||
self.request_vcard(jid_stripped)
|
||||
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('status', jid_stripped, status, show)
|
||||
if gajim.config.get('log_contact_status_changes') and self.name \
|
||||
not in no_log_for and jid_stripped not in no_log_for:
|
||||
try:
|
||||
gajim.logger.write('status', jid_stripped, status, show)
|
||||
except exceptions.PysqliteOperationalError, e:
|
||||
self.dispatch('ERROR', (_('Disk Write Error'), str(e)))
|
||||
self.dispatch('NOTIFY', (jid_stripped, show, status, resource, prio,
|
||||
keyID, timestamp, contact_nickname))
|
||||
# END presenceCB
|
||||
|
@ -1875,6 +1940,10 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
if not self.connection:
|
||||
return
|
||||
self.connection.getRoster(self._on_roster_set)
|
||||
self.discoverItems(gajim.config.get_per('accounts', self.name,
|
||||
'hostname'), id_prefix='p')
|
||||
self.discoverInfo(gajim.config.get_per('accounts', self.name,
|
||||
'hostname'), id_prefix='p')
|
||||
if gajim.config.get_per('accounts', self.name, 'use_ft_proxies'):
|
||||
self.discover_ft_proxies()
|
||||
|
||||
|
@ -1885,10 +1954,6 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
proxies = map(lambda e:e.strip(), cfg_proxies.split(','))
|
||||
for proxy in proxies:
|
||||
gajim.proxy65_manager.resolve(proxy, self.connection)
|
||||
self.discoverItems(gajim.config.get_per('accounts', self.name,
|
||||
'hostname'), id_prefix='p')
|
||||
self.discoverInfo(gajim.config.get_per('accounts', self.name,
|
||||
'hostname'), id_prefix='p')
|
||||
|
||||
def _on_roster_set(self, roster):
|
||||
raw_roster = roster.getRaw()
|
||||
|
@ -1951,29 +2016,31 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
# Get annotations from private namespace
|
||||
self.get_annotations()
|
||||
|
||||
# If it's a gmail account,
|
||||
# inform the server that we want e-mail notifications
|
||||
if gajim.get_server_from_jid(our_jid) in gajim.gmail_domains:
|
||||
gajim.log.debug(('%s is a gmail account. Setting option '
|
||||
'to get e-mail notifications on the server.') % (our_jid))
|
||||
iq = common.xmpp.Iq(typ = 'set', to = our_jid)
|
||||
iq.setAttr('id', 'MailNotify')
|
||||
query = iq.setTag('usersetting')
|
||||
query.setNamespace(common.xmpp.NS_GTALKSETTING)
|
||||
query = query.setTag('mailnotifications')
|
||||
query.setAttr('value', 'true')
|
||||
self.connection.send(iq)
|
||||
# Ask how many messages there are now
|
||||
iq = common.xmpp.Iq(typ = 'get')
|
||||
iq.setAttr('id', '13')
|
||||
query = iq.setTag('query')
|
||||
query.setNamespace(common.xmpp.NS_GMAILNOTIFY)
|
||||
self.connection.send(iq)
|
||||
|
||||
#Inform GUI we just signed in
|
||||
self.dispatch('SIGNED_IN', ())
|
||||
self.continue_connect_info = None
|
||||
|
||||
def request_gmail_notifications(self):
|
||||
# It's a gmail account,
|
||||
# inform the server that we want e-mail notifications
|
||||
our_jid = helpers.parse_jid(gajim.get_jid_from_account(self.name))
|
||||
gajim.log.debug(('%s is a gmail account. Setting option '
|
||||
'to get e-mail notifications on the server.') % (our_jid))
|
||||
iq = common.xmpp.Iq(typ = 'set', to = our_jid)
|
||||
iq.setAttr('id', 'MailNotify')
|
||||
query = iq.setTag('usersetting')
|
||||
query.setNamespace(common.xmpp.NS_GTALKSETTING)
|
||||
query = query.setTag('mailnotifications')
|
||||
query.setAttr('value', 'true')
|
||||
self.connection.send(iq)
|
||||
# Ask how many messages there are now
|
||||
iq = common.xmpp.Iq(typ = 'get')
|
||||
iq.setID(self.connection.getAnID())
|
||||
query = iq.setTag('query')
|
||||
query.setNamespace(common.xmpp.NS_GMAILNOTIFY)
|
||||
self.connection.send(iq)
|
||||
|
||||
|
||||
def _search_fields_received(self, con, iq_obj):
|
||||
jid = jid = helpers.get_jid_from_iq(iq_obj)
|
||||
tag = iq_obj.getTag('query', namespace = common.xmpp.NS_SEARCH)
|
||||
|
@ -1999,6 +2066,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
# that defines handlers
|
||||
con.RegisterHandler('message', self._messageCB)
|
||||
con.RegisterHandler('presence', self._presenceCB)
|
||||
con.RegisterHandler('presence', self._capsPresenceCB)
|
||||
con.RegisterHandler('iq', self._vCardCB, 'result',
|
||||
common.xmpp.NS_VCARD)
|
||||
con.RegisterHandler('iq', self._rosterSetCB, 'set',
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
##
|
||||
## Copyright (C) 2006 Yann Le Boulanger <asterix@lagaule.org>
|
||||
## Copyright (C) 2006 Nikos Kouremenos <kourem@gmail.com>
|
||||
## Copyright (C) 2007 Lukas Petrovicky <lukas@petrovicky.net>
|
||||
## Copyright (C) 2007 Julien Pivotto <roidelapluie@gmail.com>
|
||||
##
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
|
@ -20,7 +22,7 @@ class Contact:
|
|||
'''Information concerning each contact'''
|
||||
def __init__(self, jid='', name='', groups=[], show='', status='', sub='',
|
||||
ask='', resource='', priority=0, keyID='', our_chatstate=None,
|
||||
chatstate=None, last_status_time=None, msg_id = None, composing_jep = None):
|
||||
chatstate=None, last_status_time=None, msg_id = None, composing_xep = None):
|
||||
self.jid = jid
|
||||
self.name = name
|
||||
self.contact_name = '' # nick choosen by contact
|
||||
|
@ -37,6 +39,12 @@ class Contact:
|
|||
self.priority = priority
|
||||
self.keyID = keyID
|
||||
|
||||
# Capabilities; filled by caps.py/ConnectionCaps object
|
||||
# every time it gets these from presence stanzas
|
||||
self.caps_node=None
|
||||
self.caps_ver=None
|
||||
self.caps_exts=None
|
||||
|
||||
# please read jep-85 http://www.jabber.org/jeps/jep-0085.html
|
||||
# we keep track of jep85 support with the peer by three extra states:
|
||||
# None, False and 'ask'
|
||||
|
@ -47,9 +55,9 @@ class Contact:
|
|||
self.our_chatstate = our_chatstate
|
||||
self.msg_id = msg_id
|
||||
# tell which JEP we're using for composing state
|
||||
# None = have to ask, JEP-0022 = use this jep,
|
||||
# JEP-0085 = use this jep, False = no composing support
|
||||
self.composing_jep = composing_jep
|
||||
# None = have to ask, XEP-0022 = use this jep,
|
||||
# XEP-0085 = use this jep, False = no composing support
|
||||
self.composing_xep = composing_xep
|
||||
# this is contact's chatstate
|
||||
self.chatstate = chatstate
|
||||
self.last_status_time = last_status_time
|
||||
|
@ -153,10 +161,10 @@ class Contacts:
|
|||
|
||||
def create_contact(self, jid='', name='', groups=[], show='', status='',
|
||||
sub='', ask='', resource='', priority=0, keyID='', our_chatstate=None,
|
||||
chatstate=None, last_status_time=None, composing_jep=None):
|
||||
chatstate=None, last_status_time=None, composing_xep=None):
|
||||
return Contact(jid, name, groups, show, status, sub, ask, resource,
|
||||
priority, keyID, our_chatstate, chatstate, last_status_time,
|
||||
composing_jep)
|
||||
composing_xep)
|
||||
|
||||
def copy_contact(self, contact):
|
||||
return self.create_contact(jid = contact.jid, name = contact.name,
|
||||
|
@ -208,28 +216,28 @@ class Contacts:
|
|||
# remove metacontacts info
|
||||
self.remove_metacontact(account, jid)
|
||||
|
||||
def get_contact(self, account, jid, resource = None):
|
||||
'''Returns the list of contact instances for this jid (one per resource)
|
||||
or [] if no resource is given
|
||||
returns the contact instance for the given resource if it's given
|
||||
or None if there is not'''
|
||||
def get_contacts(self, account, jid):
|
||||
'''Returns the list of contact instances for this jid.'''
|
||||
if jid in self._contacts[account]:
|
||||
return self._contacts[account][jid]
|
||||
else:
|
||||
return []
|
||||
|
||||
def get_contact(self, account, jid, resource = None):
|
||||
'''Returns the contact instance for the given resource if it's given else
|
||||
the first contact is no resource is given or None if there is not'''
|
||||
if jid in self._contacts[account]:
|
||||
contacts = self._contacts[account][jid]
|
||||
if not resource:
|
||||
return contacts
|
||||
for c in contacts:
|
||||
return self._contacts[account][jid][0]
|
||||
for c in self._contacts[account][jid]:
|
||||
if c.resource == resource:
|
||||
return c
|
||||
if resource:
|
||||
return None
|
||||
return []
|
||||
return None
|
||||
|
||||
def get_contacts_from_jid(self, account, jid):
|
||||
'''we may have two or more resources on that jid'''
|
||||
if jid in self._contacts[account]:
|
||||
contacts_instances = self._contacts[account][jid]
|
||||
return contacts_instances
|
||||
return []
|
||||
def get_contact_from_full_jid(self, account, fjid):
|
||||
''' Get Contact object for specific resource of given jid'''
|
||||
barejid, resource = common.gajim.get_room_and_nick_from_fjid(fjid)
|
||||
return self.get_contact(account, barejid, resource)
|
||||
|
||||
def get_highest_prio_contact_from_contacts(self, contacts):
|
||||
if not contacts:
|
||||
|
@ -241,7 +249,7 @@ class Contacts:
|
|||
return prim_contact
|
||||
|
||||
def get_contact_with_highest_priority(self, account, jid):
|
||||
contacts = self.get_contacts_from_jid(account, jid)
|
||||
contacts = self.get_contacts(account, jid)
|
||||
if not contacts and '/' in jid:
|
||||
# jid may be a fake jid, try it
|
||||
room, nick = jid.split('/', 1)
|
||||
|
@ -258,7 +266,7 @@ class Contacts:
|
|||
'''Returns all contacts in the given group'''
|
||||
group_contacts = []
|
||||
for jid in self._contacts[account]:
|
||||
contacts = self.get_contacts_from_jid(account, jid)
|
||||
contacts = self.get_contacts(account, jid)
|
||||
if group in contacts[0].groups:
|
||||
group_contacts += contacts
|
||||
return group_contacts
|
||||
|
|
|
@ -13,7 +13,7 @@ class WrongFieldValue(Error): pass # when we get xmpp.Node which contains bad fi
|
|||
class ExtendedNode(xmpp.Node, object):
|
||||
@classmethod
|
||||
def __new__(cls, *a, **b):
|
||||
if 'extend' not in b.keys():
|
||||
if 'extend' not in b.keys() or not b['extend']:
|
||||
return object.__new__(cls)
|
||||
|
||||
extend = b['extend']
|
||||
|
@ -76,7 +76,9 @@ def ExtendForm(node):
|
|||
return SimpleDataForm(extend=node)
|
||||
|
||||
class DataField(ExtendedNode):
|
||||
""" Keeps data about one field - var, field type, labels, instructions... """
|
||||
""" Keeps data about one field - var, field type, labels, instructions...
|
||||
Base class for different kinds of fields. Use Field() function to
|
||||
construct one of these. """
|
||||
def __init__(self, typ=None, var=None, value=None, label=None, desc=None, required=False,
|
||||
options=None, extend=None):
|
||||
|
||||
|
@ -390,8 +392,6 @@ class MultipleDataForm(DataForm):
|
|||
DataForm.__init__(self, type=type, title=title, instructions=instructions, extend=extend)
|
||||
# all records, recorded into DataRecords
|
||||
if extend is None:
|
||||
# we have to build this object from scratch
|
||||
xmpp.Node.__init__(self)
|
||||
|
||||
if items is not None: self.items = items
|
||||
else:
|
||||
|
|
|
@ -60,6 +60,8 @@ class SystemBus:
|
|||
return False
|
||||
if self.system_bus is None:
|
||||
return False
|
||||
# Don't exit Gajim when dbus is stopped
|
||||
self.system_bus.set_exit_on_disconnect(False)
|
||||
return True
|
||||
|
||||
system_bus = SystemBus()
|
||||
|
|
|
@ -2,7 +2,7 @@ docdir = '../'
|
|||
|
||||
datadir = '../'
|
||||
|
||||
version = '0.11.1.0'
|
||||
version = '0.11.1.5'
|
||||
|
||||
import sys, os.path
|
||||
for base in ('.', 'common'):
|
||||
|
|
|
@ -143,8 +143,8 @@ class Events:
|
|||
self.fire_event_removed(removed_list)
|
||||
return
|
||||
# no event nor type given, remove them all
|
||||
del self._events[account][jid]
|
||||
self.fire_event_removed(self._events[account][jid])
|
||||
del self._events[account][jid]
|
||||
|
||||
def change_jid(self, account, old_jid, new_jid):
|
||||
if not self._events[account].has_key(old_jid):
|
||||
|
|
|
@ -21,6 +21,15 @@ class PysqliteNotAvailable(Exception):
|
|||
def __str__(self):
|
||||
return _('pysqlite2 (aka python-pysqlite2) dependency is missing. Exiting...')
|
||||
|
||||
class PysqliteOperationalError(Exception):
|
||||
'''sqlite2 raised pysqlite2.dbapi2.OperationalError'''
|
||||
def __init__(self, text=''):
|
||||
Exception.__init__(self)
|
||||
self.text = text
|
||||
|
||||
def __str__(self):
|
||||
return self.text
|
||||
|
||||
class ServiceNotAvailable(Exception):
|
||||
'''This exception is raised when we cannot use Gajim remotely'''
|
||||
def __init__(self):
|
||||
|
|
|
@ -71,6 +71,7 @@ LOGPATH = gajimpaths['LOG'] # deprecated
|
|||
VCARD_PATH = gajimpaths['VCARD']
|
||||
AVATAR_PATH = gajimpaths['AVATAR']
|
||||
MY_EMOTS_PATH = gajimpaths['MY_EMOTS']
|
||||
MY_ICONSETS_PATH = gajimpaths['MY_ICONSETS']
|
||||
TMP = gajimpaths['TMP']
|
||||
DATA_DIR = gajimpaths['DATA']
|
||||
HOME_DIR = gajimpaths['HOME']
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
## Copyright (C) 2005
|
||||
## Dimitur Kirov <dkirov@gmail.com>
|
||||
## Travis Shirk <travis@pobox.com>
|
||||
## Copyright (C) 2007 Lukas Petrovicky <lukas@petrovicky.net>
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published
|
||||
|
@ -206,6 +207,8 @@ def get_contact_dict_for_account(account):
|
|||
contacts_dict['%s (%s)' % (name, contact1.jid)] = contact1
|
||||
contacts_dict['%s (%s)' % (name, jid)] = contact
|
||||
else:
|
||||
if contact.name == gajim.get_nick_from_jid(jid):
|
||||
del contacts_dict[jid]
|
||||
contacts_dict[name] = contact
|
||||
return contacts_dict
|
||||
|
||||
|
@ -462,7 +465,7 @@ def play_sound(event):
|
|||
|
||||
def play_sound_file(path_to_soundfile):
|
||||
if path_to_soundfile == 'beep':
|
||||
print '\a' # make a speaker beep
|
||||
exec_command('beep')
|
||||
return
|
||||
if path_to_soundfile is None or not os.path.exists(path_to_soundfile):
|
||||
return
|
||||
|
@ -544,14 +547,19 @@ 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.events.get_nb_roster_events(account, contact.jid):
|
||||
return 'message'
|
||||
return 'event'
|
||||
if account and gajim.events.get_nb_roster_events(account,
|
||||
contact.get_full_jid()):
|
||||
return 'message'
|
||||
return 'event'
|
||||
if account and gajim.interface.minimized_controls.has_key(account) and \
|
||||
contact.jid in gajim.interface.minimized_controls[account] and gajim.interface.\
|
||||
minimized_controls[account][contact.jid].get_nb_unread_pm() > 0:
|
||||
return 'message'
|
||||
return 'event'
|
||||
if account and gajim.gc_connected[account].has_key(contact.jid):
|
||||
if gajim.gc_connected[account][contact.jid]:
|
||||
return 'muc_active'
|
||||
else:
|
||||
return 'muc_inactive'
|
||||
if contact.jid.find('@') <= 0: # if not '@' or '@' starts the jid ==> agent
|
||||
return contact.show
|
||||
if contact.sub in ('both', 'to'):
|
||||
|
@ -863,66 +871,127 @@ def reduce_chars_newlines(text, max_chars = 0, max_lines = 0):
|
|||
lines = map(lambda e: _cut_if_long(e), lines)
|
||||
if lines:
|
||||
reduced_text = reduce(lambda e, e1: e + '\n' + e1, lines)
|
||||
if reduced_text != text:
|
||||
reduced_text += '...'
|
||||
else:
|
||||
reduced_text = ''
|
||||
return reduced_text
|
||||
|
||||
def get_notification_icon_tooltip_text():
|
||||
text = None
|
||||
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',
|
||||
'printed_marked_gc_msg', 'gc_msg'])
|
||||
unread_pm = gajim.events.get_nb_events(types = ['printed_pm', 'pm'])
|
||||
def get_account_status(account):
|
||||
status = reduce_chars_newlines(account['status_line'], 100, 1)
|
||||
return status
|
||||
|
||||
def get_notification_icon_tooltip_dict():
|
||||
'''returns a dict of the form {acct: {'show': show, 'message': message,
|
||||
'event_lines': [list of text lines to show in tooltip]}'''
|
||||
# How many events must there be before they're shown summarized, not per-user
|
||||
max_ungrouped_events = 10
|
||||
|
||||
accounts = get_accounts_info()
|
||||
|
||||
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
|
||||
if awaiting_events == unread_chat or awaiting_events == unread_single_chat \
|
||||
or awaiting_events == unread_gc or awaiting_events == unread_pm:
|
||||
# This condition is like previous if but with xor...
|
||||
# Print in one line
|
||||
text += '-'
|
||||
else:
|
||||
# Print in multiple lines
|
||||
text += '\n '
|
||||
if unread_chat:
|
||||
text += ngettext(
|
||||
' %d unread message',
|
||||
' %d unread messages',
|
||||
unread_chat, unread_chat, unread_chat)
|
||||
text += '\n '
|
||||
if unread_single_chat:
|
||||
text += ngettext(
|
||||
' %d unread single message',
|
||||
' %d unread single messages',
|
||||
unread_single_chat, unread_single_chat, unread_single_chat)
|
||||
text += '\n '
|
||||
if unread_gc:
|
||||
text += ngettext(
|
||||
' %d unread group chat message',
|
||||
' %d unread group chat messages',
|
||||
unread_gc, unread_gc, unread_gc)
|
||||
text += '\n '
|
||||
if unread_pm:
|
||||
text += ngettext(
|
||||
' %d unread private message',
|
||||
' %d unread private messages',
|
||||
unread_pm, unread_pm, unread_pm)
|
||||
text += '\n '
|
||||
text = text[:-4] # remove latest '\n '
|
||||
elif len(accounts) > 1:
|
||||
text = _('Gajim')
|
||||
elif len(accounts) == 1:
|
||||
message = accounts[0]['status_line']
|
||||
message = reduce_chars_newlines(message, 100, 1)
|
||||
text = _('Gajim - %s') % message
|
||||
else:
|
||||
text = _('Gajim - %s') % get_uf_show('offline')
|
||||
# Gather events. (With accounts, when there are more.)
|
||||
for account in accounts:
|
||||
account_name = account['name']
|
||||
account['event_lines'] = []
|
||||
# Gather events per-account
|
||||
pending_events = gajim.events.get_events(account = account_name)
|
||||
messages, non_messages, total_messages, total_non_messages = {}, {}, 0, 0
|
||||
for jid in pending_events:
|
||||
for event in pending_events[jid]:
|
||||
if event.type_.count('file') > 0:
|
||||
# This is a non-messagee event.
|
||||
messages[jid] = non_messages.get(jid, 0) + 1
|
||||
total_non_messages = total_non_messages + 1
|
||||
else:
|
||||
# This is a message.
|
||||
messages[jid] = messages.get(jid, 0) + 1
|
||||
total_messages = total_messages + 1
|
||||
# Display unread messages numbers, if any
|
||||
if total_messages > 0:
|
||||
if total_messages > max_ungrouped_events:
|
||||
text = ngettext(
|
||||
'%d message pending',
|
||||
'%d messages pending',
|
||||
total_messages, total_messages, total_messages)
|
||||
account['event_lines'].append(text)
|
||||
else:
|
||||
for jid in messages.keys():
|
||||
text = ngettext(
|
||||
'%d message pending',
|
||||
'%d messages pending',
|
||||
messages[jid], messages[jid], messages[jid])
|
||||
contact = gajim.contacts.get_first_contact_from_jid(
|
||||
account['name'], jid)
|
||||
if jid in gajim.gc_connected[account['name']]:
|
||||
text += _(' from room %s') % (jid)
|
||||
elif contact:
|
||||
name = contact.get_shown_name()
|
||||
text += _(' from user %s') % (name)
|
||||
else:
|
||||
text += _(' from %s') % (jid)
|
||||
account['event_lines'].append(text)
|
||||
|
||||
# Display unseen events numbers, if any
|
||||
if total_non_messages > 0:
|
||||
if total_non_messages > max_ungrouped_events:
|
||||
text = ngettext(
|
||||
'%d event pending',
|
||||
'%d events pending',
|
||||
total_non_messages, total_non_messages, total_non_messages)
|
||||
accounts[account]['event_lines'].append(text)
|
||||
else:
|
||||
for jid in non_messages.keys():
|
||||
text = ngettext(
|
||||
'%d event pending',
|
||||
'%d events pending',
|
||||
non_messages[jid], non_messages[jid], non_messages[jid])
|
||||
text += _(' from user %s') % (jid)
|
||||
accounts[account]['event_lines'].append(text)
|
||||
|
||||
return accounts
|
||||
|
||||
def get_notification_icon_tooltip_text():
|
||||
text = None
|
||||
# How many events must there be before they're shown summarized, not per-user
|
||||
max_ungrouped_events = 10
|
||||
# Character which should be used to indent in the tooltip.
|
||||
indent_with = ' '
|
||||
|
||||
accounts = get_notification_icon_tooltip_dict()
|
||||
|
||||
if len(accounts) == 0:
|
||||
# No configured account
|
||||
return _('Gajim')
|
||||
|
||||
# at least one account present
|
||||
|
||||
# Is there more that one account?
|
||||
if len(accounts) == 1:
|
||||
show_more_accounts = False
|
||||
else:
|
||||
show_more_accounts = True
|
||||
|
||||
# If there is only one account, its status is shown on the first line.
|
||||
if show_more_accounts:
|
||||
text = _('Gajim')
|
||||
else:
|
||||
text = _('Gajim - %s') % (get_account_status(accounts[0]))
|
||||
|
||||
# Gather and display events. (With accounts, when there are more.)
|
||||
for account in accounts:
|
||||
account_name = account['name']
|
||||
# Set account status, if not set above
|
||||
if (show_more_accounts):
|
||||
message = '\n' + indent_with + ' %s - %s'
|
||||
text += message % (account_name, get_account_status(account))
|
||||
# Account list shown, messages need to be indented more
|
||||
indent_how = 2
|
||||
else:
|
||||
# If no account list is shown, messages could have default indenting.
|
||||
indent_how = 1
|
||||
for line in account['event_lines']:
|
||||
text += '\n' + indent_with * indent_how + ' '
|
||||
text += line
|
||||
return text
|
||||
|
||||
def get_accounts_info():
|
||||
|
@ -963,3 +1032,21 @@ def get_avatar_path(prefix):
|
|||
if os.path.exists(file_):
|
||||
return file_
|
||||
return None
|
||||
|
||||
def datetime_tuple(timestamp):
|
||||
'''Converts timestamp using strptime and the format: %Y%m%dT%H:%M:%S
|
||||
Because of various datetime formats are used the following exceptions
|
||||
are handled:
|
||||
- Optional milliseconds appened to the string are removed
|
||||
- XEP-082 datetime strings have all '-' cahrs removed to meet
|
||||
the above format.'''
|
||||
timestamp = timestamp.split('.')[0]
|
||||
timestamp = timestamp.replace('-', '')
|
||||
from time import strptime
|
||||
return strptime(timestamp, '%Y%m%dT%H:%M:%S')
|
||||
|
||||
def get_iconset_path(iconset):
|
||||
if os.path.isdir(os.path.join(gajim.DATA_DIR, 'iconsets', iconset)):
|
||||
return os.path.join(gajim.DATA_DIR, 'iconsets', iconset)
|
||||
elif os.path.isdir(os.path.join(gajim.MY_ICONSETS_PATH, iconset)):
|
||||
return os.path.join(gajim.MY_ICONSETS_PATH, iconset)
|
||||
|
|
|
@ -13,10 +13,14 @@
|
|||
## GNU General Public License for more details.
|
||||
##
|
||||
|
||||
''' This module allows to access the on-disk database of logs. '''
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import datetime
|
||||
from gzip import GzipFile
|
||||
from cStringIO import StringIO
|
||||
|
||||
import exceptions
|
||||
import gajim
|
||||
|
@ -169,19 +173,21 @@ class Logger:
|
|||
jid = jid.split('/', 1)[0] # remove the resource
|
||||
if jid in self.jids_already_in: # we already have jids in DB
|
||||
self.cur.execute('SELECT jid_id FROM jids WHERE jid=?', [jid])
|
||||
jid_id = self.cur.fetchone()[0]
|
||||
else: # oh! a new jid :), we add it now
|
||||
if typestr == 'ROOM':
|
||||
typ = constants.JID_ROOM_TYPE
|
||||
else:
|
||||
typ = constants.JID_NORMAL_TYPE
|
||||
self.cur.execute('INSERT INTO jids (jid, type) VALUES (?, ?)', (jid, typ))
|
||||
try:
|
||||
self.con.commit()
|
||||
except sqlite.OperationalError, e:
|
||||
print >> sys.stderr, str(e)
|
||||
jid_id = self.cur.lastrowid
|
||||
self.jids_already_in.append(jid)
|
||||
row = self.cur.fetchone()
|
||||
if row:
|
||||
return row[0]
|
||||
# oh! a new jid :), we add it now
|
||||
if typestr == 'ROOM':
|
||||
typ = constants.JID_ROOM_TYPE
|
||||
else:
|
||||
typ = constants.JID_NORMAL_TYPE
|
||||
self.cur.execute('INSERT INTO jids (jid, type) VALUES (?, ?)', (jid, typ))
|
||||
try:
|
||||
self.con.commit()
|
||||
except sqlite.OperationalError, e:
|
||||
print >> sys.stderr, str(e)
|
||||
jid_id = self.cur.lastrowid
|
||||
self.jids_already_in.append(jid)
|
||||
return jid_id
|
||||
|
||||
def convert_human_values_to_db_api_values(self, kind, show):
|
||||
|
@ -285,7 +291,10 @@ class Logger:
|
|||
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 (?, ?, ?, ?, ?, ?, ?)'
|
||||
self.cur.execute(sql, values)
|
||||
try:
|
||||
self.cur.execute(sql, values)
|
||||
except sqlite.OperationalError, e:
|
||||
raise exceptions.PysqliteOperationalError(str(e))
|
||||
message_id = None
|
||||
try:
|
||||
self.con.commit()
|
||||
|
@ -625,3 +634,77 @@ class Logger:
|
|||
for result in results:
|
||||
answer[result[0]] = self.convert_api_values_to_human_transport_type(result[1])
|
||||
return answer
|
||||
|
||||
# A longer note here:
|
||||
# The database contains a blob field. Pysqlite seems to need special care for such fields.
|
||||
# When storing, we need to convert string into buffer object (1).
|
||||
# When retrieving, we need to convert it back to a string to decompress it. (2)
|
||||
# GzipFile needs a file-like object, StringIO emulates file for plain strings.
|
||||
def iter_caps_data(self):
|
||||
''' Iterate over caps cache data stored in the database.
|
||||
The iterator values are pairs of (node, ver, ext, identities, features):
|
||||
identities == {'category':'foo', 'type':'bar', 'name':'boo'},
|
||||
features being a list of feature namespaces. '''
|
||||
|
||||
# get data from table
|
||||
# the data field contains binary object (gzipped data), this is a hack
|
||||
# to get that data without trying to convert it to unicode
|
||||
#tmp, self.con.text_factory = self.con.text_factory, str
|
||||
try:
|
||||
self.cur.execute('''SELECT node, ver, ext, data FROM caps_cache;''');
|
||||
except sqlite.OperationalError:
|
||||
# might happen when there's no caps_cache table yet
|
||||
# -- there's no data to read anyway then
|
||||
#self.con.text_factory = tmp
|
||||
return
|
||||
#self.con.text_factory = tmp
|
||||
|
||||
for node, ver, ext, data in self.cur:
|
||||
# for each row: unpack the data field
|
||||
# (format: (category, type, name, category, type, name, ...
|
||||
# ..., 'FEAT', feature1, feature2, ...).join(' '))
|
||||
# NOTE: if there's a need to do more gzip, put that to a function
|
||||
data=GzipFile(fileobj=StringIO(str(data))).read().split('\0') # (2) -- note above
|
||||
i=0
|
||||
identities=set()
|
||||
features=set()
|
||||
while i<(len(data)-2) and data[i]!='FEAT':
|
||||
category=data[i]
|
||||
type=data[i+1]
|
||||
name=data[i+2]
|
||||
identities.add((category,type,name))
|
||||
i+=3
|
||||
i+=1
|
||||
while i<len(data):
|
||||
features.add(data[i])
|
||||
i+=1
|
||||
if not ext: ext=None # to make '' a None
|
||||
|
||||
# yield the row
|
||||
yield node, ver, ext, identities, features
|
||||
|
||||
def add_caps_entry(self, node, ver, ext, identities, features):
|
||||
data=[]
|
||||
for identity in identities:
|
||||
# there is no FEAT category
|
||||
if identity[0]=='FEAT': return
|
||||
if len(identity)<2 or not identity[2]:
|
||||
data.extend((identity[0], identity[1], ''))
|
||||
else:
|
||||
data.extend(identity)
|
||||
data.append('FEAT')
|
||||
data.extend(features)
|
||||
data = '\0'.join(data)
|
||||
string = StringIO() # if there's a need to do more gzip, put that to a function
|
||||
gzip=GzipFile(fileobj=string, mode='w')
|
||||
gzip.write(data)
|
||||
gzip.close()
|
||||
data = string.getvalue()
|
||||
self.cur.execute('''
|
||||
INSERT INTO caps_cache ( node, ver, ext, data )
|
||||
VALUES (?, ?, ?, ?);
|
||||
''', (node, ver, ext, buffer(data))) # (1) -- note above
|
||||
try:
|
||||
self.con.commit()
|
||||
except sqlite.OperationalError, e:
|
||||
print >> sys.stderr, str(e)
|
||||
|
|
|
@ -153,9 +153,21 @@ class OptionsParser:
|
|||
self.update_config_to_01101()
|
||||
if old < [0, 11, 0, 2] and new >= [0, 11, 0, 2]:
|
||||
self.update_config_to_01102()
|
||||
if old < [0, 11, 1, 1] and new >= [0, 11, 1, 1]:
|
||||
self.update_config_to_01111()
|
||||
if old < [0, 11, 1, 2] and new >= [0, 11, 1, 2]:
|
||||
self.update_config_to_01112()
|
||||
if old < [0, 11, 1, 3] and new >= [0, 11, 1, 3]:
|
||||
self.update_config_to_01113()
|
||||
if old < [0, 11, 1, 4] and new >= [0, 11, 1, 4]:
|
||||
self.update_config_to_01114()
|
||||
if old < [0, 11, 1, 5] and new >= [0, 11, 1, 5]:
|
||||
self.update_config_to_01115()
|
||||
|
||||
gajim.logger.init_vars()
|
||||
gajim.config.set('version', new_version)
|
||||
|
||||
gajim.capscache.load_from_db()
|
||||
|
||||
def update_config_x_to_09(self):
|
||||
# Var name that changed:
|
||||
|
@ -178,7 +190,7 @@ class OptionsParser:
|
|||
'groupfontattrs', 'contacttextcolor', 'contactbgcolor', 'contactfont',
|
||||
'contactfontattrs', 'bannertextcolor', 'bannerbgcolor', 'bannerfont',
|
||||
'bannerfontattrs']
|
||||
for theme_name in (_('grocery'), _('gtk+')):
|
||||
for theme_name in (_('grocery'), _('default')):
|
||||
if theme_name not in gajim.config.get_per('themes'):
|
||||
gajim.config.add_per('themes', theme_name)
|
||||
theme = gajim.config.themes_default[theme_name]
|
||||
|
@ -209,7 +221,6 @@ class OptionsParser:
|
|||
|
||||
def assert_unread_msgs_table_exists(self):
|
||||
'''create table unread_messages if there is no such table'''
|
||||
#FIXME see #2812
|
||||
back = os.getcwd()
|
||||
os.chdir(logger.LOG_DB_FOLDER)
|
||||
con = sqlite.connect(logger.LOG_DB_FILE)
|
||||
|
@ -384,3 +395,84 @@ class OptionsParser:
|
|||
gajim.config.set('ft_add_hosts_to_send',
|
||||
self.old_values['ft_override_host_to_send'])
|
||||
gajim.config.set('version', '0.11.0.2')
|
||||
|
||||
def update_config_to_01111(self):
|
||||
'''always_hide_chatbuttons -> compact_view'''
|
||||
if self.old_values.has_key('always_hide_groupchat_buttons') and \
|
||||
self.old_values.has_key('always_hide_chat_buttons'):
|
||||
gajim.config.set('compact_view', self.old_values['always_hide_groupchat_buttons'] and \
|
||||
self.old_values['always_hide_chat_buttons'])
|
||||
gajim.config.set('version', '0.11.1.1')
|
||||
|
||||
def update_config_to_01112(self):
|
||||
'''gtk+ theme is renamed to default'''
|
||||
if self.old_values.has_key('roster_theme') and \
|
||||
self.old_values['roster_theme'] == 'gtk+':
|
||||
gajim.config.set('roster_theme', _('default'))
|
||||
gajim.config.set('version', '0.11.1.2')
|
||||
|
||||
def update_config_to_01113(self):
|
||||
# copy&pasted from update_config_to_01013, possibly 'FIXME see #2812' applies too
|
||||
back = os.getcwd()
|
||||
os.chdir(logger.LOG_DB_FOLDER)
|
||||
con = sqlite.connect(logger.LOG_DB_FILE)
|
||||
os.chdir(back)
|
||||
cur = con.cursor()
|
||||
try:
|
||||
cur.executescript(
|
||||
'''
|
||||
CREATE TABLE caps_cache (
|
||||
node TEXT,
|
||||
ver TEXT,
|
||||
ext TEXT,
|
||||
data BLOB
|
||||
);
|
||||
'''
|
||||
)
|
||||
con.commit()
|
||||
except sqlite.OperationalError, e:
|
||||
pass
|
||||
con.close()
|
||||
gajim.config.set('version', '0.11.1.3')
|
||||
|
||||
def update_config_to_01114(self):
|
||||
# add default theme if it doesn't exist
|
||||
d = ['accounttextcolor', 'accountbgcolor', 'accountfont',
|
||||
'accountfontattrs', 'grouptextcolor', 'groupbgcolor', 'groupfont',
|
||||
'groupfontattrs', 'contacttextcolor', 'contactbgcolor', 'contactfont',
|
||||
'contactfontattrs', 'bannertextcolor', 'bannerbgcolor', 'bannerfont',
|
||||
'bannerfontattrs']
|
||||
theme_name = _('default')
|
||||
if theme_name not in gajim.config.get_per('themes'):
|
||||
gajim.config.add_per('themes', theme_name)
|
||||
if gajim.config.get_per('themes', 'gtk+'):
|
||||
# copy from old gtk+ theme
|
||||
for o in d:
|
||||
val = gajim.config.get_per('themes', 'gtk+', o)
|
||||
gajim.config.set_per('themes', theme_name, o, val)
|
||||
gajim.config.del_per('themes', 'gtk+')
|
||||
else:
|
||||
# copy from default theme
|
||||
theme = gajim.config.themes_default[theme_name]
|
||||
for o in d:
|
||||
gajim.config.set_per('themes', theme_name, o, theme[d.index(o)])
|
||||
gajim.config.set('version', '0.11.1.4')
|
||||
|
||||
def update_config_to_01115(self):
|
||||
# copy&pasted from update_config_to_01013, possibly 'FIXME see #2812' applies too
|
||||
back = os.getcwd()
|
||||
os.chdir(logger.LOG_DB_FOLDER)
|
||||
con = sqlite.connect(logger.LOG_DB_FILE)
|
||||
os.chdir(back)
|
||||
cur = con.cursor()
|
||||
try:
|
||||
cur.executescript(
|
||||
'''
|
||||
DELETE FROM caps_cache;
|
||||
'''
|
||||
)
|
||||
con.commit()
|
||||
except sqlite.OperationalError, e:
|
||||
pass
|
||||
con.close()
|
||||
gajim.config.set('version', '0.11.1.5')
|
||||
|
|
|
@ -81,12 +81,18 @@ class GnomePasswordStorage(PasswordStorage):
|
|||
def save_password(self, account_name, password, update=True):
|
||||
display_name = _('Gajim account %s') % account_name
|
||||
attributes = dict(account_name=str(account_name), gajim=1)
|
||||
auth_token = gnomekeyring.item_create_sync(
|
||||
self.keyring, gnomekeyring.ITEM_GENERIC_SECRET,
|
||||
display_name, attributes, password, update)
|
||||
try:
|
||||
auth_token = gnomekeyring.item_create_sync(
|
||||
self.keyring, gnomekeyring.ITEM_GENERIC_SECRET,
|
||||
display_name, attributes, password, update)
|
||||
except gnomekeyring.DeniedError:
|
||||
set_storage(SimplePasswordStorage())
|
||||
storage.save_password(account_name, password)
|
||||
return
|
||||
token = 'gnomekeyring:%i' % auth_token
|
||||
gajim.config.set_per('accounts', account_name, 'password', token)
|
||||
|
||||
if gajim.connections.has_key(account_name):
|
||||
gajim.connections[account_name].password = password
|
||||
|
||||
storage = None
|
||||
def get_storage():
|
||||
|
@ -111,6 +117,8 @@ def get_storage():
|
|||
storage = GnomePasswordStorage()
|
||||
except gnomekeyring.NoKeyringDaemonError:
|
||||
storage = SimplePasswordStorage()
|
||||
except gnomekeyring.DeniedError:
|
||||
storage = SimplePasswordStorage()
|
||||
else:
|
||||
storage = SimplePasswordStorage()
|
||||
return storage
|
||||
|
|
|
@ -92,7 +92,7 @@ class ConnectionPubSub:
|
|||
try:
|
||||
cb, args, kwargs = self.__callbacks.pop(stanza.getID())
|
||||
cb(conn, stanza, *args, **kwargs)
|
||||
except KeyError:
|
||||
except:
|
||||
pass
|
||||
|
||||
def request_pb_configuration(self, jid, node):
|
||||
|
|
|
@ -348,9 +348,10 @@ class Socks5:
|
|||
def __init__(self, idlequeue, host, port, initiator, target, sid):
|
||||
if host is not None:
|
||||
try:
|
||||
self.host = socket.gethostbyname(host)
|
||||
self.host = host
|
||||
self.ais = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM)
|
||||
except socket.gaierror:
|
||||
self.host = None
|
||||
self.ais = None
|
||||
self.idlequeue = idlequeue
|
||||
self.fd = -1
|
||||
self.port = port
|
||||
|
@ -793,6 +794,8 @@ class Socks5Listener(IdleObject):
|
|||
only pollin events though
|
||||
'''
|
||||
self.port = port
|
||||
self.ais = socket.getaddrinfo(None, port, socket.AF_UNSPEC,
|
||||
socket.SOCK_STREAM, socket.SOL_TCP, socket.AI_PASSIVE)
|
||||
self.queue_idx = -1
|
||||
self.idlequeue = idlequeue
|
||||
self.queue = None
|
||||
|
@ -801,14 +804,21 @@ class Socks5Listener(IdleObject):
|
|||
self.fd = -1
|
||||
|
||||
def bind(self):
|
||||
self._serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self._serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self._serv.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||
self._serv.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||
# will fail when port as busy, or we don't have rights to bind
|
||||
try:
|
||||
self._serv.bind(('0.0.0.0', self.port))
|
||||
except Exception, e:
|
||||
for ai in self.ais:
|
||||
#try the different possibilities (ipv6, ipv4, etc.)
|
||||
self._serv = socket.socket(*ai[:3])
|
||||
self._serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self._serv.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||
self._serv.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||
# will fail when port as busy, or we don't have rights to bind
|
||||
try:
|
||||
self._serv.bind(ai[4])
|
||||
self.ai = ai
|
||||
break
|
||||
except:
|
||||
self.ai = None
|
||||
continue
|
||||
if not self.ai:
|
||||
# unable to bind, show error dialog
|
||||
return None
|
||||
self._serv.listen(socket.SOMAXCONN)
|
||||
|
@ -884,9 +894,18 @@ class Socks5Receiver(Socks5, IdleObject):
|
|||
|
||||
def connect(self):
|
||||
''' create the socket and plug it to the idlequeue '''
|
||||
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# this will not block the GUI
|
||||
self._sock.setblocking(False)
|
||||
for ai in self.ais:
|
||||
try:
|
||||
self._sock=socket.socket(*ai[:3])
|
||||
# this will not block the GUI
|
||||
self._sock.setblocking(False)
|
||||
self._server=ai[4]
|
||||
break
|
||||
except:
|
||||
if sys.exc_value[0] == errno.EINPROGRESS:
|
||||
break
|
||||
#for all errors, we try other addresses
|
||||
continue
|
||||
self.fd = self._sock.fileno()
|
||||
self.state = 0 # about to be connected
|
||||
self.idlequeue.plug_idle(self, True, False)
|
||||
|
@ -950,7 +969,7 @@ class Socks5Receiver(Socks5, IdleObject):
|
|||
|
||||
def do_connect(self):
|
||||
try:
|
||||
self._sock.connect((self.host, self.port))
|
||||
self._sock.connect(self._server)
|
||||
self._sock.setblocking(False)
|
||||
self._send=self._sock.send
|
||||
self._recv=self._sock.recv
|
||||
|
|
|
@ -87,7 +87,7 @@ class Commands(PlugIn):
|
|||
elif self._handlers[''].has_key(node):
|
||||
self._handlers[''][node]['execute'](conn,request)
|
||||
else:
|
||||
conn.send(Error(requet,ERR_ITEM_NOT_FOUND))
|
||||
conn.send(Error(request,ERR_ITEM_NOT_FOUND))
|
||||
raise NodeProcessed
|
||||
|
||||
def _DiscoHandler(self,conn,request,typ):
|
||||
|
|
|
@ -23,7 +23,7 @@ Contains one tunable attribute: DefaultTimeout (25 seconds by default). It defin
|
|||
Dispatcher.SendAndWaitForResponce method will wait for reply stanza before giving up.
|
||||
'''
|
||||
|
||||
import simplexml, sys
|
||||
import simplexml, sys, locale
|
||||
from xml.parsers.expat import ExpatError
|
||||
from protocol import *
|
||||
from client import PlugIn
|
||||
|
@ -111,6 +111,9 @@ class Dispatcher(PlugIn):
|
|||
self._metastream.setAttr('version', '1.0')
|
||||
self._metastream.setAttr('xmlns:stream', NS_STREAMS)
|
||||
self._metastream.setAttr('to', self._owner.Server)
|
||||
if locale.getdefaultlocale()[0]:
|
||||
self._metastream.setAttr('xml:lang',
|
||||
locale.getdefaultlocale()[0].split('_')[0])
|
||||
self._owner.send("<?xml version='1.0'?>%s>" % str(self._metastream)[:-2])
|
||||
|
||||
def _check_stream_start(self, ns, tag, attrs):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
## features.py
|
||||
##
|
||||
## Copyright (C) 2003-2004 Alexey "Snake" Nezhdanov
|
||||
## Copyright (C) 2007 Julien Pivotto <roidelapluie@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
|
||||
|
@ -71,6 +72,7 @@ def discoverItems(disp,jid,node=None, cb=None):
|
|||
cb(ret)
|
||||
_discover(disp, NS_DISCO_ITEMS, jid, node, _on_response)
|
||||
|
||||
# this one is
|
||||
def discoverInfo(disp,jid,node=None, cb=None):
|
||||
""" Query remote object about info that it publishes. Returns identities and features lists."""
|
||||
""" According to JEP-0030:
|
||||
|
@ -128,16 +130,13 @@ def _ReceivedRegInfo(con, resp, agent):
|
|||
return
|
||||
df=tag.getTag('x',namespace=NS_DATA)
|
||||
if df:
|
||||
con.Event(NS_REGISTER,REGISTER_DATA_RECEIVED,(agent,DataForm(node=df),True,''))
|
||||
con.Event(NS_REGISTER,REGISTER_DATA_RECEIVED,(agent,df,True,''))
|
||||
return
|
||||
df=DataForm(typ='form')
|
||||
df={}
|
||||
for i in resp.getQueryPayload():
|
||||
if not isinstance(i, Node):
|
||||
pass
|
||||
elif i.getName()=='instructions':
|
||||
df.addInstructions(i.getData())
|
||||
else:
|
||||
df.setField(i.getName()).setValue(i.getData())
|
||||
continue
|
||||
df[i.getName()] = i.getData()
|
||||
con.Event(NS_REGISTER, REGISTER_DATA_RECEIVED, (agent,df,False,''))
|
||||
|
||||
def register(disp, host, info, cb):
|
||||
|
|
|
@ -21,8 +21,8 @@ xmpp-related data structures.
|
|||
|
||||
from simplexml import Node,NodeBuilder,ustr
|
||||
import time
|
||||
NS_ACTIVITY ='http://jabber.org/protocol/activity' # JEP-0108
|
||||
NS_ADDRESS ='http://jabber.org/protocol/address' # JEP-0033
|
||||
NS_ACTIVITY ='http://jabber.org/protocol/activity' # XEP-0108
|
||||
NS_ADDRESS ='http://jabber.org/protocol/address' # XEP-0033
|
||||
NS_AGENTS ='jabber:iq:agents'
|
||||
NS_AMP ='http://jabber.org/protocol/amp'
|
||||
NS_AMP_ERRORS =NS_AMP+'#errors'
|
||||
|
@ -39,58 +39,58 @@ NS_CLIENT ='jabber:client'
|
|||
NS_COMMANDS ='http://jabber.org/protocol/commands'
|
||||
NS_COMPONENT_ACCEPT='jabber:component:accept'
|
||||
NS_COMPONENT_1 ='http://jabberd.jabberstudio.org/ns/component/1.0'
|
||||
NS_COMPRESS ='http://jabber.org/protocol/compress' # JEP-0138
|
||||
NS_COMPRESS ='http://jabber.org/protocol/compress' # XEP-0138
|
||||
NS_CONFERENCE ='jabber:x:conference'
|
||||
NS_DATA ='jabber:x:data' # JEP-0004
|
||||
NS_DATA ='jabber:x:data' # XEP-0004
|
||||
NS_DELAY ='jabber:x:delay'
|
||||
NS_DIALBACK ='jabber:server:dialback'
|
||||
NS_DISCO ='http://jabber.org/protocol/disco'
|
||||
NS_DISCO_INFO =NS_DISCO+'#info'
|
||||
NS_DISCO_ITEMS =NS_DISCO+'#items'
|
||||
NS_ENCRYPTED ='jabber:x:encrypted' # JEP-0027
|
||||
NS_EVENT ='jabber:x:event' # JEP-0022
|
||||
NS_ENCRYPTED ='jabber:x:encrypted' # XEP-0027
|
||||
NS_EVENT ='jabber:x:event' # XEP-0022
|
||||
NS_FEATURE ='http://jabber.org/protocol/feature-neg'
|
||||
NS_FILE ='http://jabber.org/protocol/si/profile/file-transfer' # JEP-0096
|
||||
NS_GAMING ='http://jabber.org/protocol/gaming' # XEP-0196
|
||||
NS_GEOLOC ='http://jabber.org/protocol/geoloc' # JEP-0080
|
||||
NS_GROUPCHAT ='gc-1.0'
|
||||
NS_HTTP_AUTH ='http://jabber.org/protocol/http-auth' # JEP-0070
|
||||
NS_HTTP_BIND ='http://jabber.org/protocol/httpbind' # JEP-0124
|
||||
NS_HTTP_AUTH ='http://jabber.org/protocol/http-auth' # XEP-0070
|
||||
NS_HTTP_BIND ='http://jabber.org/protocol/httpbind' # XEP-0124
|
||||
NS_IBB ='http://jabber.org/protocol/ibb'
|
||||
NS_INVISIBLE ='presence-invisible' # Jabberd2
|
||||
NS_IQ ='iq' # Jabberd2
|
||||
NS_LAST ='jabber:iq:last'
|
||||
NS_MESSAGE ='message' # Jabberd2
|
||||
NS_MOOD ='http://jabber.org/protocol/mood' # JEP-0107
|
||||
NS_MOOD ='http://jabber.org/protocol/mood' # XEP-0107
|
||||
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_NICK ='http://jabber.org/protocol/nick' # XEP-0172
|
||||
NS_OFFLINE ='http://www.jabber.org/jeps/jep-0030.html' # XEP-0013
|
||||
NS_PHYSLOC ='http://jabber.org/protocol/physloc' # XEP-0112
|
||||
NS_PRESENCE ='presence' # Jabberd2
|
||||
NS_PRIVACY ='jabber:iq:privacy'
|
||||
NS_PRIVATE ='jabber:iq:private'
|
||||
NS_PROFILE ='http://jabber.org/protocol/profile' # JEP-0154
|
||||
NS_PUBSUB ='http://jabber.org/protocol/pubsub' # JEP-0060
|
||||
NS_PROFILE ='http://jabber.org/protocol/profile' # XEP-0154
|
||||
NS_PUBSUB ='http://jabber.org/protocol/pubsub' # XEP-0060
|
||||
NS_PUBSUB_OWNER ='http://jabber.org/protocol/pubsub#owner' # JEP-0060
|
||||
NS_REGISTER ='jabber:iq:register'
|
||||
NS_ROSTER ='jabber:iq:roster'
|
||||
NS_ROSTERX ='http://jabber.org/protocol/rosterx' # JEP-0144
|
||||
NS_RPC ='jabber:iq:rpc' # JEP-0009
|
||||
NS_ROSTERX ='http://jabber.org/protocol/rosterx' # XEP-0144
|
||||
NS_RPC ='jabber:iq:rpc' # XEP-0009
|
||||
NS_SASL ='urn:ietf:params:xml:ns:xmpp-sasl'
|
||||
NS_SEARCH ='jabber:iq:search'
|
||||
NS_SERVER ='jabber:server'
|
||||
NS_SESSION ='urn:ietf:params:xml:ns:xmpp-session'
|
||||
NS_SI ='http://jabber.org/protocol/si' # JEP-0096
|
||||
NS_SI_PUB ='http://jabber.org/protocol/sipub' # JEP-0137
|
||||
NS_SIGNED ='jabber:x:signed' # JEP-0027
|
||||
NS_SI ='http://jabber.org/protocol/si' # XEP-0096
|
||||
NS_SI_PUB ='http://jabber.org/protocol/sipub' # XEP-0137
|
||||
NS_SIGNED ='jabber:x:signed' # XEP-0027
|
||||
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' # JEP-0900
|
||||
NS_TIME_REVISED ='http://www.xmpp.org/extensions/xep-0202.html#ns' # JEP-0202
|
||||
NS_TIME ='jabber:iq:time' # XEP-0900
|
||||
NS_TIME_REVISED ='urn:xmpp:time' # XEP-0202
|
||||
NS_TLS ='urn:ietf:params:xml:ns:xmpp-tls'
|
||||
NS_TUNE ='http://jabber.org/protocol/tune' # XEP-0118
|
||||
NS_VACATION ='http://jabber.org/protocol/vacation'
|
||||
|
@ -101,11 +101,11 @@ NS_VCARD_UPDATE =NS_VCARD+':x:update'
|
|||
NS_VERSION ='jabber:iq:version'
|
||||
NS_VIEWING ='http://jabber.org/protocol/viewing' # XEP--197
|
||||
NS_PING ='urn:xmpp:ping' # XEP-0199
|
||||
NS_WAITINGLIST ='http://jabber.org/protocol/waitinglist' # JEP-0130
|
||||
NS_XHTML_IM ='http://jabber.org/protocol/xhtml-im' # JEP-0071
|
||||
NS_WAITINGLIST ='http://jabber.org/protocol/waitinglist' # XEP-0130
|
||||
NS_XHTML_IM ='http://jabber.org/protocol/xhtml-im' # XEP-0071
|
||||
NS_XHTML = 'http://www.w3.org/1999/xhtml' # "
|
||||
NS_DATA_LAYOUT ='http://jabber.org/protocol/xdata-layout' # JEP-0141
|
||||
NS_DATA_VALIDATE='http://jabber.org/protocol/xdata-validate' # JEP-0122
|
||||
NS_DATA_LAYOUT ='http://jabber.org/protocol/xdata-layout' # XEP-0141
|
||||
NS_DATA_VALIDATE='http://jabber.org/protocol/xdata-validate' # XEP-0122
|
||||
NS_XMPP_STREAMS ='urn:ietf:params:xml:ns:xmpp-streams'
|
||||
|
||||
xmpp_stream_error_conditions="""
|
||||
|
@ -429,7 +429,7 @@ class Message(Protocol):
|
|||
self.setTagData('body',val)
|
||||
|
||||
def setXHTML(self,val,xmllang=None):
|
||||
""" Sets the xhtml text of the message (JEP-0071).
|
||||
""" Sets the xhtml text of the message (XEP-0071).
|
||||
The parameter is the "inner html" to the body."""
|
||||
try:
|
||||
if xmllang:
|
||||
|
@ -456,6 +456,14 @@ class Message(Protocol):
|
|||
th=self.getThread()
|
||||
if th: m.setThread(th)
|
||||
return m
|
||||
def getStatusCode(self):
|
||||
"""Returns the status code of the message (for groupchat config
|
||||
change)"""
|
||||
attrs = []
|
||||
for xtag in self.getTags('x'):
|
||||
for child in xtag.getTags('status'):
|
||||
attrs.append(child.getAttr('code'))
|
||||
return attrs
|
||||
|
||||
class Presence(Protocol):
|
||||
""" XMPP Presence object."""
|
||||
|
@ -516,7 +524,11 @@ class Presence(Protocol):
|
|||
return self._muc_getSubTagDataAttr('actor','jid')[1]
|
||||
def getStatusCode(self):
|
||||
"""Returns the status code of the presence (for groupchat)"""
|
||||
return self._muc_getItemAttr('status','code')
|
||||
attrs = []
|
||||
for xtag in self.getTags('x'):
|
||||
for child in xtag.getTags('status'):
|
||||
attrs.append(child.getAttr('code'))
|
||||
return attrs
|
||||
|
||||
class Iq(Protocol):
|
||||
""" XMPP Iq object - get/set dialog mechanism. """
|
||||
|
@ -597,7 +609,7 @@ class Error(Protocol):
|
|||
|
||||
class DataField(Node):
|
||||
""" This class is used in the DataForm class to describe the single data item.
|
||||
If you are working with jabber:x:data (JEP-0004, JEP-0068, JEP-0122)
|
||||
If you are working with jabber:x:data (XEP-0004, XEP-0068, XEP-0122)
|
||||
then you will need to work with instances of this class. """
|
||||
def __init__(self,name=None,value=None,typ=None,required=0,desc=None,options=[],node=None):
|
||||
""" Create new data field of specified name,value and type.
|
||||
|
@ -674,7 +686,7 @@ class DataField(Node):
|
|||
|
||||
class DataForm(Node):
|
||||
""" DataForm class. Used for manipulating dataforms in XMPP.
|
||||
Relevant JEPs: 0004, 0068, 0122.
|
||||
Relevant XEPs: 0004, 0068, 0122.
|
||||
Can be used in disco, pub-sub and many other applications."""
|
||||
def __init__(self, typ=None, data=[], title=None, node=None):
|
||||
"""
|
||||
|
|
|
@ -33,6 +33,8 @@ import thread
|
|||
import logging
|
||||
log = logging.getLogger('gajim.c.x.transports_nb')
|
||||
|
||||
from common import gajim
|
||||
|
||||
USE_PYOPENSSL = False
|
||||
|
||||
try:
|
||||
|
@ -296,7 +298,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
|||
self.renew_send_timeout()
|
||||
|
||||
def connect(self,server=None, proxy = None, secure = None):
|
||||
''' Try to establish connection. Returns non-empty string on success. '''
|
||||
''' Try to establish connection. Returns True/False on success/failure. '''
|
||||
if not server:
|
||||
server=self._server
|
||||
else:
|
||||
|
@ -416,6 +418,12 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
|||
self.idlequeue.remove_timeout(self.fd)
|
||||
|
||||
def onreceive(self, recv_handler):
|
||||
''' Sets the on_receive callback. Do not confuse it with
|
||||
on_receive() method, which is the callback itself.
|
||||
|
||||
If recv_handler==None, it tries to set that callback assuming that
|
||||
our owner also has a Dispatcher object plugged in, to its
|
||||
ProcessNonBlocking method.'''
|
||||
if not recv_handler:
|
||||
if hasattr(self._owner, 'Dispatcher'):
|
||||
self.on_receive = self._owner.Dispatcher.ProcessNonBlocking
|
||||
|
@ -735,7 +743,12 @@ class NonBlockingTLS(PlugIn):
|
|||
# FIXME: should method be configurable?
|
||||
tcpsock._sslContext = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD)
|
||||
#tcpsock._sslContext = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
|
||||
tcpsock._sslContext.set_info_callback(self._ssl_info_callback)
|
||||
tcpsock.ssl_errnum = 0
|
||||
tcpsock._sslContext.set_verify(OpenSSL.SSL.VERIFY_PEER, self._ssl_verify_callback)
|
||||
try:
|
||||
tcpsock._sslContext.load_verify_locations(os.path.join(gajim.DATA_DIR, 'other', 'cacerts.pem'))
|
||||
except:
|
||||
log.warning(_("Unable to load SSL certificats from file %s" % os.path.abspath(os.path.join(gajim.DATA_DIR,'other','ca.crt'))))
|
||||
tcpsock._sslObj = OpenSSL.SSL.Connection(tcpsock._sslContext, tcpsock._sock)
|
||||
tcpsock._sslObj.set_connect_state() # set to client mode
|
||||
|
||||
|
@ -759,29 +772,6 @@ class NonBlockingTLS(PlugIn):
|
|||
# fake it, for now
|
||||
self.starttls='success'
|
||||
|
||||
def _on_ssl_handshake_done(self):
|
||||
log.debug("Handshake done!")
|
||||
#self.starttls='success'
|
||||
|
||||
tcpsock = self._owner.Connection
|
||||
cert = tcpsock._sslObj.get_peer_certificate()
|
||||
peer = cert.get_subject()
|
||||
issuer = cert.get_issuer()
|
||||
tcpsock._sslIssuer = unicode(issuer)
|
||||
tcpsock._sslServer = unicode(peer)
|
||||
tcpsock.serverDigestSHA1 = cert.digest('sha1')
|
||||
tcpsock.serverDigestMD5 = cert.digest('md5')
|
||||
|
||||
if log.getEffectiveLevel() <= logging.DEBUG:
|
||||
peercert = tcpsock._sslObj.get_peer_certificate()
|
||||
ciphers = tcpsock._sslObj.get_cipher_list()
|
||||
|
||||
print >> sys.stderr, "Ciphers:", ciphers
|
||||
print >> sys.stderr, "Peer cert:", peercert
|
||||
self._dumpX509(peercert)
|
||||
|
||||
print >> sys.stderr, OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, peercert)
|
||||
|
||||
def _startSSL_stdlib(self):
|
||||
log.debug("_startSSL_stdlib called")
|
||||
tcpsock=self._owner.Connection
|
||||
|
@ -795,37 +785,17 @@ class NonBlockingTLS(PlugIn):
|
|||
tcpsock._send = wrapper.send
|
||||
self.starttls='success'
|
||||
|
||||
def _ssl_info_callback(self, sslconn, type, st):
|
||||
def _ssl_verify_callback(self, sslconn, cert, errnum, depth, ok):
|
||||
# Exceptions can't propagate up through this callback, so print them here.
|
||||
try:
|
||||
self._ssl_info_callback_guarded(sslconn, type, st)
|
||||
if errnum == 0:
|
||||
return True
|
||||
self._owner.Connection.ssl_errnum = errnum
|
||||
return True
|
||||
except:
|
||||
log.error("Exception caught in _ssl_info_callback:", exc_info=True)
|
||||
traceback.print_exc() # Make sure something is printed, even if log is disabled.
|
||||
|
||||
def _ssl_info_callback_guarded(self, sslconn, type, st):
|
||||
b = self.ssl_h_bits
|
||||
|
||||
#if type & b['SSL_CB_LOOP']:
|
||||
# if type & SSL_ST_CONNECT: tls_state = "connect"
|
||||
# elif type & SSL_ST_ACCEPT: tls_state = "accept"
|
||||
# else: tls_state = "undefined"
|
||||
# print "tls_state: %s: %s" % (tls_state, sslconn.state_string())
|
||||
|
||||
#if type & b['SSL_CB_ALERT']:
|
||||
# if type & SSL_CB_READ: rdwr = "read"
|
||||
# elif type & SSL_CB_WRITE: rdwr = "write"
|
||||
# else: rdwr = "unknown"
|
||||
# print "tls_alert: %s:%d: %s" % (rdwr, st, sslconn.state_string())
|
||||
|
||||
#mask = ""
|
||||
#for k, v in b.iteritems():
|
||||
# if type & v: mask += " " + k
|
||||
#print "mask:", mask, st
|
||||
|
||||
if type & b['SSL_CB_HANDSHAKE_DONE']:
|
||||
self._on_ssl_handshake_done()
|
||||
|
||||
def StartTLSHandler(self, conn, starttls):
|
||||
''' Handle server reply if TLS is allowed to process. Behaves accordingly.
|
||||
Used internally.'''
|
||||
|
|
|
@ -121,6 +121,7 @@ class P2PClient(IdleObject):
|
|||
self.sock_type = TYPE_SERVER
|
||||
else:
|
||||
self.sock_type = TYPE_CLIENT
|
||||
self.fd = -1
|
||||
conn = P2PConnection('', _sock, host, port, self._caller, self.on_connect, self)
|
||||
self.sock_hash = conn._sock.__hash__
|
||||
self.fd = conn.fd
|
||||
|
@ -129,10 +130,14 @@ class P2PClient(IdleObject):
|
|||
for val in self.stanzaqueue:
|
||||
stanza, is_message = val
|
||||
if is_message:
|
||||
if self.conn_holder.number_of_awaiting_messages.has_key(self.fd):
|
||||
self.conn_holder.number_of_awaiting_messages[self.fd]+=1
|
||||
if self.fd == -1:
|
||||
self._caller.dispatch('MSGERROR',[unicode(self.to), -1, \
|
||||
_('Connection to host could not be established'), None, None])
|
||||
else:
|
||||
self.conn_holder.number_of_awaiting_messages[self.fd]=1
|
||||
if self.conn_holder.number_of_awaiting_messages.has_key(self.fd):
|
||||
self.conn_holder.number_of_awaiting_messages[self.fd]+=1
|
||||
else:
|
||||
self.conn_holder.number_of_awaiting_messages[self.fd]=1
|
||||
|
||||
def add_stanza(self, stanza, is_message = False):
|
||||
if self.Connection:
|
||||
|
@ -207,11 +212,11 @@ class P2PClient(IdleObject):
|
|||
|
||||
def on_disconnect(self):
|
||||
if self.conn_holder:
|
||||
if self.conn_holder.number_of_awaiting_messages.has_key(self.fd):
|
||||
if self.conn_holder.number_of_awaiting_messages[self.fd] > 0:
|
||||
if self.conn_holder.number_of_awaiting_messages.has_key(self.conn_holder.fd):
|
||||
if self.conn_holder.number_of_awaiting_messages[self.conn_holder.fd] > 0:
|
||||
self._caller.dispatch('MSGERROR',[unicode(self.to), -1, \
|
||||
_('Connection to host could not be established'), None, None])
|
||||
del self.conn_holder.number_of_awaiting_messages[self.fd]
|
||||
del self.conn_holder.number_of_awaiting_messages[self.conn_holder.fd]
|
||||
self.conn_holder.remove_connection(self.sock_hash)
|
||||
if self.__dict__.has_key('Dispatcher'):
|
||||
self.Dispatcher.PlugOut()
|
||||
|
@ -518,13 +523,6 @@ class ClientZeroconf:
|
|||
self.listener = None
|
||||
self.number_of_awaiting_messages = {}
|
||||
|
||||
def test_avahi(self):
|
||||
try:
|
||||
import avahi
|
||||
except ImportError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def connect(self, show, msg):
|
||||
self.port = self.start_listener(self.caller.port)
|
||||
if not self.port:
|
||||
|
|
|
@ -640,7 +640,7 @@ class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream):
|
|||
mtype = msg.getType()
|
||||
subject = msg.getSubject() # if not there, it's None
|
||||
tim = msg.getTimestamp()
|
||||
tim = time.strptime(tim, '%Y%m%dT%H:%M:%S')
|
||||
tim = helpers.datetime_tuple(tim)
|
||||
tim = time.localtime(timegm(tim))
|
||||
frm = msg.getFrom()
|
||||
if frm == None:
|
||||
|
@ -663,23 +663,23 @@ class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream):
|
|||
invite = None
|
||||
delayed = msg.getTag('x', namespace = common.xmpp.NS_DELAY) != None
|
||||
msg_id = None
|
||||
composing_jep = None
|
||||
composing_xep = None
|
||||
xtags = msg.getTags('x')
|
||||
# chatstates - look for chatstate tags in a message if not delayed
|
||||
if not delayed:
|
||||
composing_jep = False
|
||||
composing_xep = False
|
||||
children = msg.getChildren()
|
||||
for child in children:
|
||||
if child.getNamespace() == 'http://jabber.org/protocol/chatstates':
|
||||
chatstate = child.getName()
|
||||
composing_jep = 'JEP-0085'
|
||||
composing_xep = 'XEP-0085'
|
||||
break
|
||||
# No JEP-0085 support, fallback to JEP-0022
|
||||
if not chatstate:
|
||||
chatstate_child = msg.getTag('x', namespace = common.xmpp.NS_EVENT)
|
||||
if chatstate_child:
|
||||
chatstate = 'active'
|
||||
composing_jep = 'JEP-0022'
|
||||
composing_xep = 'XEP-0022'
|
||||
if not msgtxt and chatstate_child.getTag('composing'):
|
||||
chatstate = 'composing'
|
||||
# JEP-0172 User Nickname
|
||||
|
@ -715,14 +715,14 @@ class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream):
|
|||
msg_id = gajim.logger.write('chat_msg_recv', frm, msgtxt, tim = tim,
|
||||
subject = subject)
|
||||
self.dispatch('MSG', (frm, msgtxt, tim, encrypted, mtype, subject,
|
||||
chatstate, msg_id, composing_jep, user_nick, msghtml))
|
||||
chatstate, msg_id, composing_xep, user_nick, msghtml))
|
||||
elif mtype == 'normal': # it's single message
|
||||
if self.name not in no_log_for and jid not in no_log_for and msgtxt:
|
||||
gajim.logger.write('single_msg_recv', frm, msgtxt, tim = tim,
|
||||
subject = subject)
|
||||
if invite:
|
||||
self.dispatch('MSG', (frm, msgtxt, tim, encrypted, 'normal',
|
||||
subject, chatstate, msg_id, composing_jep, user_nick))
|
||||
subject, chatstate, msg_id, composing_xep, user_nick))
|
||||
# END messageCB
|
||||
|
||||
def parse_data_form(self, node):
|
||||
|
|
|
@ -41,6 +41,7 @@ import gobject
|
|||
from common import gajim
|
||||
from common import GnuPG
|
||||
from common.zeroconf import client_zeroconf
|
||||
from common.zeroconf import zeroconf
|
||||
from connection_handlers_zeroconf import *
|
||||
|
||||
USE_GPG = GnuPG.USE_GPG
|
||||
|
@ -103,12 +104,11 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
|
|||
gajim.config.set_per('accounts', gajim.ZEROCONF_ACC_NAME, 'password', 'zeroconf')
|
||||
gajim.config.set_per('accounts', gajim.ZEROCONF_ACC_NAME, 'sync_with_global_status', True)
|
||||
|
||||
#XXX make sure host is US-ASCII
|
||||
self.host = unicode(socket.gethostname())
|
||||
gajim.config.set_per('accounts', gajim.ZEROCONF_ACC_NAME, 'hostname', self.host)
|
||||
gajim.config.set_per('accounts', gajim.ZEROCONF_ACC_NAME, 'custom_port', 5298)
|
||||
gajim.config.set_per('accounts', gajim.ZEROCONF_ACC_NAME, 'is_zeroconf', True)
|
||||
self.host = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'hostname')
|
||||
#XXX make sure host is US-ASCII
|
||||
self.host = unicode(socket.gethostname())
|
||||
gajim.config.set_per('accounts', gajim.ZEROCONF_ACC_NAME, 'hostname', self.host)
|
||||
self.port = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'custom_port')
|
||||
self.autoconnect = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'autoconnect')
|
||||
self.sync_with_global_status = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'sync_with_global_status')
|
||||
|
@ -229,7 +229,7 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
|
|||
self.get_config_values_or_default()
|
||||
if not self.connection:
|
||||
self.connection = client_zeroconf.ClientZeroconf(self)
|
||||
if not self.connection.test_avahi():
|
||||
if not zeroconf.test_zeroconf():
|
||||
self.dispatch('STATUS', 'offline')
|
||||
self.status = 'offline'
|
||||
self.dispatch('CONNECTION_LOST',
|
||||
|
@ -348,7 +348,7 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
|
|||
return STATUS_LIST[self.connected]
|
||||
|
||||
def send_message(self, jid, msg, keyID, type = 'chat', subject='',
|
||||
chatstate = None, msg_id = None, composing_jep = None, resource = None,
|
||||
chatstate = None, msg_id = None, composing_xep = None, resource = None,
|
||||
user_nick = None):
|
||||
fjid = jid
|
||||
|
||||
|
@ -396,10 +396,10 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
|
|||
# please note that the only valid tag inside a message containing a <body>
|
||||
# tag is the active event
|
||||
if chatstate is not None:
|
||||
if composing_jep == 'JEP-0085' or not composing_jep:
|
||||
if composing_xep == 'XEP-0085' or not composing_xep:
|
||||
# JEP-0085
|
||||
msg_iq.setTag(chatstate, namespace = common.xmpp.NS_CHATSTATES)
|
||||
if composing_jep == 'JEP-0022' or not composing_jep:
|
||||
if composing_xep == 'XEP-0022' or not composing_xep:
|
||||
# JEP-0022
|
||||
chatstate_node = msg_iq.setTag('x', namespace = common.xmpp.NS_EVENT)
|
||||
if not msgtxt: # when no <body>, add <id>
|
||||
|
|
|
@ -12,404 +12,29 @@
|
|||
## GNU General Public License for more details.
|
||||
##
|
||||
|
||||
from common import gajim
|
||||
|
||||
try:
|
||||
import dbus.glib
|
||||
except ImportError, e:
|
||||
pass
|
||||
|
||||
|
||||
C_NAME, C_DOMAIN, C_INTERFACE, C_PROTOCOL, C_HOST, \
|
||||
C_ADDRESS, C_PORT, C_BARE_NAME, C_TXT = range(9)
|
||||
|
||||
class Zeroconf:
|
||||
def __init__(self, new_serviceCB, remove_serviceCB, name_conflictCB,
|
||||
disconnected_CB, error_CB, name, host, port):
|
||||
self.avahi = None
|
||||
self.domain = None # specific domain to browse
|
||||
self.stype = '_presence._tcp'
|
||||
self.port = port # listening port that gets announced
|
||||
self.username = name
|
||||
self.host = host
|
||||
self.txt = {} # service data
|
||||
|
||||
#XXX these CBs should be set to None when we destroy the object
|
||||
# (go offline), because they create a circular reference
|
||||
self.new_serviceCB = new_serviceCB
|
||||
self.remove_serviceCB = remove_serviceCB
|
||||
self.name_conflictCB = name_conflictCB
|
||||
self.disconnected_CB = disconnected_CB
|
||||
self.error_CB = error_CB
|
||||
|
||||
self.service_browser = None
|
||||
self.domain_browser = None
|
||||
self.bus = None
|
||||
self.server = None
|
||||
self.contacts = {} # all current local contacts with data
|
||||
self.entrygroup = None
|
||||
self.connected = False
|
||||
self.announced = False
|
||||
self.invalid_self_contact = {}
|
||||
def test_avahi():
|
||||
try:
|
||||
import avahi
|
||||
except ImportError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def test_bonjour():
|
||||
try:
|
||||
import pybonjour
|
||||
except ImportError:
|
||||
return False
|
||||
return True
|
||||
|
||||
## handlers for dbus callbacks
|
||||
def entrygroup_commit_error_CB(self, err):
|
||||
# left blank for possible later usage
|
||||
pass
|
||||
|
||||
def error_callback1(self, err):
|
||||
gajim.log.debug('Error while resolving: ' + str(err))
|
||||
|
||||
def error_callback(self, err):
|
||||
gajim.log.debug(str(err))
|
||||
# timeouts are non-critical
|
||||
if str(err) != 'Timeout reached':
|
||||
self.disconnect()
|
||||
self.disconnected_CB()
|
||||
def test_zeroconf():
|
||||
return test_avahi() or test_bonjour()
|
||||
|
||||
def new_service_callback(self, interface, protocol, name, stype, domain, flags):
|
||||
gajim.log.debug('Found service %s in domain %s on %i.%i.' % (name, domain, interface, protocol))
|
||||
if not self.connected:
|
||||
return
|
||||
|
||||
# synchronous resolving
|
||||
self.server.ResolveService( int(interface), int(protocol), name, stype, \
|
||||
domain, self.avahi.PROTO_UNSPEC, dbus.UInt32(0), \
|
||||
reply_handler=self.service_resolved_callback, error_handler=self.error_callback1)
|
||||
|
||||
def remove_service_callback(self, interface, protocol, name, stype, domain, flags):
|
||||
gajim.log.debug('Service %s in domain %s on %i.%i disappeared.' % (name, domain, interface, protocol))
|
||||
if not self.connected:
|
||||
return
|
||||
if name != self.name:
|
||||
for key in self.contacts.keys():
|
||||
if self.contacts[key][C_BARE_NAME] == name:
|
||||
del self.contacts[key]
|
||||
self.remove_serviceCB(key)
|
||||
return
|
||||
|
||||
def new_service_type(self, interface, protocol, stype, domain, flags):
|
||||
# Are we already browsing this domain for this type?
|
||||
if self.service_browser:
|
||||
return
|
||||
|
||||
object_path = self.server.ServiceBrowserNew(interface, protocol, \
|
||||
stype, domain, dbus.UInt32(0))
|
||||
|
||||
self.service_browser = dbus.Interface(self.bus.get_object(self.avahi.DBUS_NAME, \
|
||||
object_path) , self.avahi.DBUS_INTERFACE_SERVICE_BROWSER)
|
||||
self.service_browser.connect_to_signal('ItemNew', self.new_service_callback)
|
||||
self.service_browser.connect_to_signal('ItemRemove', self.remove_service_callback)
|
||||
self.service_browser.connect_to_signal('Failure', self.error_callback)
|
||||
|
||||
def new_domain_callback(self,interface, protocol, domain, flags):
|
||||
if domain != "local":
|
||||
self.browse_domain(interface, protocol, domain)
|
||||
|
||||
def txt_array_to_dict(self, txt_array):
|
||||
txt_dict = {}
|
||||
for els in txt_array:
|
||||
key, val = '', None
|
||||
for c in els:
|
||||
#FIXME: remove when outdated, this is for avahi < 0.6.14
|
||||
if c < 0 or c > 255:
|
||||
c = '.'
|
||||
else:
|
||||
c = chr(c)
|
||||
if val is None:
|
||||
if c == '=':
|
||||
val = ''
|
||||
else:
|
||||
key += c
|
||||
else:
|
||||
val += c
|
||||
if val is None: # missing '='
|
||||
val = ''
|
||||
txt_dict[key] = val.decode('utf-8')
|
||||
return txt_dict
|
||||
|
||||
def service_resolved_callback(self, interface, protocol, name, stype, domain, host, aprotocol, address, port, txt, flags):
|
||||
gajim.log.debug('Service data for service %s in domain %s on %i.%i:'
|
||||
% (name, domain, interface, protocol))
|
||||
gajim.log.debug('Host %s (%s), port %i, TXT data: %s' % (host, address, port,
|
||||
self.txt_array_to_dict(txt)))
|
||||
if not self.connected:
|
||||
return
|
||||
bare_name = name
|
||||
if name.find('@') == -1:
|
||||
name = name + '@' + name
|
||||
|
||||
# we don't want to see ourselves in the list
|
||||
if name != self.name:
|
||||
self.contacts[name] = (name, domain, interface, protocol, host, address, port,
|
||||
bare_name, txt)
|
||||
self.new_serviceCB(name)
|
||||
else:
|
||||
# remember data
|
||||
# In case this is not our own record but of another
|
||||
# gajim instance on the same machine,
|
||||
# it will be used when we get a new name.
|
||||
self.invalid_self_contact[name] = (name, domain, interface, protocol, host, address, port, bare_name, txt)
|
||||
|
||||
|
||||
# different handler when resolving all contacts
|
||||
def service_resolved_all_callback(self, interface, protocol, name, stype, domain, host, aprotocol, address, port, txt, flags):
|
||||
if not self.connected:
|
||||
return
|
||||
bare_name = name
|
||||
if name.find('@') == -1:
|
||||
name = name + '@' + name
|
||||
self.contacts[name] = (name, domain, interface, protocol, host, address, port, bare_name, txt)
|
||||
|
||||
def service_added_callback(self):
|
||||
gajim.log.debug('Service successfully added')
|
||||
|
||||
def service_committed_callback(self):
|
||||
gajim.log.debug('Service successfully committed')
|
||||
|
||||
def service_updated_callback(self):
|
||||
gajim.log.debug('Service successfully updated')
|
||||
|
||||
def service_add_fail_callback(self, err):
|
||||
gajim.log.debug('Error while adding service. %s' % str(err))
|
||||
if str(err) == 'Local name collision':
|
||||
alternative_name = self.server.GetAlternativeServiceName(self.username)
|
||||
self.name_conflictCB(alternative_name)
|
||||
return
|
||||
self.error_CB(_('Error while adding service. %s') % str(err))
|
||||
self.disconnect()
|
||||
|
||||
def server_state_changed_callback(self, state, error):
|
||||
if state == self.avahi.SERVER_RUNNING:
|
||||
self.create_service()
|
||||
elif state == self.avahi.SERVER_COLLISION:
|
||||
self.entrygroup.Reset()
|
||||
elif state == self.avahi.CLIENT_FAILURE:
|
||||
# does it ever go here?
|
||||
gajim.log.debug('CLIENT FAILURE')
|
||||
|
||||
def entrygroup_state_changed_callback(self, state, error):
|
||||
# the name is already present, so recreate
|
||||
if state == self.avahi.ENTRY_GROUP_COLLISION:
|
||||
self.service_add_fail_callback('Local name collision')
|
||||
elif state == self.avahi.ENTRY_GROUP_FAILURE:
|
||||
gajim.log.debug('zeroconf.py: ENTRY_GROUP_FAILURE reached(that'
|
||||
' should not happen)')
|
||||
|
||||
# make zeroconf-valid names
|
||||
def replace_show(self, show):
|
||||
if show in ['chat', 'online', '']:
|
||||
return 'avail'
|
||||
elif show == 'xa':
|
||||
return 'away'
|
||||
return show
|
||||
|
||||
def avahi_txt(self):
|
||||
utf8_dict = {}
|
||||
for key in self.txt:
|
||||
val = self.txt[key]
|
||||
if isinstance(val, unicode):
|
||||
utf8_dict[key] = val.encode('utf-8')
|
||||
else:
|
||||
utf8_dict[key] = val
|
||||
return self.avahi.dict_to_txt_array(utf8_dict)
|
||||
|
||||
def create_service(self):
|
||||
try:
|
||||
if not self.entrygroup:
|
||||
# create an EntryGroup for publishing
|
||||
self.entrygroup = dbus.Interface(self.bus.get_object(self.avahi.DBUS_NAME, self.server.EntryGroupNew()), self.avahi.DBUS_INTERFACE_ENTRY_GROUP)
|
||||
self.entrygroup.connect_to_signal('StateChanged', self.entrygroup_state_changed_callback)
|
||||
|
||||
txt = {}
|
||||
|
||||
#remove empty keys
|
||||
for key,val in self.txt.iteritems():
|
||||
if val:
|
||||
txt[key] = val
|
||||
|
||||
txt['port.p2pj'] = self.port
|
||||
txt['version'] = 1
|
||||
txt['txtvers'] = 1
|
||||
|
||||
# replace gajim's show messages with compatible ones
|
||||
if self.txt.has_key('status'):
|
||||
txt['status'] = self.replace_show(self.txt['status'])
|
||||
else:
|
||||
txt['status'] = 'avail'
|
||||
|
||||
self.txt = txt
|
||||
gajim.log.debug('Publishing service %s of type %s' % (self.name, self.stype))
|
||||
self.entrygroup.AddService(self.avahi.IF_UNSPEC, self.avahi.PROTO_UNSPEC, dbus.UInt32(0), self.name, self.stype, '', '', self.port, self.avahi_txt(), reply_handler=self.service_added_callback, error_handler=self.service_add_fail_callback)
|
||||
|
||||
self.entrygroup.Commit(reply_handler=self.service_committed_callback,
|
||||
error_handler=self.entrygroup_commit_error_CB)
|
||||
|
||||
return True
|
||||
|
||||
except dbus.DBusException, e:
|
||||
gajim.log.debug(str(e))
|
||||
return False
|
||||
|
||||
def announce(self):
|
||||
if not self.connected:
|
||||
return False
|
||||
|
||||
state = self.server.GetState()
|
||||
if state == self.avahi.SERVER_RUNNING:
|
||||
self.create_service()
|
||||
self.announced = True
|
||||
return True
|
||||
|
||||
def remove_announce(self):
|
||||
if self.announced == False:
|
||||
return False
|
||||
try:
|
||||
if self.entrygroup.GetState() != self.avahi.ENTRY_GROUP_FAILURE:
|
||||
self.entrygroup.Reset()
|
||||
self.entrygroup.Free()
|
||||
# .Free() has mem leaks
|
||||
obj = self.entrygroup._obj
|
||||
obj._bus = None
|
||||
self.entrygroup._obj = None
|
||||
self.entrygroup = None
|
||||
self.announced = False
|
||||
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except dbus.DBusException, e:
|
||||
gajim.log.debug("Can't remove service. That should not happen")
|
||||
|
||||
def browse_domain(self, interface, protocol, domain):
|
||||
self.new_service_type(interface, protocol, self.stype, domain, '')
|
||||
|
||||
def avahi_dbus_connect_cb(self, a, connect, disconnect):
|
||||
if connect != "":
|
||||
gajim.log.debug('Lost connection to avahi-daemon')
|
||||
self.disconnect()
|
||||
if self.disconnected_CB:
|
||||
self.disconnected_CB()
|
||||
else:
|
||||
gajim.log.debug('We are connected to avahi-daemon')
|
||||
|
||||
# connect to dbus
|
||||
def connect_dbus(self):
|
||||
try:
|
||||
import dbus
|
||||
except ImportError:
|
||||
gajim.log.debug('Error: python-dbus needs to be installed. No zeroconf support.')
|
||||
return False
|
||||
if self.bus:
|
||||
return True
|
||||
try:
|
||||
self.bus = dbus.SystemBus()
|
||||
self.bus.add_signal_receiver(self.avahi_dbus_connect_cb,
|
||||
"NameOwnerChanged", "org.freedesktop.DBus",
|
||||
arg0="org.freedesktop.Avahi")
|
||||
except Exception, e:
|
||||
# System bus is not present
|
||||
self.bus = None
|
||||
gajim.log.debug(str(e))
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
# connect to avahi
|
||||
def connect_avahi(self):
|
||||
if not self.connect_dbus():
|
||||
return False
|
||||
try:
|
||||
import avahi
|
||||
self.avahi = avahi
|
||||
except ImportError:
|
||||
gajim.log.debug('Error: python-avahi needs to be installed. No zeroconf support.')
|
||||
return False
|
||||
|
||||
if self.server:
|
||||
return True
|
||||
try:
|
||||
self.server = dbus.Interface(self.bus.get_object(self.avahi.DBUS_NAME, \
|
||||
self.avahi.DBUS_PATH_SERVER), self.avahi.DBUS_INTERFACE_SERVER)
|
||||
self.server.connect_to_signal('StateChanged',
|
||||
self.server_state_changed_callback)
|
||||
except Exception, e:
|
||||
# Avahi service is not present
|
||||
self.server = None
|
||||
gajim.log.debug(str(e))
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def connect(self):
|
||||
self.name = self.username + '@' + self.host # service name
|
||||
if not self.connect_avahi():
|
||||
return False
|
||||
|
||||
self.connected = True
|
||||
# start browsing
|
||||
if self.domain is None:
|
||||
# Explicitly browse .local
|
||||
self.browse_domain(self.avahi.IF_UNSPEC, self.avahi.PROTO_UNSPEC, "local")
|
||||
|
||||
# Browse for other browsable domains
|
||||
self.domain_browser = dbus.Interface(self.bus.get_object(self.avahi.DBUS_NAME, \
|
||||
self.server.DomainBrowserNew(self.avahi.IF_UNSPEC, \
|
||||
self.avahi.PROTO_UNSPEC, '', self.avahi.DOMAIN_BROWSER_BROWSE,\
|
||||
dbus.UInt32(0))), self.avahi.DBUS_INTERFACE_DOMAIN_BROWSER)
|
||||
self.domain_browser.connect_to_signal('ItemNew', self.new_domain_callback)
|
||||
self.domain_browser.connect_to_signal('Failure', self.error_callback)
|
||||
else:
|
||||
self.browse_domain(self.avahi.IF_UNSPEC, self.avahi.PROTO_UNSPEC, self.domain)
|
||||
|
||||
return True
|
||||
|
||||
def disconnect(self):
|
||||
if self.connected:
|
||||
self.connected = False
|
||||
if self.service_browser:
|
||||
self.service_browser.Free()
|
||||
self.service_browser._obj._bus = None
|
||||
self.service_browser._obj = None
|
||||
if self.domain_browser:
|
||||
self.domain_browser.Free()
|
||||
self.domain_browser._obj._bus = None
|
||||
self.domain_browser._obj = None
|
||||
self.remove_announce()
|
||||
self.server._obj._bus = None
|
||||
self.server._obj = None
|
||||
self.server = None
|
||||
self.service_browser = None
|
||||
self.domain_browser = None
|
||||
|
||||
# refresh txt data of all contacts manually (no callback available)
|
||||
def resolve_all(self):
|
||||
if not self.connected:
|
||||
return
|
||||
for val in self.contacts.values():
|
||||
self.server.ResolveService(int(val[C_INTERFACE]), int(val[C_PROTOCOL]), val[C_BARE_NAME], \
|
||||
self.stype, val[C_DOMAIN], self.avahi.PROTO_UNSPEC, dbus.UInt32(0),\
|
||||
reply_handler=self.service_resolved_all_callback, error_handler=self.error_callback)
|
||||
|
||||
def get_contacts(self):
|
||||
return self.contacts
|
||||
|
||||
def get_contact(self, jid):
|
||||
if not jid in self.contacts:
|
||||
return None
|
||||
return self.contacts[jid]
|
||||
|
||||
def update_txt(self, show = None):
|
||||
if show:
|
||||
self.txt['status'] = self.replace_show(show)
|
||||
|
||||
txt = self.avahi_txt()
|
||||
if self.connected and self.entrygroup:
|
||||
self.entrygroup.UpdateServiceTxt(self.avahi.IF_UNSPEC, self.avahi.PROTO_UNSPEC, dbus.UInt32(0), self.name, self.stype,'', txt, reply_handler=self.service_updated_callback, error_handler=self.error_callback)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
# END Zeroconf
|
||||
if test_avahi():
|
||||
from common.zeroconf import zeroconf_avahi
|
||||
Zeroconf = zeroconf_avahi.Zeroconf
|
||||
elif test_bonjour():
|
||||
from common.zeroconf import zeroconf_bonjour
|
||||
Zeroconf = zeroconf_bonjour.Zeroconf
|
||||
|
|
|
@ -0,0 +1,415 @@
|
|||
## common/zeroconf/zeroconf.py
|
||||
##
|
||||
## Copyright (C) 2006 Stefan Bethge <stefan@lanpartei.de>
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
|
||||
from common import gajim
|
||||
|
||||
try:
|
||||
import dbus.glib
|
||||
except ImportError, e:
|
||||
pass
|
||||
|
||||
from common.zeroconf.zeroconf import C_BARE_NAME, C_INTERFACE, C_PROTOCOL, C_DOMAIN
|
||||
|
||||
class Zeroconf:
|
||||
def __init__(self, new_serviceCB, remove_serviceCB, name_conflictCB,
|
||||
disconnected_CB, error_CB, name, host, port):
|
||||
self.avahi = None
|
||||
self.domain = None # specific domain to browse
|
||||
self.stype = '_presence._tcp'
|
||||
self.port = port # listening port that gets announced
|
||||
self.username = name
|
||||
self.host = host
|
||||
self.txt = {} # service data
|
||||
|
||||
#XXX these CBs should be set to None when we destroy the object
|
||||
# (go offline), because they create a circular reference
|
||||
self.new_serviceCB = new_serviceCB
|
||||
self.remove_serviceCB = remove_serviceCB
|
||||
self.name_conflictCB = name_conflictCB
|
||||
self.disconnected_CB = disconnected_CB
|
||||
self.error_CB = error_CB
|
||||
|
||||
self.service_browser = None
|
||||
self.domain_browser = None
|
||||
self.bus = None
|
||||
self.server = None
|
||||
self.contacts = {} # all current local contacts with data
|
||||
self.entrygroup = None
|
||||
self.connected = False
|
||||
self.announced = False
|
||||
self.invalid_self_contact = {}
|
||||
|
||||
|
||||
## handlers for dbus callbacks
|
||||
def entrygroup_commit_error_CB(self, err):
|
||||
# left blank for possible later usage
|
||||
pass
|
||||
|
||||
def error_callback1(self, err):
|
||||
gajim.log.debug('Error while resolving: ' + str(err))
|
||||
|
||||
def error_callback(self, err):
|
||||
gajim.log.debug(str(err))
|
||||
# timeouts are non-critical
|
||||
if str(err) != 'Timeout reached':
|
||||
self.disconnect()
|
||||
self.disconnected_CB()
|
||||
|
||||
def new_service_callback(self, interface, protocol, name, stype, domain, flags):
|
||||
gajim.log.debug('Found service %s in domain %s on %i.%i.' % (name, domain, interface, protocol))
|
||||
if not self.connected:
|
||||
return
|
||||
|
||||
# synchronous resolving
|
||||
self.server.ResolveService( int(interface), int(protocol), name, stype, \
|
||||
domain, self.avahi.PROTO_UNSPEC, dbus.UInt32(0), \
|
||||
reply_handler=self.service_resolved_callback, error_handler=self.error_callback1)
|
||||
|
||||
def remove_service_callback(self, interface, protocol, name, stype, domain, flags):
|
||||
gajim.log.debug('Service %s in domain %s on %i.%i disappeared.' % (name, domain, interface, protocol))
|
||||
if not self.connected:
|
||||
return
|
||||
if name != self.name:
|
||||
for key in self.contacts.keys():
|
||||
if self.contacts[key][C_BARE_NAME] == name:
|
||||
del self.contacts[key]
|
||||
self.remove_serviceCB(key)
|
||||
return
|
||||
|
||||
def new_service_type(self, interface, protocol, stype, domain, flags):
|
||||
# Are we already browsing this domain for this type?
|
||||
if self.service_browser:
|
||||
return
|
||||
|
||||
object_path = self.server.ServiceBrowserNew(interface, protocol, \
|
||||
stype, domain, dbus.UInt32(0))
|
||||
|
||||
self.service_browser = dbus.Interface(self.bus.get_object(self.avahi.DBUS_NAME, \
|
||||
object_path) , self.avahi.DBUS_INTERFACE_SERVICE_BROWSER)
|
||||
self.service_browser.connect_to_signal('ItemNew', self.new_service_callback)
|
||||
self.service_browser.connect_to_signal('ItemRemove', self.remove_service_callback)
|
||||
self.service_browser.connect_to_signal('Failure', self.error_callback)
|
||||
|
||||
def new_domain_callback(self,interface, protocol, domain, flags):
|
||||
if domain != "local":
|
||||
self.browse_domain(interface, protocol, domain)
|
||||
|
||||
def txt_array_to_dict(self, txt_array):
|
||||
txt_dict = {}
|
||||
for els in txt_array:
|
||||
key, val = '', None
|
||||
for c in els:
|
||||
#FIXME: remove when outdated, this is for avahi < 0.6.14
|
||||
if c < 0 or c > 255:
|
||||
c = '.'
|
||||
else:
|
||||
c = chr(c)
|
||||
if val is None:
|
||||
if c == '=':
|
||||
val = ''
|
||||
else:
|
||||
key += c
|
||||
else:
|
||||
val += c
|
||||
if val is None: # missing '='
|
||||
val = ''
|
||||
txt_dict[key] = val.decode('utf-8')
|
||||
return txt_dict
|
||||
|
||||
def service_resolved_callback(self, interface, protocol, name, stype, domain, host, aprotocol, address, port, txt, flags):
|
||||
gajim.log.debug('Service data for service %s in domain %s on %i.%i:'
|
||||
% (name, domain, interface, protocol))
|
||||
gajim.log.debug('Host %s (%s), port %i, TXT data: %s' % (host, address, port,
|
||||
self.txt_array_to_dict(txt)))
|
||||
if not self.connected:
|
||||
return
|
||||
bare_name = name
|
||||
if name.find('@') == -1:
|
||||
name = name + '@' + name
|
||||
|
||||
# we don't want to see ourselves in the list
|
||||
if name != self.name:
|
||||
self.contacts[name] = (name, domain, interface, protocol, host, address, port,
|
||||
bare_name, txt)
|
||||
self.new_serviceCB(name)
|
||||
else:
|
||||
# remember data
|
||||
# In case this is not our own record but of another
|
||||
# gajim instance on the same machine,
|
||||
# it will be used when we get a new name.
|
||||
self.invalid_self_contact[name] = (name, domain, interface, protocol, host, address, port, bare_name, txt)
|
||||
|
||||
|
||||
# different handler when resolving all contacts
|
||||
def service_resolved_all_callback(self, interface, protocol, name, stype, domain, host, aprotocol, address, port, txt, flags):
|
||||
if not self.connected:
|
||||
return
|
||||
bare_name = name
|
||||
if name.find('@') == -1:
|
||||
name = name + '@' + name
|
||||
self.contacts[name] = (name, domain, interface, protocol, host, address, port, bare_name, txt)
|
||||
|
||||
def service_added_callback(self):
|
||||
gajim.log.debug('Service successfully added')
|
||||
|
||||
def service_committed_callback(self):
|
||||
gajim.log.debug('Service successfully committed')
|
||||
|
||||
def service_updated_callback(self):
|
||||
gajim.log.debug('Service successfully updated')
|
||||
|
||||
def service_add_fail_callback(self, err):
|
||||
gajim.log.debug('Error while adding service. %s' % str(err))
|
||||
if str(err) == 'Local name collision':
|
||||
alternative_name = self.server.GetAlternativeServiceName(self.username)
|
||||
self.name_conflictCB(alternative_name)
|
||||
return
|
||||
self.error_CB(_('Error while adding service. %s') % str(err))
|
||||
self.disconnect()
|
||||
|
||||
def server_state_changed_callback(self, state, error):
|
||||
if state == self.avahi.SERVER_RUNNING:
|
||||
self.create_service()
|
||||
elif state == self.avahi.SERVER_COLLISION:
|
||||
self.entrygroup.Reset()
|
||||
elif state == self.avahi.CLIENT_FAILURE:
|
||||
# does it ever go here?
|
||||
gajim.log.debug('CLIENT FAILURE')
|
||||
|
||||
def entrygroup_state_changed_callback(self, state, error):
|
||||
# the name is already present, so recreate
|
||||
if state == self.avahi.ENTRY_GROUP_COLLISION:
|
||||
self.service_add_fail_callback('Local name collision')
|
||||
elif state == self.avahi.ENTRY_GROUP_FAILURE:
|
||||
gajim.log.debug('zeroconf.py: ENTRY_GROUP_FAILURE reached(that'
|
||||
' should not happen)')
|
||||
|
||||
# make zeroconf-valid names
|
||||
def replace_show(self, show):
|
||||
if show in ['chat', 'online', '']:
|
||||
return 'avail'
|
||||
elif show == 'xa':
|
||||
return 'away'
|
||||
return show
|
||||
|
||||
def avahi_txt(self):
|
||||
utf8_dict = {}
|
||||
for key in self.txt:
|
||||
val = self.txt[key]
|
||||
if isinstance(val, unicode):
|
||||
utf8_dict[key] = val.encode('utf-8')
|
||||
else:
|
||||
utf8_dict[key] = val
|
||||
return self.avahi.dict_to_txt_array(utf8_dict)
|
||||
|
||||
def create_service(self):
|
||||
try:
|
||||
if not self.entrygroup:
|
||||
# create an EntryGroup for publishing
|
||||
self.entrygroup = dbus.Interface(self.bus.get_object(self.avahi.DBUS_NAME, self.server.EntryGroupNew()), self.avahi.DBUS_INTERFACE_ENTRY_GROUP)
|
||||
self.entrygroup.connect_to_signal('StateChanged', self.entrygroup_state_changed_callback)
|
||||
|
||||
txt = {}
|
||||
|
||||
#remove empty keys
|
||||
for key,val in self.txt.iteritems():
|
||||
if val:
|
||||
txt[key] = val
|
||||
|
||||
txt['port.p2pj'] = self.port
|
||||
txt['version'] = 1
|
||||
txt['txtvers'] = 1
|
||||
|
||||
# replace gajim's show messages with compatible ones
|
||||
if self.txt.has_key('status'):
|
||||
txt['status'] = self.replace_show(self.txt['status'])
|
||||
else:
|
||||
txt['status'] = 'avail'
|
||||
|
||||
self.txt = txt
|
||||
gajim.log.debug('Publishing service %s of type %s' % (self.name, self.stype))
|
||||
self.entrygroup.AddService(self.avahi.IF_UNSPEC, self.avahi.PROTO_UNSPEC, dbus.UInt32(0), self.name, self.stype, '', '', self.port, self.avahi_txt(), reply_handler=self.service_added_callback, error_handler=self.service_add_fail_callback)
|
||||
|
||||
self.entrygroup.Commit(reply_handler=self.service_committed_callback,
|
||||
error_handler=self.entrygroup_commit_error_CB)
|
||||
|
||||
return True
|
||||
|
||||
except dbus.DBusException, e:
|
||||
gajim.log.debug(str(e))
|
||||
return False
|
||||
|
||||
def announce(self):
|
||||
if not self.connected:
|
||||
return False
|
||||
|
||||
state = self.server.GetState()
|
||||
if state == self.avahi.SERVER_RUNNING:
|
||||
self.create_service()
|
||||
self.announced = True
|
||||
return True
|
||||
|
||||
def remove_announce(self):
|
||||
if self.announced == False:
|
||||
return False
|
||||
try:
|
||||
if self.entrygroup.GetState() != self.avahi.ENTRY_GROUP_FAILURE:
|
||||
self.entrygroup.Reset()
|
||||
self.entrygroup.Free()
|
||||
# .Free() has mem leaks
|
||||
obj = self.entrygroup._obj
|
||||
obj._bus = None
|
||||
self.entrygroup._obj = None
|
||||
self.entrygroup = None
|
||||
self.announced = False
|
||||
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except dbus.DBusException, e:
|
||||
gajim.log.debug("Can't remove service. That should not happen")
|
||||
|
||||
def browse_domain(self, interface, protocol, domain):
|
||||
self.new_service_type(interface, protocol, self.stype, domain, '')
|
||||
|
||||
def avahi_dbus_connect_cb(self, a, connect, disconnect):
|
||||
if connect != "":
|
||||
gajim.log.debug('Lost connection to avahi-daemon')
|
||||
self.disconnect()
|
||||
if self.disconnected_CB:
|
||||
self.disconnected_CB()
|
||||
else:
|
||||
gajim.log.debug('We are connected to avahi-daemon')
|
||||
|
||||
# connect to dbus
|
||||
def connect_dbus(self):
|
||||
try:
|
||||
import dbus
|
||||
except ImportError:
|
||||
gajim.log.debug('Error: python-dbus needs to be installed. No zeroconf support.')
|
||||
return False
|
||||
if self.bus:
|
||||
return True
|
||||
try:
|
||||
self.bus = dbus.SystemBus()
|
||||
self.bus.add_signal_receiver(self.avahi_dbus_connect_cb,
|
||||
"NameOwnerChanged", "org.freedesktop.DBus",
|
||||
arg0="org.freedesktop.Avahi")
|
||||
except Exception, e:
|
||||
# System bus is not present
|
||||
self.bus = None
|
||||
gajim.log.debug(str(e))
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
# connect to avahi
|
||||
def connect_avahi(self):
|
||||
if not self.connect_dbus():
|
||||
return False
|
||||
try:
|
||||
import avahi
|
||||
self.avahi = avahi
|
||||
except ImportError:
|
||||
gajim.log.debug('Error: python-avahi needs to be installed. No zeroconf support.')
|
||||
return False
|
||||
|
||||
if self.server:
|
||||
return True
|
||||
try:
|
||||
self.server = dbus.Interface(self.bus.get_object(self.avahi.DBUS_NAME, \
|
||||
self.avahi.DBUS_PATH_SERVER), self.avahi.DBUS_INTERFACE_SERVER)
|
||||
self.server.connect_to_signal('StateChanged',
|
||||
self.server_state_changed_callback)
|
||||
except Exception, e:
|
||||
# Avahi service is not present
|
||||
self.server = None
|
||||
gajim.log.debug(str(e))
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def connect(self):
|
||||
self.name = self.username + '@' + self.host # service name
|
||||
if not self.connect_avahi():
|
||||
return False
|
||||
|
||||
self.connected = True
|
||||
# start browsing
|
||||
if self.domain is None:
|
||||
# Explicitly browse .local
|
||||
self.browse_domain(self.avahi.IF_UNSPEC, self.avahi.PROTO_UNSPEC, "local")
|
||||
|
||||
# Browse for other browsable domains
|
||||
self.domain_browser = dbus.Interface(self.bus.get_object(self.avahi.DBUS_NAME, \
|
||||
self.server.DomainBrowserNew(self.avahi.IF_UNSPEC, \
|
||||
self.avahi.PROTO_UNSPEC, '', self.avahi.DOMAIN_BROWSER_BROWSE,\
|
||||
dbus.UInt32(0))), self.avahi.DBUS_INTERFACE_DOMAIN_BROWSER)
|
||||
self.domain_browser.connect_to_signal('ItemNew', self.new_domain_callback)
|
||||
self.domain_browser.connect_to_signal('Failure', self.error_callback)
|
||||
else:
|
||||
self.browse_domain(self.avahi.IF_UNSPEC, self.avahi.PROTO_UNSPEC, self.domain)
|
||||
|
||||
return True
|
||||
|
||||
def disconnect(self):
|
||||
if self.connected:
|
||||
self.connected = False
|
||||
if self.service_browser:
|
||||
self.service_browser.Free()
|
||||
self.service_browser._obj._bus = None
|
||||
self.service_browser._obj = None
|
||||
if self.domain_browser:
|
||||
self.domain_browser.Free()
|
||||
self.domain_browser._obj._bus = None
|
||||
self.domain_browser._obj = None
|
||||
self.remove_announce()
|
||||
self.server._obj._bus = None
|
||||
self.server._obj = None
|
||||
self.server = None
|
||||
self.service_browser = None
|
||||
self.domain_browser = None
|
||||
|
||||
# refresh txt data of all contacts manually (no callback available)
|
||||
def resolve_all(self):
|
||||
if not self.connected:
|
||||
return
|
||||
for val in self.contacts.values():
|
||||
self.server.ResolveService(int(val[C_INTERFACE]), int(val[C_PROTOCOL]),
|
||||
val[C_BARE_NAME], self.stype, val[C_DOMAIN],
|
||||
self.avahi.PROTO_UNSPEC, dbus.UInt32(0),
|
||||
reply_handler=self.service_resolved_all_callback,
|
||||
error_handler=self.error_callback)
|
||||
|
||||
def get_contacts(self):
|
||||
return self.contacts
|
||||
|
||||
def get_contact(self, jid):
|
||||
if not jid in self.contacts:
|
||||
return None
|
||||
return self.contacts[jid]
|
||||
|
||||
def update_txt(self, show = None):
|
||||
if show:
|
||||
self.txt['status'] = self.replace_show(show)
|
||||
|
||||
txt = self.avahi_txt()
|
||||
if self.connected and self.entrygroup:
|
||||
self.entrygroup.UpdateServiceTxt(self.avahi.IF_UNSPEC, self.avahi.PROTO_UNSPEC, dbus.UInt32(0), self.name, self.stype,'', txt, reply_handler=self.service_updated_callback, error_handler=self.error_callback)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
# END Zeroconf
|
|
@ -0,0 +1,329 @@
|
|||
## common/zeroconf/zeroconf_bonjour.py
|
||||
##
|
||||
## Copyright (C) 2006 Stefan Bethge <stefan@lanpartei.de>
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
|
||||
from common import gajim
|
||||
import sys
|
||||
import select
|
||||
from string import split
|
||||
from common.zeroconf.zeroconf import C_BARE_NAME, C_DOMAIN
|
||||
|
||||
try:
|
||||
import pybonjour
|
||||
except ImportError, e:
|
||||
pass
|
||||
|
||||
|
||||
resolve_timeout = 1
|
||||
|
||||
class Zeroconf:
|
||||
def __init__(self, new_serviceCB, remove_serviceCB, name_conflictCB,
|
||||
disconnected_CB, error_CB, name, host, port):
|
||||
self.domain = None # specific domain to browse
|
||||
self.stype = '_presence._tcp'
|
||||
self.port = port # listening port that gets announced
|
||||
self.username = name
|
||||
self.host = host
|
||||
self.txt = pybonjour.TXTRecord() # service data
|
||||
|
||||
# XXX these CBs should be set to None when we destroy the object
|
||||
# (go offline), because they create a circular reference
|
||||
self.new_serviceCB = new_serviceCB
|
||||
self.remove_serviceCB = remove_serviceCB
|
||||
self.name_conflictCB = name_conflictCB
|
||||
self.disconnected_CB = disconnected_CB
|
||||
self.error_CB = error_CB
|
||||
|
||||
self.contacts = {} # all current local contacts with data
|
||||
self.connected = False
|
||||
self.announced = False
|
||||
self.invalid_self_contact = {}
|
||||
self.resolved = []
|
||||
|
||||
|
||||
def browse_callback(self, sdRef, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain):
|
||||
gajim.log.debug('Found service %s in domain %s on %i(type: %s).' % (serviceName, replyDomain, interfaceIndex, regtype))
|
||||
if not self.connected:
|
||||
return
|
||||
if errorCode != pybonjour.kDNSServiceErr_NoError:
|
||||
return
|
||||
if not (flags & pybonjour.kDNSServiceFlagsAdd):
|
||||
self.remove_service_callback(serviceName)
|
||||
return
|
||||
|
||||
# asynchronous resolving
|
||||
resolve_sdRef = pybonjour.DNSServiceResolve(0, interfaceIndex, serviceName, regtype, replyDomain, self.service_resolved_callback)
|
||||
|
||||
try:
|
||||
while not self.resolved:
|
||||
ready = select.select([resolve_sdRef], [], [], resolve_timeout)
|
||||
if resolve_sdRef not in ready[0]:
|
||||
gajim.log.debug('Resolve timed out')
|
||||
break
|
||||
pybonjour.DNSServiceProcessResult(resolve_sdRef)
|
||||
else:
|
||||
self.resolved.pop()
|
||||
finally:
|
||||
resolve_sdRef.close()
|
||||
|
||||
def remove_service_callback(self, name):
|
||||
gajim.log.debug('Service %s disappeared.' % name)
|
||||
if not self.connected:
|
||||
return
|
||||
if name != self.name:
|
||||
for key in self.contacts.keys():
|
||||
if self.contacts[key][C_BARE_NAME] == name:
|
||||
del self.contacts[key]
|
||||
self.remove_serviceCB(key)
|
||||
return
|
||||
|
||||
def new_domain_callback(self,interface, protocol, domain, flags):
|
||||
if domain != "local":
|
||||
self.browse_domain(interface, protocol, domain)
|
||||
|
||||
# takes a TXTRecord instance
|
||||
def txt_array_to_dict(self, txt):
|
||||
items = pybonjour.TXTRecord.parse(txt)._items
|
||||
dict = {}
|
||||
for val in items.values():
|
||||
dict[val[0]] = val[1]
|
||||
return dict
|
||||
|
||||
def service_resolved_callback(self, sdRef, flags, interfaceIndex, errorCode, fullname,
|
||||
hosttarget, port, txtRecord):
|
||||
|
||||
# TODO: do proper decoding...
|
||||
escaping= {
|
||||
r'\.': '.',
|
||||
r'\032': ' ',
|
||||
r'\064': '@',
|
||||
}
|
||||
|
||||
name, stype, protocol, domain, dummy = split(fullname, '.')
|
||||
|
||||
# Replace the escaped values
|
||||
for src, trg in escaping.items():
|
||||
name = name.replace(src, trg)
|
||||
|
||||
txt = pybonjour.TXTRecord.parse(txtRecord)
|
||||
|
||||
gajim.log.debug('Service data for service %s on %i:' % (fullname, interfaceIndex))
|
||||
gajim.log.debug('Host %s, port %i, TXT data: %s' % (hosttarget, port, txt._items))
|
||||
|
||||
if not self.connected:
|
||||
return
|
||||
|
||||
bare_name = name
|
||||
if '@' not in name:
|
||||
name = name + '@' + name
|
||||
|
||||
# we don't want to see ourselves in the list
|
||||
if name != self.name:
|
||||
self.contacts[name] = (name, domain, interfaceIndex, protocol, hosttarget, hosttarget, port, bare_name, txtRecord)
|
||||
|
||||
self.new_serviceCB(name)
|
||||
else:
|
||||
# remember data
|
||||
# In case this is not our own record but of another
|
||||
# gajim instance on the same machine,
|
||||
# it will be used when we get a new name.
|
||||
self.invalid_self_contact[name] = (name, domain, interfaceIndex, protocol, hosttarget, hosttarget, port, bare_name, txtRecord)
|
||||
# count services
|
||||
self.resolved.append(True)
|
||||
|
||||
# different handler when resolving all contacts
|
||||
def service_resolved_all_callback(self, sdRef, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtRecord):
|
||||
if not self.connected:
|
||||
return
|
||||
|
||||
escaping= {
|
||||
r'\.': '.',
|
||||
r'\032': ' ',
|
||||
r'\064': '@',
|
||||
}
|
||||
|
||||
name, stype, protocol, domain, dummy = split(fullname, '.')
|
||||
|
||||
# Replace the escaped values
|
||||
for src, trg in escaping.items():
|
||||
name = name.replace(src, trg)
|
||||
|
||||
bare_name = name
|
||||
if name.find('@') == -1:
|
||||
name = name + '@' + name
|
||||
|
||||
# we don't want to see ourselves in the list
|
||||
if name != self.name:
|
||||
self.contacts[name] = (name, domain, interfaceIndex, protocol, hosttarget, hosttarget, port, bare_name, txtRecord)
|
||||
|
||||
|
||||
def service_added_callback(self, sdRef, flags, errorCode, name, regtype, domain):
|
||||
if errorCode == pybonjour.kDNSServiceErr_NoError:
|
||||
gajim.log.debug('Service successfully added')
|
||||
|
||||
def service_add_fail_callback(self, err):
|
||||
if err[0][0] == pybonjour.kDNSServiceErr_NameConflict:
|
||||
gajim.log.debug('Error while adding service. %s' % str(err))
|
||||
parts = self.username.split(' ')
|
||||
|
||||
#check if last part is a number and if, increment it
|
||||
try:
|
||||
stripped = str(int(parts[-1]))
|
||||
except:
|
||||
stripped = 1
|
||||
alternative_name = self.username + str(stripped+1)
|
||||
self.name_conflictCB(alternative_name)
|
||||
return
|
||||
self.error_CB(_('Error while adding service. %s') % str(err))
|
||||
self.disconnect()
|
||||
|
||||
# make zeroconf-valid names
|
||||
def replace_show(self, show):
|
||||
if show in ['chat', 'online', '']:
|
||||
return 'avail'
|
||||
elif show == 'xa':
|
||||
return 'away'
|
||||
return show
|
||||
|
||||
def create_service(self):
|
||||
txt = {}
|
||||
|
||||
#remove empty keys
|
||||
for key,val in self.txt:
|
||||
if val:
|
||||
txt[key] = val
|
||||
|
||||
txt['port.p2pj'] = self.port
|
||||
txt['version'] = 1
|
||||
txt['txtvers'] = 1
|
||||
|
||||
# replace gajim's show messages with compatible ones
|
||||
if 'status' in self.txt:
|
||||
txt['status'] = self.replace_show(self.txt['status'])
|
||||
else:
|
||||
txt['status'] = 'avail'
|
||||
|
||||
self.txt = pybonjour.TXTRecord(txt, strict=True)
|
||||
|
||||
try:
|
||||
sdRef = pybonjour.DNSServiceRegister(name = self.name,
|
||||
regtype = self.stype, port = self.port, txtRecord = self.txt,
|
||||
callBack = self.service_added_callback)
|
||||
self.service_sdRef = sdRef
|
||||
except pybonjour.BonjourError, e:
|
||||
self.service_add_fail_callback(e)
|
||||
else:
|
||||
gajim.log.debug('Publishing service %s of type %s' % (self.name, self.stype))
|
||||
|
||||
ready = select.select([sdRef], [], [], resolve_timeout)
|
||||
if sdRef in ready[0]:
|
||||
pybonjour.DNSServiceProcessResult(sdRef)
|
||||
|
||||
def announce(self):
|
||||
if not self.connected:
|
||||
return False
|
||||
|
||||
self.create_service()
|
||||
self.announced = True
|
||||
return True
|
||||
|
||||
def remove_announce(self):
|
||||
if self.announced == False:
|
||||
return False
|
||||
try:
|
||||
self.service_sdRef.close()
|
||||
self.announced = False
|
||||
return True
|
||||
except pybonjour.BonjourError, e:
|
||||
geajim.log.debug(e)
|
||||
return False
|
||||
|
||||
|
||||
def connect(self):
|
||||
self.name = self.username + '@' + self.host # service name
|
||||
|
||||
self.connected = True
|
||||
|
||||
# start browsing
|
||||
if self.domain is None:
|
||||
# Explicitly browse .local
|
||||
self.browse_domain()
|
||||
|
||||
# Browse for other browsable domains
|
||||
#self.domain_sdRef = pybonjour.DNSServiceEnumerateDomains(flags, interfaceIndex=0, callBack=self.new_domain_callback)
|
||||
|
||||
else:
|
||||
self.browse_domain(self.domain)
|
||||
|
||||
return True
|
||||
|
||||
def disconnect(self):
|
||||
if self.connected:
|
||||
self.connected = False
|
||||
self.browse_sdRef.close()
|
||||
self.remove_announce()
|
||||
|
||||
|
||||
def browse_domain(self, domain=None):
|
||||
gajim.log.debug('starting to browse')
|
||||
try:
|
||||
self.browse_sdRef = pybonjour.DNSServiceBrowse(regtype=self.stype, domain=domain, callBack=self.browse_callback)
|
||||
except pybonjour.BonjourError, e:
|
||||
self.error_CB("Error while browsing: %s" % e)
|
||||
|
||||
def browse_loop(self):
|
||||
ready = select.select([self.browse_sdRef], [], [], 2)
|
||||
if self.browse_sdRef in ready[0]:
|
||||
pybonjour.DNSServiceProcessResult(self.browse_sdRef)
|
||||
|
||||
# refresh txt data of all contacts manually (no callback available)
|
||||
def resolve_all(self):
|
||||
if not self.connected:
|
||||
return
|
||||
|
||||
# for now put here as this is synchronous
|
||||
self.browse_loop()
|
||||
|
||||
for val in self.contacts.values():
|
||||
resolve_sdRef = pybonjour.DNSServiceResolve(0,
|
||||
pybonjour.kDNSServiceInterfaceIndexAny, val[C_BARE_NAME],
|
||||
self.stype + '.', val[C_DOMAIN] + '.',
|
||||
self.service_resolved_all_callback)
|
||||
|
||||
try:
|
||||
ready = select.select([resolve_sdRef], [], [], resolve_timeout)
|
||||
if resolve_sdRef not in ready[0]:
|
||||
gajim.log.debug('Resolve timed out (in resolve_all)')
|
||||
break
|
||||
pybonjour.DNSServiceProcessResult(resolve_sdRef)
|
||||
finally:
|
||||
resolve_sdRef.close()
|
||||
|
||||
def get_contacts(self):
|
||||
return self.contacts
|
||||
|
||||
def get_contact(self, jid):
|
||||
if not jid in self.contacts:
|
||||
return None
|
||||
return self.contacts[jid]
|
||||
|
||||
def update_txt(self, show = None):
|
||||
if show:
|
||||
self.txt['status'] = self.replace_show(show)
|
||||
|
||||
try:
|
||||
pybonjour.DNSServiceUpdateRecord(self.service_sdRef, None, 0, self.txt)
|
||||
except pybonjour.BonjourError, e:
|
||||
return False
|
||||
return True
|
||||
|
1529
src/config.py
|
@ -26,6 +26,7 @@ import os
|
|||
import tooltips
|
||||
import dialogs
|
||||
import locale
|
||||
import Queue
|
||||
|
||||
import gtkgui_helpers
|
||||
from common import gajim
|
||||
|
@ -141,9 +142,14 @@ class ConversationTextview:
|
|||
|
||||
buffer.create_tag('focus-out-line', justification = gtk.JUSTIFY_CENTER)
|
||||
|
||||
# One mark at the begining then 2 marks between each lines
|
||||
size = gajim.config.get('max_conversation_lines')
|
||||
size = 2 * size - 1
|
||||
self.marks_queue = Queue.Queue(size)
|
||||
|
||||
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
|
||||
# holds a mark at the end of --- line
|
||||
self.focus_out_end_mark = None
|
||||
|
||||
self.line_tooltip = tooltips.BaseTooltip()
|
||||
# use it for hr too
|
||||
|
@ -213,13 +219,14 @@ class ConversationTextview:
|
|||
print_focus_out_line = False
|
||||
buffer = self.tv.get_buffer()
|
||||
|
||||
if self.focus_out_end_iter_offset is None:
|
||||
if self.focus_out_end_mark 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():
|
||||
focus_out_end_iter = buffer.get_iter_at_mark(self.focus_out_end_mark)
|
||||
focus_out_end_iter_offset = focus_out_end_iter.get_offset()
|
||||
if 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
|
||||
|
@ -230,9 +237,9 @@ class ConversationTextview:
|
|||
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)
|
||||
if self.focus_out_end_mark is not None:
|
||||
end_iter_for_previous_line = buffer.get_iter_at_mark(
|
||||
self.focus_out_end_mark)
|
||||
begin_iter_for_previous_line = end_iter_for_previous_line.copy()
|
||||
# img_char+1 (the '\n')
|
||||
begin_iter_for_previous_line.backward_chars(2)
|
||||
|
@ -240,6 +247,7 @@ class ConversationTextview:
|
|||
# remove focus out line
|
||||
buffer.delete(begin_iter_for_previous_line,
|
||||
end_iter_for_previous_line)
|
||||
buffer.delete_mark(self.focus_out_end_mark)
|
||||
|
||||
# add the new focus out line
|
||||
end_iter = buffer.get_end_iter()
|
||||
|
@ -255,7 +263,8 @@ class ConversationTextview:
|
|||
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()
|
||||
self.focus_out_end_mark = buffer.create_mark(None,
|
||||
buffer.get_end_iter(), left_gravity=True)
|
||||
|
||||
buffer.end_user_action()
|
||||
|
||||
|
@ -315,7 +324,10 @@ class ConversationTextview:
|
|||
buffer = self.tv.get_buffer()
|
||||
start, end = buffer.get_bounds()
|
||||
buffer.delete(start, end)
|
||||
self.focus_out_end_iter_offset = None
|
||||
size = gajim.config.get('max_conversation_lines')
|
||||
size = 2 * size - 1
|
||||
self.marks_queue = Queue.Queue(size)
|
||||
self.focus_out_end_mark = None
|
||||
|
||||
def visit_url_from_menuitem(self, widget, link):
|
||||
'''basically it filters out the widget instance'''
|
||||
|
@ -767,13 +779,29 @@ class ConversationTextview:
|
|||
'''prints 'chat' type messages'''
|
||||
buffer = self.tv.get_buffer()
|
||||
buffer.begin_user_action()
|
||||
if self.marks_queue.full():
|
||||
# remove oldest line
|
||||
m1 = self.marks_queue.get()
|
||||
m2 = self.marks_queue.get()
|
||||
i1 = buffer.get_iter_at_mark(m1)
|
||||
i2 = buffer.get_iter_at_mark(m2)
|
||||
buffer.delete(i1, i2)
|
||||
buffer.delete_mark(m1)
|
||||
end_iter = buffer.get_end_iter()
|
||||
at_the_end = False
|
||||
if self.at_the_end():
|
||||
at_the_end = True
|
||||
|
||||
# Create one mark and add it to queue once if it's the first line
|
||||
# else twice (one for end bound, one for start bound)
|
||||
mark = None
|
||||
if buffer.get_char_count() > 0:
|
||||
buffer.insert_with_tags_by_name(end_iter, '\n', 'eol')
|
||||
mark = buffer.create_mark(None, end_iter, left_gravity=True)
|
||||
self.marks_queue.put(mark)
|
||||
if not mark:
|
||||
mark = buffer.create_mark(None, end_iter, left_gravity=True)
|
||||
self.marks_queue.put(mark)
|
||||
if kind == 'incoming_queue':
|
||||
kind = 'incoming'
|
||||
if old_kind == 'incoming_queue':
|
||||
|
|
112
src/dialogs.py
|
@ -8,6 +8,7 @@
|
|||
## Copyright (C) 2005-2006 Travis Shirk <travis@pobox.com>
|
||||
## Copyright (C) 2005 Norman Rasmussen <norman@rasmussen.co.za>
|
||||
## Copyright (C) 2007 Lukas Petrovicky <lukas@petrovicky.net>
|
||||
## Copyright (C) 2007 Julien Pivotto <roidelapluie@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
|
||||
|
@ -115,7 +116,7 @@ class EditGroupsDialog:
|
|||
if not gajim.interface.roster.regroup and _account != account:
|
||||
continue
|
||||
for _jid in all_jid[_account]:
|
||||
contacts = gajim.contacts.get_contact(_account, _jid)
|
||||
contacts = gajim.contacts.get_contacts(_account, _jid)
|
||||
for c in contacts:
|
||||
if group in c.groups:
|
||||
c.groups.remove(group)
|
||||
|
@ -133,7 +134,7 @@ class EditGroupsDialog:
|
|||
if not gajim.interface.roster.regroup and _account != account:
|
||||
continue
|
||||
for _jid in all_jid[_account]:
|
||||
contacts = gajim.contacts.get_contact(_account, _jid)
|
||||
contacts = gajim.contacts.get_contacts(_account, _jid)
|
||||
for c in contacts:
|
||||
if not group in c.groups:
|
||||
c.groups.append(group)
|
||||
|
@ -547,13 +548,20 @@ class ChangeStatusMessageDialog:
|
|||
if not msg_name: # msg_name was ''
|
||||
msg_name = msg_text_1l
|
||||
msg_name = msg_name.decode('utf-8')
|
||||
iter_ = self.message_liststore.append((msg_name,))
|
||||
|
||||
gajim.config.add_per('statusmsg', msg_name)
|
||||
if msg_name in self.preset_messages_dict:
|
||||
dlg2 = ConfirmationDialog(_('Overwrite Status Message?'),
|
||||
_('This name is already used. Do you want to overwrite this status message?'))
|
||||
resp = dlg2.run()
|
||||
if resp != gtk.RESPONSE_OK:
|
||||
return
|
||||
else:
|
||||
iter_ = self.message_liststore.append((msg_name,))
|
||||
gajim.config.add_per('statusmsg', msg_name)
|
||||
# select in combobox the one we just saved
|
||||
self.message_combobox.set_active_iter(iter_)
|
||||
gajim.config.set_per('statusmsg', msg_name, 'message', msg_text_1l)
|
||||
self.preset_messages_dict[msg_name] = msg_text
|
||||
# select in combobox the one we just saved
|
||||
self.message_combobox.set_active_iter(iter_)
|
||||
|
||||
|
||||
class AddNewContactWindow:
|
||||
|
@ -610,6 +618,8 @@ _('Please fill in the data of the contact you want to add in account %s') %accou
|
|||
for j in gajim.contacts.get_jid_list(acct):
|
||||
if gajim.jid_is_transport(j):
|
||||
type_ = gajim.get_transport_name_from_jid(j, False)
|
||||
if not type_:
|
||||
continue
|
||||
if self.agents.has_key(type_):
|
||||
self.agents[type_].append(j)
|
||||
else:
|
||||
|
@ -625,30 +635,37 @@ _('Please fill in the data of the contact you want to add in account %s') %accou
|
|||
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)
|
||||
self.group_comboboxentry.set_model(liststore)
|
||||
# Combobox with transport/jabber icons
|
||||
liststore = gtk.ListStore(str, gtk.gdk.Pixbuf, str)
|
||||
cell = gtk.CellRendererPixbuf()
|
||||
self.protocol_combobox.pack_start(cell, False)
|
||||
self.protocol_combobox.add_attribute(cell, 'pixbuf', 1)
|
||||
cell = gtk.CellRendererText()
|
||||
cell.set_property('xpad', 5)
|
||||
self.protocol_combobox.pack_start(cell, True)
|
||||
self.protocol_combobox.add_attribute(cell, 'text', 0)
|
||||
self.protocol_combobox.set_model(liststore)
|
||||
uf_type = {'jabber': 'Jabber', 'aim': 'AIM', 'gadu-gadu': 'Gadu Gadu',
|
||||
'icq': 'ICQ', 'msn': 'MSN', 'yahoo': 'Yahoo'}
|
||||
# Jabber as first
|
||||
liststore.append(['Jabber', 'jabber'])
|
||||
img = gajim.interface.roster.jabber_state_images['16']['online']
|
||||
liststore.append(['Jabber', img.get_pixbuf(), 'jabber'])
|
||||
for type_ in self.agents:
|
||||
if type_ == 'jabber':
|
||||
continue
|
||||
if type_ in uf_type:
|
||||
liststore.append([uf_type[type_], type_])
|
||||
imgs = gajim.interface.roster.transports_state_images
|
||||
img = None
|
||||
if imgs['16'].has_key(type_) and imgs['16'][type_].has_key('online'):
|
||||
img = imgs['16'][type_]['online']
|
||||
if type_ in uf_type:
|
||||
liststore.append([uf_type[type_], img.get_pixbuf(), type_])
|
||||
else:
|
||||
liststore.append([type_, img.get_pixbuf(), type_])
|
||||
else:
|
||||
liststore.append([type_, type_])
|
||||
self.protocol_combobox.set_model(liststore)
|
||||
liststore.append([type_, img, type_])
|
||||
self.protocol_combobox.set_active(0)
|
||||
self.protocol_jid_combobox.set_no_show_all(True)
|
||||
self.protocol_jid_combobox.hide()
|
||||
self.subscription_table.set_no_show_all(True)
|
||||
self.auto_authorize_checkbutton.show()
|
||||
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)
|
||||
|
@ -666,7 +683,7 @@ _('Please fill in the data of the contact you want to add in account %s') %accou
|
|||
iter = model.get_iter_first()
|
||||
i = 0
|
||||
while iter:
|
||||
if model[iter][1] == type_:
|
||||
if model[iter][2] == type_:
|
||||
self.protocol_combobox.set_active(i)
|
||||
break
|
||||
iter = model.iter_next(iter)
|
||||
|
@ -741,7 +758,7 @@ _('Please fill in the data of the contact you want to add in account %s') %accou
|
|||
|
||||
model = self.protocol_combobox.get_model()
|
||||
iter = self.protocol_combobox.get_active_iter()
|
||||
type_ = model[iter][1]
|
||||
type_ = model[iter][2]
|
||||
if type_ != 'jabber':
|
||||
transport = self.protocol_jid_combobox.get_active_text().decode(
|
||||
'utf-8')
|
||||
|
@ -795,7 +812,7 @@ _('Please fill in the data of the contact you want to add in account %s') %accou
|
|||
def on_protocol_combobox_changed(self, widget):
|
||||
model = widget.get_model()
|
||||
iter = widget.get_active_iter()
|
||||
type_ = model[iter][1]
|
||||
type_ = model[iter][2]
|
||||
model = self.protocol_jid_combobox.get_model()
|
||||
model.clear()
|
||||
if len(self.agents[type_]):
|
||||
|
@ -1192,6 +1209,7 @@ class InputDialog:
|
|||
|
||||
def on_okbutton_clicked(self, widget):
|
||||
user_input = self.input_entry.get_text().decode('utf-8')
|
||||
self.cancel_handler = None
|
||||
self.dialog.destroy()
|
||||
if isinstance(self.ok_handler, tuple):
|
||||
self.ok_handler[0](user_input, *self.ok_handler[1:])
|
||||
|
@ -1327,7 +1345,8 @@ class SubscriptionRequestWindow:
|
|||
|
||||
|
||||
class JoinGroupchatWindow:
|
||||
def __init__(self, account, room_jid = '', nick = '', automatic = False):
|
||||
def __init__(self, account, room_jid = '', nick = '', password = '',
|
||||
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'''
|
||||
|
@ -1351,9 +1370,12 @@ class JoinGroupchatWindow:
|
|||
self.window = self.xml.get_widget('join_groupchat_window')
|
||||
self._room_jid_entry = self.xml.get_widget('room_jid_entry')
|
||||
self._nickname_entry = self.xml.get_widget('nickname_entry')
|
||||
self._password_entry = self.xml.get_widget('password_entry')
|
||||
|
||||
self._room_jid_entry.set_text(room_jid)
|
||||
self._nickname_entry.set_text(nick)
|
||||
if password:
|
||||
self._password_entry.set_text(password)
|
||||
self.xml.signal_autoconnect(self)
|
||||
gajim.interface.instances[account]['join_gc'] = self #now add us to open windows
|
||||
if len(gajim.connections) > 1:
|
||||
|
@ -1421,8 +1443,7 @@ class JoinGroupchatWindow:
|
|||
'''When Join button is clicked'''
|
||||
nickname = self._nickname_entry.get_text().decode('utf-8')
|
||||
room_jid = self._room_jid_entry.get_text().decode('utf-8')
|
||||
password = self.xml.get_widget('password_entry').get_text().decode(
|
||||
'utf-8')
|
||||
password = self._password_entry.get_text().decode('utf-8')
|
||||
user, server, resource = helpers.decompose_jid(room_jid)
|
||||
if not user or not server or resource:
|
||||
ErrorDialog(_('Invalid group chat Jabber ID'),
|
||||
|
@ -1460,7 +1481,7 @@ class JoinGroupchatWindow:
|
|||
if not room_jid_bookmarked:
|
||||
name = gajim.get_nick_from_jid(room_jid)
|
||||
bmdict = { 'name': name, 'jid': room_jid, 'autojoin': u'1',
|
||||
'password': password, 'nick': nickname,
|
||||
'minimize': '0', 'password': password, 'nick': nickname,
|
||||
'print_status': gajim.config.get('print_status_in_muc')}
|
||||
|
||||
gajim.connections[self.account].bookmarks.append(bmdict)
|
||||
|
@ -1858,17 +1879,6 @@ class SingleMessageWindow:
|
|||
spell2.set_language(lang)
|
||||
except gobject.GError, msg:
|
||||
dialogs.AspellDictError(lang)
|
||||
self.send_button.set_no_show_all(True)
|
||||
self.reply_button.set_no_show_all(True)
|
||||
self.send_and_close_button.set_no_show_all(True)
|
||||
self.to_label.set_no_show_all(True)
|
||||
self.to_entry.set_no_show_all(True)
|
||||
self.from_label.set_no_show_all(True)
|
||||
self.from_entry.set_no_show_all(True)
|
||||
self.close_button.set_no_show_all(True)
|
||||
self.cancel_button.set_no_show_all(True)
|
||||
self.message_scrolledwindow.set_no_show_all(True)
|
||||
self.conversation_scrolledwindow.set_no_show_all(True)
|
||||
|
||||
self.prepare_widgets_for(self.action)
|
||||
|
||||
|
@ -2217,7 +2227,7 @@ class PrivacyListWindow:
|
|||
jid_entry_completion.set_text_column(0)
|
||||
jid_entry_completion.set_model(jids_list_store)
|
||||
jid_entry_completion.set_popup_completion(True)
|
||||
self.edit_type_jabberid_entry.set_completion(jid_entry_completion)
|
||||
self.edit_type_jabberid_entry.set_completion(jid_entry_completion)
|
||||
|
||||
if action == 'EDIT':
|
||||
self.refresh_rules()
|
||||
|
@ -2231,7 +2241,6 @@ class PrivacyListWindow:
|
|||
|
||||
self.window.set_title(title)
|
||||
|
||||
self.add_edit_vbox.set_no_show_all(True)
|
||||
self.window.show_all()
|
||||
self.add_edit_vbox.hide()
|
||||
|
||||
|
@ -2683,6 +2692,7 @@ class InvitationReceivedDialog:
|
|||
|
||||
self.room_jid = room_jid
|
||||
self.account = account
|
||||
self.password = password
|
||||
xml = gtkgui_helpers.get_glade('invitation_received_dialog.glade')
|
||||
self.dialog = xml.get_widget('invitation_received_dialog')
|
||||
|
||||
|
@ -2716,7 +2726,8 @@ class InvitationReceivedDialog:
|
|||
def on_accept_button_clicked(self, widget):
|
||||
self.dialog.destroy()
|
||||
try:
|
||||
JoinGroupchatWindow(self.account, self.room_jid)
|
||||
JoinGroupchatWindow(self.account, self.room_jid,
|
||||
password=self.password)
|
||||
except GajimGeneralException:
|
||||
pass
|
||||
|
||||
|
@ -2796,7 +2807,10 @@ class ImageChooserDialog(FileChooserDialog):
|
|||
path_to_file = gtkgui_helpers.decode_filechooser_file_paths(
|
||||
(path_to_file,))[0]
|
||||
if os.path.exists(path_to_file):
|
||||
callback(widget, path_to_file)
|
||||
if isinstance(callback, tuple):
|
||||
callback[0](widget, path_to_file, *callback[1:])
|
||||
else:
|
||||
callback(widget, path_to_file)
|
||||
|
||||
try:
|
||||
if os.name == 'nt':
|
||||
|
@ -2856,12 +2870,19 @@ class AvatarChooserDialog(ImageChooserDialog):
|
|||
ImageChooserDialog.__init__(self, path_to_file, on_response_ok,
|
||||
on_response_cancel)
|
||||
button = gtk.Button(None, gtk.STOCK_CLEAR)
|
||||
self.response_clear = on_response_clear
|
||||
if on_response_clear:
|
||||
button.connect('clicked', on_response_clear)
|
||||
button.connect('clicked', self.on_clear)
|
||||
button.show_all()
|
||||
self.action_area.pack_start(button)
|
||||
self.action_area.reorder_child(button, 0)
|
||||
|
||||
def on_clear(self, widget):
|
||||
if isinstance(self.response_clear, tuple):
|
||||
self.response_clear[0](widget, *self.response_clear[1:])
|
||||
else:
|
||||
self.response_clear(widget)
|
||||
|
||||
class AddSpecialNotificationDialog:
|
||||
def __init__(self, jid):
|
||||
'''jid is the jid for which we want to add special notification
|
||||
|
@ -2983,9 +3004,6 @@ class AdvancedNotificationsWindow:
|
|||
self.delete_button.set_sensitive(False)
|
||||
self.down_button.set_sensitive(False)
|
||||
self.up_button.set_sensitive(False)
|
||||
self.recipient_list_entry.set_no_show_all(True)
|
||||
for st in ['online', 'away', 'xa', 'dnd', 'invisible']:
|
||||
self.__dict__[st + '_cb'].set_no_show_all(True)
|
||||
|
||||
self.window.show_all()
|
||||
|
||||
|
|
88
src/disco.py
|
@ -76,7 +76,7 @@ def _gen_agent_type_info():
|
|||
('_jid', 'weather'): (False, 'weather.png'),
|
||||
('gateway', 'sip'): (False, 'sip.png'),
|
||||
('directory', 'user'): (None, 'jud.png'),
|
||||
('pubsub', 'generic'): (None, 'pubsub.png'),
|
||||
('pubsub', 'generic'): (PubSubBrowser, 'pubsub.png'),
|
||||
('pubsub', 'service'): (PubSubBrowser, 'pubsub.png'),
|
||||
('proxy', 'bytestreams'): (None, 'bytestreams.png'), # Socks5 FT proxy
|
||||
|
||||
|
@ -438,8 +438,6 @@ _('Without a connection, you can not browse available services'))
|
|||
self.on_services_treeview_selection_changed)
|
||||
self.services_scrollwin = self.xml.get_widget('services_scrollwin')
|
||||
self.progressbar = self.xml.get_widget('services_progressbar')
|
||||
self.progressbar.set_no_show_all(True)
|
||||
self.progressbar.hide()
|
||||
self.banner = self.xml.get_widget('banner_agent_label')
|
||||
self.banner_icon = self.xml.get_widget('banner_agent_icon')
|
||||
self.banner_eventbox = self.xml.get_widget('banner_agent_eventbox')
|
||||
|
@ -447,8 +445,6 @@ _('Without a connection, you can not browse available services'))
|
|||
self.banner.realize()
|
||||
self.paint_banner()
|
||||
self.filter_hbox = self.xml.get_widget('filter_hbox')
|
||||
self.filter_hbox.set_no_show_all(True)
|
||||
self.filter_hbox.hide()
|
||||
self.action_buttonbox = self.xml.get_widget('action_buttonbox')
|
||||
|
||||
# Address combobox
|
||||
|
@ -1047,7 +1043,7 @@ class ToplevelAgentBrowser(AgentBrowser):
|
|||
# as it was before setting the timeout
|
||||
if props and self.tooltip.id == props[0]:
|
||||
# bounding rectangle of coordinates for the cell within the treeview
|
||||
rect = view.get_cell_area(props[0], props[1])
|
||||
rect = view.get_cell_area(props[0], props[1])
|
||||
# position of the treeview on the screen
|
||||
position = view.window.get_origin()
|
||||
self.tooltip.show_tooltip(state, rect.height, position[1] + rect.y)
|
||||
|
@ -1554,10 +1550,10 @@ class MucBrowser(AgentBrowser):
|
|||
self.join_button = None
|
||||
|
||||
def _create_treemodel(self):
|
||||
# JID, node, name, users, description, fetched
|
||||
# JID, node, name, users_int, users_str, description, fetched
|
||||
# This is rather long, I'd rather not use a data_func here though.
|
||||
# Users is a string, because want to be able to leave it empty.
|
||||
self.model = gtk.ListStore(str, str, str, str, str, bool)
|
||||
self.model = gtk.ListStore(str, str, str, int, str, str, bool)
|
||||
self.model.set_sort_column_id(2, gtk.SORT_ASCENDING)
|
||||
self.window.services_treeview.set_model(self.model)
|
||||
# Name column
|
||||
|
@ -1567,20 +1563,23 @@ class MucBrowser(AgentBrowser):
|
|||
renderer = gtk.CellRendererText()
|
||||
col.pack_start(renderer)
|
||||
col.set_attributes(renderer, text = 2)
|
||||
col.set_sort_column_id(2)
|
||||
self.window.services_treeview.insert_column(col, -1)
|
||||
col.set_resizable(True)
|
||||
# Users column
|
||||
col = gtk.TreeViewColumn(_('Users'))
|
||||
renderer = gtk.CellRendererText()
|
||||
col.pack_start(renderer)
|
||||
col.set_attributes(renderer, text = 3)
|
||||
col.set_attributes(renderer, text = 4)
|
||||
col.set_sort_column_id(3)
|
||||
self.window.services_treeview.insert_column(col, -1)
|
||||
col.set_resizable(True)
|
||||
# Description column
|
||||
col = gtk.TreeViewColumn(_('Description'))
|
||||
renderer = gtk.CellRendererText()
|
||||
col.pack_start(renderer)
|
||||
col.set_attributes(renderer, text = 4)
|
||||
col.set_attributes(renderer, text = 5)
|
||||
col.set_sort_column_id(4)
|
||||
self.window.services_treeview.insert_column(col, -1)
|
||||
col.set_resizable(True)
|
||||
# Id column
|
||||
|
@ -1588,9 +1587,11 @@ class MucBrowser(AgentBrowser):
|
|||
renderer = gtk.CellRendererText()
|
||||
col.pack_start(renderer)
|
||||
col.set_attributes(renderer, text = 0)
|
||||
col.set_sort_column_id(0)
|
||||
self.window.services_treeview.insert_column(col, -1)
|
||||
col.set_resizable(True)
|
||||
self.window.services_treeview.set_headers_visible(True)
|
||||
self.window.services_treeview.set_headers_clickable(True)
|
||||
# Source id for idle callback used to start disco#info queries.
|
||||
self._fetch_source = None
|
||||
# Query failure counter
|
||||
|
@ -1692,7 +1693,7 @@ class MucBrowser(AgentBrowser):
|
|||
# We're at the end of the model, we can leave end=None though.
|
||||
pass
|
||||
while iter and self.model.get_path(iter) != end:
|
||||
if not self.model.get_value(iter, 5):
|
||||
if not self.model.get_value(iter, 6):
|
||||
jid = self.model.get_value(iter, 0).decode('utf-8')
|
||||
node = self.model.get_value(iter, 1).decode('utf-8')
|
||||
self.cache.get_info(jid, node, self._agent_info)
|
||||
|
@ -1723,13 +1724,14 @@ class MucBrowser(AgentBrowser):
|
|||
if iter:
|
||||
if name:
|
||||
self.model[iter][2] = name
|
||||
self.model[iter][3] = len(items) # The number of users
|
||||
self.model[iter][5] = True
|
||||
self.model[iter][3] = len(items) # The number of users
|
||||
self.model[iter][4] = str(len(items)) # The number of users
|
||||
self.model[iter][6] = True
|
||||
self._fetch_source = None
|
||||
self._query_visible()
|
||||
|
||||
def _add_item(self, jid, node, item, force):
|
||||
self.model.append((jid, node, item.get('name', ''), '', '', False))
|
||||
self.model.append((jid, node, item.get('name', ''), -1, '', '', False))
|
||||
if not self._fetch_source:
|
||||
self._fetch_source = gobject.idle_add(self._start_info_query)
|
||||
|
||||
|
@ -1743,14 +1745,15 @@ class MucBrowser(AgentBrowser):
|
|||
users = form.getField('muc#roominfo_occupants')
|
||||
descr = form.getField('muc#roominfo_description')
|
||||
if users:
|
||||
self.model[iter][3] = users.getValue()
|
||||
self.model[iter][3] = int(users.getValue())
|
||||
self.model[iter][4] = users.getValue()
|
||||
if descr:
|
||||
self.model[iter][4] = descr.getValue()
|
||||
self.model[iter][5] = descr.getValue()
|
||||
# Only set these when we find a form with additional info
|
||||
# Some servers don't support forms and put extra info in
|
||||
# the name attribute, so we preserve it in that case.
|
||||
self.model[iter][2] = name
|
||||
self.model[iter][5] = True
|
||||
self.model[iter][6] = True
|
||||
break
|
||||
else:
|
||||
# We didn't find a form, switch to alternate query mode
|
||||
|
@ -1791,8 +1794,9 @@ class DiscussionGroupsBrowser(AgentBrowser):
|
|||
def _create_treemodel(self):
|
||||
''' Create treemodel for the window. '''
|
||||
# JID, node, name (with description) - pango markup, dont have info?, subscribed?
|
||||
self.model = gtk.ListStore(str, str, str, bool, bool)
|
||||
self.model.set_sort_column_id(3, gtk.SORT_ASCENDING)
|
||||
self.model = gtk.TreeStore(str, str, str, bool, bool)
|
||||
# sort by name
|
||||
self.model.set_sort_column_id(2, gtk.SORT_ASCENDING)
|
||||
self.window.services_treeview.set_model(self.model)
|
||||
|
||||
# Name column
|
||||
|
@ -1804,6 +1808,7 @@ class DiscussionGroupsBrowser(AgentBrowser):
|
|||
col.set_attributes(renderer, markup=2)
|
||||
col.set_resizable(True)
|
||||
self.window.services_treeview.insert_column(col, -1)
|
||||
self.window.services_treeview.set_headers_visible(True)
|
||||
|
||||
# Subscription state
|
||||
renderer = gtk.CellRendererToggle()
|
||||
|
@ -1813,7 +1818,29 @@ class DiscussionGroupsBrowser(AgentBrowser):
|
|||
col.set_resizable(False)
|
||||
self.window.services_treeview.insert_column(col, -1)
|
||||
|
||||
self.window.services_treeview.set_headers_visible(True)
|
||||
# Node Column
|
||||
renderer = gtk.CellRendererText()
|
||||
col = gtk.TreeViewColumn(_('Node'))
|
||||
col.pack_start(renderer)
|
||||
col.set_attributes(renderer, markup=1)
|
||||
col.set_resizable(True)
|
||||
self.window.services_treeview.insert_column(col, -1)
|
||||
|
||||
def _add_items(self, jid, node, items, force):
|
||||
for item in items:
|
||||
jid = item['jid']
|
||||
node = item.get('node', '')
|
||||
self._total_items += 1
|
||||
self._add_item(jid, node, item, force)
|
||||
|
||||
def _in_list_foreach(self, model, path, iter, node):
|
||||
if model[path][1] == node:
|
||||
self.in_list = True
|
||||
|
||||
def _in_list(self, node):
|
||||
self.in_list = False
|
||||
self.model.foreach(self._in_list_foreach, node)
|
||||
return self.in_list
|
||||
|
||||
def _add_item(self, jid, node, item, force):
|
||||
''' Called when we got basic information about new node from query.
|
||||
|
@ -1830,7 +1857,24 @@ class DiscussionGroupsBrowser(AgentBrowser):
|
|||
name = gobject.markup_escape_text(name)
|
||||
name = '<b>%s</b>' % name
|
||||
|
||||
self.model.append((jid, node, name, dunno, subscribed))
|
||||
node_splitted = node.split('/')
|
||||
parent_iter = None
|
||||
while len(node_splitted) > 1:
|
||||
parent_node = node_splitted.pop(0)
|
||||
parent_iter = self._get_child_iter(parent_iter, parent_node)
|
||||
node_splitted[0] = parent_node + '/' + node_splitted[0]
|
||||
if not self._in_list(node):
|
||||
self.model.append(parent_iter, (jid, node, name, dunno, subscribed))
|
||||
self.cache.get_items(jid, node, self._add_items, force = force,
|
||||
args = (force,))
|
||||
|
||||
def _get_child_iter(self, parent_iter, node):
|
||||
child_iter = self.model.iter_children(parent_iter)
|
||||
while child_iter:
|
||||
if self.model[child_iter][1] == node:
|
||||
return child_iter
|
||||
child_iter = self.model.iter_next(child_iter)
|
||||
return None
|
||||
|
||||
def _add_actions(self):
|
||||
self.post_button = gtk.Button(label=_('New post'), use_underline=True)
|
||||
|
@ -1905,7 +1949,7 @@ class DiscussionGroupsBrowser(AgentBrowser):
|
|||
model, iter = self.window.services_treeview.get_selection().get_selected()
|
||||
if iter is None: return
|
||||
|
||||
groupnode = model.get_value(iter, 1) # 1 = groupnode
|
||||
groupnode = model.get_value(iter, 1) # 1 = groupnode
|
||||
|
||||
gajim.connections[self.account].send_pb_unsubscribe(self.jid, groupnode, self._unsubscribeCB, groupnode)
|
||||
|
||||
|
|
|
@ -0,0 +1,276 @@
|
|||
## features_window.py
|
||||
##
|
||||
## Copyright (C) 2007 Yann Le Boulanger <asterix@lagaule.org>
|
||||
##
|
||||
## 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 gtk
|
||||
import gobject
|
||||
import gtkgui_helpers
|
||||
|
||||
import dialogs
|
||||
|
||||
from common import gajim
|
||||
from common import helpers
|
||||
|
||||
import random
|
||||
from tempfile import gettempdir
|
||||
from subprocess import Popen
|
||||
|
||||
class FeaturesWindow:
|
||||
'''Class for features window'''
|
||||
|
||||
def __init__(self):
|
||||
self.xml = gtkgui_helpers.get_glade('features_window.glade')
|
||||
self.window = self.xml.get_widget('features_window')
|
||||
treeview = self.xml.get_widget('features_treeview')
|
||||
self.desc_label = self.xml.get_widget('feature_desc_label')
|
||||
|
||||
# {name: (available_function, unix_text, windows_text)}
|
||||
self.features = {
|
||||
_('PyOpenSSL'): (self.pyopenssl_available,
|
||||
_('A library used to validate server certificates to ensure a secure connection.'),
|
||||
_('Requires python-pyopenssl.'),
|
||||
_('Requires python-pyopenssl.')),
|
||||
_('Bonjour / Zeroconf'): (self.zeroconf_available,
|
||||
_('Serverless chatting with autodetected clients in a local network.'),
|
||||
_('Requires python-avahi.'),
|
||||
_('Requires pybonjour (http://o2s.csail.mit.edu/o2s-wiki/pybonjour).')),
|
||||
_('gajim-remote'): (self.dbus_available,
|
||||
_('A script to controle gajim via commandline.'),
|
||||
_('Requires python-dbus.'),
|
||||
_('Feature not available under Windows.')),
|
||||
_('OpenGPG'): (self.gpg_available,
|
||||
_('Encrypting chatmessages with gpg keys.'),
|
||||
_('Requires gpg and python-GnuPGInterface.'),
|
||||
_('Feature not available under Windows.')),
|
||||
_('network-manager'): (self.network_manager_available,
|
||||
_('Autodetection of network status.'),
|
||||
_('Requires gnome-network-manager and python-dbus.'),
|
||||
_('Feature not available under Windows.')),
|
||||
_('Session Management'): (self.session_management_available,
|
||||
_('Gajim session is stored on logout and restored on login.'),
|
||||
_('Requires python-gnome2.'),
|
||||
_('Feature not available under Windows.')),
|
||||
_('gnome-keyring'): (self.gnome_keyring_available,
|
||||
_('Passwords can be stored securely and not just in plaintext.'),
|
||||
_('Requires gnome-keyring and python-gnome2-desktop.'),
|
||||
_('Feature not available under Windows.')),
|
||||
_('SRV'): (self.srv_available,
|
||||
_('Ability to connect to servers which is using SRV records.'),
|
||||
_('Requires dnsutils.'),
|
||||
_('Requires nslookup to use SRV records.')),
|
||||
_('Spell Checker'): (self.speller_available,
|
||||
_('Spellchecking of composed messages.'),
|
||||
_('Requires python-gnome2-extras or compilation of gtkspell module from Gajim sources.'),
|
||||
_('Feature not available under Windows.')),
|
||||
_('Notification-daemon'): (self.notification_available,
|
||||
_('Passive popups notifying for new events.'),
|
||||
_('Requires python-notify or instead python-dbus in conjunction with notification-daemon.'),
|
||||
_('Feature not available under Windows.')),
|
||||
_('Trayicon'): (self.trayicon_available,
|
||||
_('A icon in systemtray reflecting the current presence.'),
|
||||
_('Requires python-gnome2-extras or compiled trayicon module from Gajim sources.'),
|
||||
_('Requires PyGTK >= 2.10.')),
|
||||
_('Idle'): (self.idle_available,
|
||||
_('Ability to measure idle time, in order to set auto status.'),
|
||||
_('Requires compilation of the idle module from Gajim sources.'),
|
||||
_('Requires compilation of the idle module from Gajim sources.')),
|
||||
_('LaTeX'): (self.latex_available,
|
||||
_('Transform LaTeX espressions between $$ $$.'),
|
||||
_('Requires texlive-latex-base, dvips and imagemagick. You have to set \'use_latex\' to True in the Advanced Configuration Editor.'),
|
||||
_('Feature not available under Windows.')),
|
||||
}
|
||||
|
||||
# name, supported
|
||||
self.model = gtk.ListStore(str, bool)
|
||||
treeview.set_model(self.model)
|
||||
|
||||
col = gtk.TreeViewColumn(_('Available'))
|
||||
treeview.append_column(col)
|
||||
cell = gtk.CellRendererToggle()
|
||||
cell.set_property('radio', True)
|
||||
col.pack_start(cell)
|
||||
col.set_attributes(cell, active = 1)
|
||||
|
||||
col = gtk.TreeViewColumn(_('Feature'))
|
||||
treeview.append_column(col)
|
||||
cell = gtk.CellRendererText()
|
||||
col.pack_start(cell, expand = True)
|
||||
col.add_attribute(cell, 'text', 0)
|
||||
|
||||
# Fill model
|
||||
for feature in self.features:
|
||||
func = self.features[feature][0]
|
||||
rep = func()
|
||||
self.model.append([feature, rep])
|
||||
self.xml.signal_autoconnect(self)
|
||||
self.window.show_all()
|
||||
self.xml.get_widget('close_button').grab_focus()
|
||||
|
||||
def on_close_button_clicked(self, widget):
|
||||
self.window.destroy()
|
||||
|
||||
def on_features_treeview_cursor_changed(self, widget):
|
||||
selection = widget.get_selection()
|
||||
path = selection.get_selected_rows()[1][0]
|
||||
available = self.model[path][1]
|
||||
feature = self.model[path][0]
|
||||
text = self.features[feature][1] + '\n'
|
||||
if os.name == 'nt':
|
||||
text = text + self.features[feature][3]
|
||||
else:
|
||||
text = text + self.features[feature][2]
|
||||
self.desc_label.set_text(text)
|
||||
|
||||
def pyopenssl_available(self):
|
||||
try:
|
||||
import OpenSSL.SSL
|
||||
import OpenSSL.crypto
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
def zeroconf_available(self):
|
||||
try:
|
||||
import avahi
|
||||
except:
|
||||
try:
|
||||
import pybonjour
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
def dbus_available(self):
|
||||
if os.name == 'nt':
|
||||
return False
|
||||
from common import dbus_support
|
||||
return dbus_support.supported
|
||||
|
||||
def gpg_available(self):
|
||||
if os.name == 'nt':
|
||||
return False
|
||||
from common import GnuPG
|
||||
return GnuPG.USE_GPG
|
||||
|
||||
def network_manager_available(self):
|
||||
if os.name == 'nt':
|
||||
return False
|
||||
import network_manager_listener
|
||||
return network_manager_listener.supported
|
||||
|
||||
def session_management_available(self):
|
||||
if os.name == 'nt':
|
||||
return False
|
||||
try:
|
||||
import gnome.ui
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
def gnome_keyring_available(self):
|
||||
if os.name == 'nt':
|
||||
return False
|
||||
try:
|
||||
import gnomekeyring
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
def srv_available(self):
|
||||
return helpers.is_in_path('nslookup')
|
||||
|
||||
def speller_available(self):
|
||||
if os.name == 'nt':
|
||||
return False
|
||||
try:
|
||||
import gtkspell
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
def notification_available(self):
|
||||
if os.name == 'nt':
|
||||
return False
|
||||
from common import dbus_support
|
||||
if self.dbus_available() and dbus_support.get_notifications_interface():
|
||||
return True
|
||||
try:
|
||||
import pynotify
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
def trayicon_available(self):
|
||||
if os.name == 'nt' and gtk.pygtk_version >= (2, 10, 0) and \
|
||||
gtk.gtk_version >= (2, 10, 0):
|
||||
return True
|
||||
try:
|
||||
import systray
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
def idle_available(self):
|
||||
from common import sleepy
|
||||
return sleepy.SUPPORTED
|
||||
|
||||
def latex_available(self):
|
||||
'''check is latex is available and if it can create a picture.'''
|
||||
|
||||
if os.name == 'nt':
|
||||
return False
|
||||
|
||||
exitcode = 0
|
||||
random.seed()
|
||||
tmpfile = os.path.join(gettempdir(), "gajimtex_" + \
|
||||
random.randint(0,100).__str__())
|
||||
|
||||
# build latex string
|
||||
texstr = '\\documentclass[12pt]{article}\\usepackage[dvips]{graphicx}'
|
||||
texstr += '\\usepackage{amsmath}\\usepackage{amssymb}\\pagestyle{empty}'
|
||||
texstr += '\\begin{document}\\begin{large}\\begin{gather*}test'
|
||||
texstr += '\\end{gather*}\\end{large}\\end{document}'
|
||||
|
||||
file = open(os.path.join(tmpfile + ".tex"), "w+")
|
||||
file.write(texstr)
|
||||
file.flush()
|
||||
file.close()
|
||||
try:
|
||||
p = Popen(['latex', '--interaction=nonstopmode', tmpfile + '.tex'],
|
||||
cwd=gettempdir())
|
||||
exitcode = p.wait()
|
||||
except:
|
||||
exitcode = 1
|
||||
if exitcode == 0:
|
||||
try:
|
||||
p = Popen(['dvips', '-E', '-o', tmpfile + '.ps', tmpfile + '.dvi'],
|
||||
cwd=gettempdir())
|
||||
exitcode = p.wait()
|
||||
except:
|
||||
exitcode = 1
|
||||
if exitcode == 0:
|
||||
try:
|
||||
p = Popen(['convert', tmpfile + '.ps', tmpfile + '.png'],
|
||||
cwd=gettempdir())
|
||||
exitcode = p.wait()
|
||||
except:
|
||||
exitcode = 1
|
||||
extensions = [".tex", ".log", ".aux", ".dvi", ".ps", ".png"]
|
||||
for ext in extensions:
|
||||
try:
|
||||
os.remove(tmpfile + ext)
|
||||
except Exception:
|
||||
pass
|
||||
if exitcode == 0:
|
||||
return True
|
||||
return False
|
|
@ -116,8 +116,6 @@ class FileTransfersWindow:
|
|||
self.cancel_menuitem = self.xml.get_widget('cancel_menuitem')
|
||||
self.pause_menuitem = self.xml.get_widget('pause_menuitem')
|
||||
self.continue_menuitem = self.xml.get_widget('continue_menuitem')
|
||||
self.continue_menuitem.hide()
|
||||
self.continue_menuitem.set_no_show_all(True)
|
||||
self.remove_menuitem = self.xml.get_widget('remove_menuitem')
|
||||
self.xml.signal_autoconnect(self)
|
||||
|
||||
|
@ -420,10 +418,18 @@ _('Connection with peer cannot be established.'))
|
|||
#they are not translatable.
|
||||
return _('%(hours)02.d:%(minutes)02.d:%(seconds)02.d') % times
|
||||
|
||||
def _get_eta_and_speed(self, full_size, transfered_size, elapsed_time):
|
||||
if elapsed_time == 0:
|
||||
def _get_eta_and_speed(self, full_size, transfered_size, file_props):
|
||||
if len(file_props['transfered_size']) == 0:
|
||||
return 0., 0.
|
||||
speed = round(float(transfered_size) / elapsed_time)
|
||||
elif len(file_props['transfered_size']) == 1:
|
||||
speed = round(float(transfered_size) / file_props['elapsed-time'])
|
||||
else:
|
||||
# first and last are (time, transfered_size)
|
||||
first = file_props['transfered_size'][0]
|
||||
last = file_props['transfered_size'][-1]
|
||||
transfered = last[1] - first[1]
|
||||
tim = last[0] - first[0]
|
||||
speed = round(float(transfered) / tim)
|
||||
if speed == 0.:
|
||||
return 0., 0.
|
||||
remaining_size = full_size - transfered_size
|
||||
|
@ -484,8 +490,13 @@ _('Connection with peer cannot be established.'))
|
|||
if file_props.has_key('offset') and file_props['offset']:
|
||||
transfered_size -= file_props['offset']
|
||||
full_size -= file_props['offset']
|
||||
|
||||
if file_props['elapsed-time'] > 0:
|
||||
file_props['transfered_size'].append((file_props['last-time'], transfered_size))
|
||||
if len(file_props['transfered_size']) > 6:
|
||||
file_props['transfered_size'].pop(0)
|
||||
eta, speed = self._get_eta_and_speed(full_size, transfered_size,
|
||||
file_props['elapsed-time'])
|
||||
file_props)
|
||||
|
||||
self.model.set(iter, C_PROGRESS, text)
|
||||
self.model.set(iter, C_PERCENT, int(percent))
|
||||
|
@ -547,6 +558,8 @@ _('Connection with peer cannot be established.'))
|
|||
file_props['sender'] = account
|
||||
file_props['receiver'] = contact
|
||||
file_props['tt_account'] = account
|
||||
# keep the last time: transfered_size to compute transfer speed
|
||||
file_props['transfered_size'] = []
|
||||
return file_props
|
||||
|
||||
def add_transfer(self, account, contact, file_props):
|
||||
|
@ -784,6 +797,8 @@ _('Connection with peer cannot be established.'))
|
|||
elif self.is_transfer_active(file_props):
|
||||
file_props['paused'] = True
|
||||
self.set_status(file_props['type'], file_props['sid'], 'pause')
|
||||
# reset that to compute speed only when we resume
|
||||
file_props['transfered_size'] = []
|
||||
self.toggle_pause_continue(False)
|
||||
|
||||
def on_cancel_button_clicked(self, widget):
|
||||
|
|
|
@ -137,6 +137,15 @@ class GajimRemote:
|
|||
'using this account'), False),
|
||||
]
|
||||
],
|
||||
'send_groupchat_message':[
|
||||
_('Sends new message to a groupchat you\'ve joined.'),
|
||||
[
|
||||
('room_jid', _('JID of the room that will receive the message'), True),
|
||||
(_('message'), _('message contents'), True),
|
||||
(_('account'), _('if specified, the message will be sent '
|
||||
'using this account'), False),
|
||||
]
|
||||
],
|
||||
'contact_info': [
|
||||
_('Gets detailed info on a contact'),
|
||||
[
|
||||
|
|
252
src/gajim.py
|
@ -6,6 +6,8 @@
|
|||
## Copyright (C) 2005-2006 Nikos Kouremenos <kourem@gmail.com>
|
||||
## Copyright (C) 2005-2006 Dimitur Kirov <dkirov@gmail.com>
|
||||
## Copyright (C) 2005 Travis Shirk <travis@pobox.com>
|
||||
## Copyright (C) 2007 Lukas Petrovicky <lukas@petrovicky.net>
|
||||
## Copyright (C) 2007 Julien Pivotto <roidelapluie@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
|
||||
|
@ -70,10 +72,11 @@ def parseAndSetLogLevels(arg):
|
|||
def parseOpts():
|
||||
profile = ''
|
||||
verbose = False
|
||||
config_path = None
|
||||
|
||||
try:
|
||||
shortargs = 'hqvl:p:'
|
||||
longargs = 'help quiet verbose loglevel= profile='
|
||||
shortargs = 'hqvl:p:c:'
|
||||
longargs = 'help quiet verbose loglevel= profile= config_path='
|
||||
opts, args = getopt.getopt(sys.argv[1:], shortargs, longargs.split())
|
||||
except getopt.error, msg:
|
||||
print msg
|
||||
|
@ -93,11 +96,22 @@ def parseOpts():
|
|||
profile = a
|
||||
elif o in ('-l', '--loglevel'):
|
||||
parseAndSetLogLevels(a)
|
||||
return profile, verbose
|
||||
elif o in ('-c', '--config-path'):
|
||||
config_path = a
|
||||
return profile, verbose, config_path
|
||||
|
||||
profile, verbose = parseOpts()
|
||||
profile, verbose, config_path = parseOpts()
|
||||
del parseOpts, parseAndSetLogLevels, parseLogTarget, parseLogLevel
|
||||
|
||||
import locale
|
||||
profile = unicode(profile, locale.getpreferredencoding())
|
||||
|
||||
import common.configpaths
|
||||
common.configpaths.gajimpaths.init(config_path)
|
||||
del config_path
|
||||
common.configpaths.gajimpaths.init_profile(profile)
|
||||
del profile
|
||||
|
||||
import message_control
|
||||
|
||||
from chat_control import ChatControlBase
|
||||
|
@ -106,6 +120,8 @@ from atom_window import AtomWindow
|
|||
from common import exceptions
|
||||
from common.zeroconf import connection_zeroconf
|
||||
from common import dbus_support
|
||||
if dbus_support.supported:
|
||||
import dbus
|
||||
|
||||
if os.name == 'posix': # dl module is Unix Only
|
||||
try: # rename the process name to gajim
|
||||
|
@ -196,12 +212,6 @@ from common import optparser
|
|||
if verbose: gajim.verbose = True
|
||||
del verbose
|
||||
|
||||
import locale
|
||||
profile = unicode(profile, locale.getpreferredencoding())
|
||||
|
||||
import common.configpaths
|
||||
common.configpaths.init_profile(profile)
|
||||
del profile
|
||||
gajimpaths = common.configpaths.gajimpaths
|
||||
|
||||
pid_filename = gajimpaths['PID_FILE']
|
||||
|
@ -316,9 +326,15 @@ pid_dir = os.path.dirname(pid_filename)
|
|||
if not os.path.exists(pid_dir):
|
||||
check_paths.create_path(pid_dir)
|
||||
# Create pid file
|
||||
f = open(pid_filename, 'w')
|
||||
f.write(str(os.getpid()))
|
||||
f.close()
|
||||
try:
|
||||
f = open(pid_filename, 'w')
|
||||
f.write(str(os.getpid()))
|
||||
f.close()
|
||||
except IOError, e:
|
||||
dlg = dialogs.ErrorDialog(_('Disk Write Error'), str(e))
|
||||
dlg.run()
|
||||
dlg.destroy()
|
||||
sys.exit()
|
||||
del pid_dir
|
||||
del f
|
||||
|
||||
|
@ -396,6 +412,9 @@ class Interface:
|
|||
prompt = data[2]
|
||||
proposed_nick = data[3]
|
||||
gc_control = self.msg_win_mgr.get_control(room_jid, account)
|
||||
if not gc_control and \
|
||||
room_jid in self.minimized_controls[account]:
|
||||
gc_control = self.minimized_controls[account][room_jid]
|
||||
if gc_control: # user may close the window before we are here
|
||||
gc_control.show_change_nick_input_dialog(title, prompt, proposed_nick)
|
||||
|
||||
|
@ -479,16 +498,21 @@ class Interface:
|
|||
model[self.roster.status_message_menuitem_iter][3] = True
|
||||
|
||||
# Inform all controls for this account of the connection state change
|
||||
for ctrl in self.msg_win_mgr.get_controls():
|
||||
ctrls = self.msg_win_mgr.get_controls()
|
||||
if self.minimized_controls.has_key(account):
|
||||
# Can not be the case when we remove account
|
||||
ctrls += self.minimized_controls[account].values()
|
||||
for ctrl in ctrls:
|
||||
if ctrl.account == account:
|
||||
if status == 'offline' or (status == 'invisible' and \
|
||||
gajim.connections[account].is_zeroconf):
|
||||
gajim.connections[account].is_zeroconf):
|
||||
ctrl.got_disconnected()
|
||||
else:
|
||||
# Other code rejoins all GCs, so we don't do it here
|
||||
if not ctrl.type_id == message_control.TYPE_GC:
|
||||
ctrl.got_connected()
|
||||
ctrl.parent_win.redraw_tab(ctrl)
|
||||
if ctrl.parent_win:
|
||||
ctrl.parent_win.redraw_tab(ctrl)
|
||||
|
||||
self.roster.on_status_changed(account, status)
|
||||
if account in self.show_vcard_when_connect:
|
||||
|
@ -535,7 +559,7 @@ class Interface:
|
|||
# Update contact
|
||||
jid_list = gajim.contacts.get_jid_list(account)
|
||||
if ji in jid_list or jid == gajim.get_jid_from_account(account):
|
||||
lcontact = gajim.contacts.get_contacts_from_jid(account, ji)
|
||||
lcontact = gajim.contacts.get_contacts(account, ji)
|
||||
contact1 = None
|
||||
resources = []
|
||||
for c in lcontact:
|
||||
|
@ -636,7 +660,7 @@ class Interface:
|
|||
# (when contact signs out or has errors)
|
||||
if array[1] in ('offline', 'error'):
|
||||
contact1.our_chatstate = contact1.chatstate = \
|
||||
contact1.composing_jep = None
|
||||
contact1.composing_xep = None
|
||||
gajim.connections[account].remove_transfers_for_contact(contact1)
|
||||
self.roster.chg_contact_status(contact1, array[1], status_message,
|
||||
account)
|
||||
|
@ -665,7 +689,7 @@ class Interface:
|
|||
|
||||
def handle_event_msg(self, account, array):
|
||||
# 'MSG' (account, (jid, msg, time, encrypted, msg_type, subject,
|
||||
# chatstate, msg_id, composing_jep, user_nick, xhtml))
|
||||
# chatstate, msg_id, composing_xep, user_nick, xhtml))
|
||||
# user_nick is JEP-0172
|
||||
|
||||
full_jid_with_resource = array[0]
|
||||
|
@ -678,7 +702,7 @@ class Interface:
|
|||
subject = array[5]
|
||||
chatstate = array[6]
|
||||
msg_id = array[7]
|
||||
composing_jep = array[8]
|
||||
composing_xep = array[8]
|
||||
xhtml = array[10]
|
||||
if gajim.config.get('ignore_incoming_xhtml'):
|
||||
xhtml = None
|
||||
|
@ -687,9 +711,8 @@ class Interface:
|
|||
|
||||
groupchat_control = self.msg_win_mgr.get_control(jid, account)
|
||||
if not groupchat_control and \
|
||||
gajim.interface.minimized_controls.has_key(account) and \
|
||||
jid in gajim.interface.minimized_controls[account]:
|
||||
groupchat_control = gajim.interface.minimized_controls[account][jid]
|
||||
jid in self.minimized_controls[account]:
|
||||
groupchat_control = self.minimized_controls[account][jid]
|
||||
pm = False
|
||||
if groupchat_control and groupchat_control.type_id == \
|
||||
message_control.TYPE_GC:
|
||||
|
@ -720,11 +743,9 @@ class Interface:
|
|||
|
||||
# Handle chat states
|
||||
contact = gajim.contacts.get_contact(account, jid, resource)
|
||||
if contact and isinstance(contact, list):
|
||||
contact = contact[0]
|
||||
if contact:
|
||||
if contact.composing_jep != 'JEP-0085': # We cache xep85 support
|
||||
contact.composing_jep = composing_jep
|
||||
if contact.composing_xep != 'XEP-0085': # We cache xep85 support
|
||||
contact.composing_xep = composing_xep
|
||||
if chat_control and chat_control.type_id == message_control.TYPE_CHAT:
|
||||
if chatstate is not None:
|
||||
# other peer sent us reply, so he supports jep85 or jep22
|
||||
|
@ -748,7 +769,7 @@ class Interface:
|
|||
return
|
||||
|
||||
if gajim.config.get('ignore_unknown_contacts') and \
|
||||
not gajim.contacts.get_contact(account, jid) and not pm:
|
||||
not gajim.contacts.get_contacts(account, jid) and not pm:
|
||||
return
|
||||
if not contact:
|
||||
# contact is not in the roster, create a fake one to display
|
||||
|
@ -769,7 +790,7 @@ class Interface:
|
|||
if pm:
|
||||
nickname = resource
|
||||
groupchat_control.on_private_message(nickname, message, array[2],
|
||||
xhtml)
|
||||
xhtml, msg_id)
|
||||
else:
|
||||
# array: (jid, msg, time, encrypted, msg_type, subject)
|
||||
if encrypted:
|
||||
|
@ -798,6 +819,9 @@ class Interface:
|
|||
jids = full_jid_with_resource.split('/', 1)
|
||||
jid = jids[0]
|
||||
gc_control = self.msg_win_mgr.get_control(jid, account)
|
||||
if not gc_control and \
|
||||
jid in self.minimized_controls[account]:
|
||||
gc_control = self.minimized_controls[account][jid]
|
||||
if gc_control and gc_control.type_id != message_control.TYPE_GC:
|
||||
gc_control = None
|
||||
if gc_control:
|
||||
|
@ -821,7 +845,7 @@ class Interface:
|
|||
return
|
||||
|
||||
gc_control.print_conversation('Error %s: %s' % (array[1], array[2]))
|
||||
if gc_control.parent_win.get_active_jid() == jid:
|
||||
if gc_control.parent_win and gc_control.parent_win.get_active_jid() == jid:
|
||||
gc_control.set_subject(gc_control.subject)
|
||||
return
|
||||
|
||||
|
@ -991,6 +1015,9 @@ class Interface:
|
|||
win.set_values(array)
|
||||
if account in self.show_vcard_when_connect:
|
||||
self.show_vcard_when_connect.remove(account)
|
||||
jid = array['jid']
|
||||
if self.instances[account]['infos'].has_key(jid):
|
||||
self.instances[account]['infos'][jid].set_values(array)
|
||||
|
||||
def handle_event_vcard(self, account, vcard):
|
||||
# ('VCARD', account, data)
|
||||
|
@ -1026,6 +1053,9 @@ class Interface:
|
|||
|
||||
# Show avatar in roster or gc_roster
|
||||
gc_ctrl = self.msg_win_mgr.get_control(jid, account)
|
||||
if not gc_ctrl and \
|
||||
jid in self.minimized_controls[account]:
|
||||
gc_ctrl = self.minimized_controls[account][jid]
|
||||
if gc_ctrl and gc_ctrl.type_id == message_control.TYPE_GC:
|
||||
gc_ctrl.draw_avatar(resource)
|
||||
else:
|
||||
|
@ -1042,10 +1072,6 @@ class Interface:
|
|||
win = self.instances[account]['infos'][array[0] + '/' + array[1]]
|
||||
if win:
|
||||
c = gajim.contacts.get_contact(account, array[0], array[1])
|
||||
# c is a list when no resource is given. it probably means that contact
|
||||
# is offline, so only on Contact instance
|
||||
if isinstance(c, list) and len(c):
|
||||
c = c[0]
|
||||
if c: # c can be none if it's a gc contact
|
||||
c.last_status_time = time.localtime(time.time() - array[2])
|
||||
if array[3]:
|
||||
|
@ -1081,7 +1107,6 @@ class Interface:
|
|||
# PrivateChatControl
|
||||
control = self.msg_win_mgr.get_control(room_jid, account)
|
||||
if not control and \
|
||||
self.minimized_controls.has_key(account) and \
|
||||
room_jid in self.minimized_controls[account]:
|
||||
control = self.minimized_controls[account][room_jid]
|
||||
|
||||
|
@ -1090,8 +1115,11 @@ class Interface:
|
|||
if control:
|
||||
control.chg_contact_status(nick, show, status, array[4], array[5],
|
||||
array[6], array[7], array[8], array[9], array[10], array[11])
|
||||
if control and not control.parent_win:
|
||||
gajim.interface.roster.draw_contact(room_jid, account)
|
||||
|
||||
contact = gajim.contacts.\
|
||||
get_contact_with_highest_priority(account, room_jid)
|
||||
if contact:
|
||||
self.roster.draw_contact(room_jid, account)
|
||||
|
||||
ctrl = self.msg_win_mgr.get_control(fjid, account)
|
||||
|
||||
|
@ -1119,7 +1147,6 @@ class Interface:
|
|||
|
||||
gc_control = self.msg_win_mgr.get_control(room_jid, account)
|
||||
if not gc_control and \
|
||||
self.minimized_controls.has_key(account) and \
|
||||
room_jid in self.minimized_controls[account]:
|
||||
gc_control = self.minimized_controls[account][room_jid]
|
||||
|
||||
|
@ -1141,7 +1168,7 @@ class Interface:
|
|||
contact = gajim.contacts.\
|
||||
get_contact_with_highest_priority(account, room_jid)
|
||||
if contact:
|
||||
gajim.interface.roster.draw_contact(room_jid, account)
|
||||
self.roster.draw_contact(room_jid, account)
|
||||
|
||||
if self.remote_ctrl:
|
||||
self.remote_ctrl.raise_signal('GCMessage', (account, array))
|
||||
|
@ -1154,7 +1181,6 @@ class Interface:
|
|||
gc_control = self.msg_win_mgr.get_control(jid, account)
|
||||
|
||||
if not gc_control and \
|
||||
self.minimized_controls.has_key(account) and \
|
||||
jid in self.minimized_controls[account]:
|
||||
gc_control = self.minimized_controls[account][jid]
|
||||
|
||||
|
@ -1162,7 +1188,7 @@ class Interface:
|
|||
get_contact_with_highest_priority(account, jid)
|
||||
if contact:
|
||||
contact.status = array[1]
|
||||
gajim.interface.roster.draw_contact(jid, account)
|
||||
self.roster.draw_contact(jid, account)
|
||||
|
||||
if not gc_control:
|
||||
return
|
||||
|
@ -1197,6 +1223,46 @@ class Interface:
|
|||
self.instances[account]['gc_config'][room_jid] = \
|
||||
config.GroupchatConfigWindow(account, room_jid, array[1])
|
||||
|
||||
def handle_event_gc_config_change(self, account, array):
|
||||
#('GC_CONFIG_CHANGE', account, (jid, statusCode)) statuscode is a list
|
||||
# http://www.xmpp.org/extensions/xep-0045.html#roomconfig-notify
|
||||
# http://www.xmpp.org/extensions/xep-0045.html#registrar-statuscodes-init
|
||||
jid = array[0]
|
||||
statusCode = array[1]
|
||||
|
||||
gc_control = self.msg_win_mgr.get_control(jid, account)
|
||||
if not gc_control and \
|
||||
jid in self.minimized_controls[account]:
|
||||
gc_control = self.minimized_controls[account][jid]
|
||||
if not gc_control:
|
||||
return
|
||||
|
||||
changes = []
|
||||
if '100' in statusCode:
|
||||
# Can be a presence (see chg_contact_status in groupchat_contol.py)
|
||||
changes.append(_('Any occupant is allowed to see your full JID'))
|
||||
if '102' in statusCode:
|
||||
changes.append(_('Room now shows unavailable member'))
|
||||
if '103' in statusCode:
|
||||
changes.append(_('room now does not show unavailable members'))
|
||||
if '104' in statusCode:
|
||||
changes.append(\
|
||||
_('A non-privacy-related room configuration change has occurred'))
|
||||
if '170' in statusCode:
|
||||
# Can be a presence (see chg_contact_status in groupchat_contol.py)
|
||||
changes.append(_('Room logging is now enabled'))
|
||||
if '171' in statusCode:
|
||||
changes.append(_('Room logging is now disabled'))
|
||||
if '172' in statusCode:
|
||||
changes.append(_('Room is now non-anonymous'))
|
||||
if '173' in statusCode:
|
||||
changes.append(_('Room is now semi-anonymous'))
|
||||
if '174' in statusCode:
|
||||
changes.append(_('Room is now fully-anonymous'))
|
||||
|
||||
for change in changes:
|
||||
gc_control.print_conversation(change)
|
||||
|
||||
def handle_event_gc_affiliation(self, account, array):
|
||||
#('GC_AFFILIATION', account, (room_jid, affiliation, list)) list is list
|
||||
room_jid = array[0]
|
||||
|
@ -1204,6 +1270,29 @@ class Interface:
|
|||
self.instances[account]['gc_config'][room_jid].\
|
||||
affiliation_list_received(array[1], array[2])
|
||||
|
||||
def handle_event_gc_password_required(self, account, array):
|
||||
#('GC_PASSWORD_REQUIRED', account, (room_jid, nick))
|
||||
room_jid = array[0]
|
||||
nick = array[1]
|
||||
|
||||
def on_ok(text):
|
||||
gajim.connections[account].join_gc(nick, room_jid, text)
|
||||
gajim.gc_passwords[room_jid] = text
|
||||
|
||||
def on_cancel():
|
||||
# get and destroy window
|
||||
if room_jid in gajim.interface.minimized_controls[account]:
|
||||
self.roster.on_disconnect(None, room_jid, account)
|
||||
else:
|
||||
win = self.msg_win_mgr.get_window(room_jid, account)
|
||||
ctrl = win.get_control(room_jid, account)
|
||||
win.remove_tab(ctrl, 3)
|
||||
|
||||
dlg = dialogs.InputDialog(_('Password Required'),
|
||||
_('A Password is required to join the room %s. Please type it') % \
|
||||
room_jid, is_modal=False, ok_handler=on_ok, cancel_handler=on_cancel)
|
||||
dlg.input_entry.set_visibility(False)
|
||||
|
||||
def handle_event_gc_invitation(self, account, array):
|
||||
#('GC_INVITATION', (room_jid, jid_from, reason, password))
|
||||
jid = gajim.get_jid_without_resource(array[1])
|
||||
|
@ -1240,7 +1329,7 @@ class Interface:
|
|||
sub = array[2]
|
||||
ask = array[3]
|
||||
groups = array[4]
|
||||
contacts = gajim.contacts.get_contacts_from_jid(account, jid)
|
||||
contacts = gajim.contacts.get_contacts(account, jid)
|
||||
# contact removes us.
|
||||
if (not sub or sub == 'none') and (not ask or ask == 'none') and \
|
||||
not name and not groups:
|
||||
|
@ -1304,11 +1393,11 @@ class Interface:
|
|||
|
||||
# join autojoinable rooms
|
||||
for bm in bms:
|
||||
minimize = bm['minimize'] in ('1', 'true')
|
||||
if bm['autojoin'] in ('1', 'true'):
|
||||
self.roster.join_gc_room(account, bm['jid'], bm['nick'],
|
||||
bm['password'],
|
||||
minimize = gajim.config.get('minimize_autojoined_rooms'))
|
||||
|
||||
bm['password'], minimize = minimize)
|
||||
|
||||
def handle_event_file_send_error(self, account, array):
|
||||
jid = array[0]
|
||||
file_props = array[1]
|
||||
|
@ -1620,7 +1709,8 @@ class Interface:
|
|||
if self.instances[account].has_key('profile'):
|
||||
win = self.instances[account]['profile']
|
||||
win.vcard_published()
|
||||
for gc_control in self.msg_win_mgr.get_controls(message_control.TYPE_GC):
|
||||
for gc_control in self.msg_win_mgr.get_controls(message_control.TYPE_GC) + \
|
||||
self.minimized_controls[account].values():
|
||||
if gc_control.account == account:
|
||||
show = gajim.SHOW_LIST[gajim.connections[account].connected]
|
||||
status = gajim.connections[account].status
|
||||
|
@ -1648,7 +1738,8 @@ class Interface:
|
|||
if gajim.connections[account].connected == invisible_show:
|
||||
return
|
||||
# join already open groupchats
|
||||
for gc_control in self.msg_win_mgr.get_controls(message_control.TYPE_GC):
|
||||
for gc_control in self.msg_win_mgr.get_controls(message_control.TYPE_GC) + \
|
||||
self.minimized_controls[account].values():
|
||||
if account != gc_control.account:
|
||||
continue
|
||||
room_jid = gc_control.room_jid
|
||||
|
@ -2080,8 +2171,10 @@ class Interface:
|
|||
'GC_MSG': self.handle_event_gc_msg,
|
||||
'GC_SUBJECT': self.handle_event_gc_subject,
|
||||
'GC_CONFIG': self.handle_event_gc_config,
|
||||
'GC_CONFIG_CHANGE': self.handle_event_gc_config_change,
|
||||
'GC_INVITATION': self.handle_event_gc_invitation,
|
||||
'GC_AFFILIATION': self.handle_event_gc_affiliation,
|
||||
'GC_PASSWORD_REQUIRED': self.handle_event_gc_password_required,
|
||||
'BAD_PASSPHRASE': self.handle_event_bad_passphrase,
|
||||
'ROSTER_INFO': self.handle_event_roster_info,
|
||||
'BOOKMARKS': self.handle_event_bookmarks,
|
||||
|
@ -2138,6 +2231,12 @@ class Interface:
|
|||
jid = gajim.get_jid_without_resource(fjid)
|
||||
if type_ in ('printed_gc_msg', 'printed_marked_gc_msg', 'gc_msg'):
|
||||
w = self.msg_win_mgr.get_window(jid, account)
|
||||
if self.minimized_controls[account].has_key(jid):
|
||||
if not w:
|
||||
ctrl = self.minimized_controls[account][jid]
|
||||
w = self.msg_win_mgr.create_window(ctrl.contact, \
|
||||
ctrl.account, ctrl.type_id)
|
||||
self.roster.on_groupchat_maximized(None, jid, account)
|
||||
elif type_ in ('printed_chat', 'chat', ''):
|
||||
# '' is for log in/out notifications
|
||||
if self.msg_win_mgr.has_window(fjid, account):
|
||||
|
@ -2153,8 +2252,10 @@ class Interface:
|
|||
gajim.events.change_jid(account, fjid, jid)
|
||||
resource = None
|
||||
fjid = jid
|
||||
contact = gajim.contacts.get_contact(account, jid, resource)
|
||||
if not contact or isinstance(contact, list):
|
||||
contact = None
|
||||
if resource:
|
||||
contact = gajim.contacts.get_contact(account, jid, resource)
|
||||
if not contact:
|
||||
contact = highest_contact
|
||||
self.roster.new_chat(contact, account, resource = resource)
|
||||
w = self.msg_win_mgr.get_window(fjid, account)
|
||||
|
@ -2173,8 +2274,7 @@ class Interface:
|
|||
show = 'offline'
|
||||
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)
|
||||
self.roster.new_private_chat(gc_contact, account)
|
||||
w = self.msg_win_mgr.get_window(fjid, account)
|
||||
elif type_ in ('normal', 'file-request', 'file-request-error',
|
||||
'file-send-error', 'file-error', 'file-stopped', 'file-completed'):
|
||||
|
@ -2183,15 +2283,17 @@ class Interface:
|
|||
if not event:
|
||||
# default to jid without resource
|
||||
event = gajim.events.get_first_event(account, jid, type_)
|
||||
if not event:
|
||||
return
|
||||
# Open the window
|
||||
self.roster.open_event(account, jid, event)
|
||||
else:
|
||||
# Open the window
|
||||
self.roster.open_event(account, fjid, event)
|
||||
elif type_ == 'gmail':
|
||||
url = 'http://mail.google.com/mail?account_id=%s' % urllib.quote(
|
||||
gajim.config.get_per('accounts', account, 'name'))
|
||||
helpers.launch_browser_mailer('url', url)
|
||||
url=gajim.connections[account].gmail_url
|
||||
if url:
|
||||
helpers.launch_browser_mailer('url', url)
|
||||
elif type_ == 'gc-invitation':
|
||||
event = gajim.events.get_first_event(account, jid, type_)
|
||||
data = event.parameters
|
||||
|
@ -2217,6 +2319,8 @@ class Interface:
|
|||
# handler when an emoticon is clicked in emoticons_menu
|
||||
self.emoticon_menuitem_clicked = None
|
||||
self.minimized_controls = {}
|
||||
self.status_sent_to_users = {}
|
||||
self.status_sent_to_groups = {}
|
||||
self.default_colors = {
|
||||
'inmsgcolor': gajim.config.get('inmsgcolor'),
|
||||
'outmsgcolor': gajim.config.get('outmsgcolor'),
|
||||
|
@ -2252,7 +2356,7 @@ class Interface:
|
|||
#add default themes if there is not in the config file
|
||||
theme = gajim.config.get('roster_theme')
|
||||
if not theme in gajim.config.get_per('themes'):
|
||||
gajim.config.set('roster_theme', 'gtk+')
|
||||
gajim.config.set('roster_theme', _('default'))
|
||||
if len(gajim.config.get_per('themes')) == 0:
|
||||
d = ['accounttextcolor', 'accountbgcolor', 'accountfont',
|
||||
'accountfontattrs', 'grouptextcolor', 'groupbgcolor', 'groupfont',
|
||||
|
@ -2309,6 +2413,7 @@ class Interface:
|
|||
for a in gajim.connections:
|
||||
self.instances[a] = {'infos': {}, 'disco': {}, 'gc_config': {},
|
||||
'search': {}}
|
||||
self.minimized_controls[a] = {}
|
||||
gajim.contacts.add_account(a)
|
||||
gajim.groups[a] = {}
|
||||
gajim.gc_connected[a] = {}
|
||||
|
@ -2335,11 +2440,35 @@ class Interface:
|
|||
self.remote_ctrl = None
|
||||
|
||||
if gajim.config.get('networkmanager_support') and dbus_support.supported:
|
||||
try:
|
||||
import network_manager_listener
|
||||
except:
|
||||
import network_manager_listener
|
||||
if not network_manager_listener.supported:
|
||||
print >> sys.stderr, _('Network Manager support not available')
|
||||
|
||||
# Handle gnome screensaver
|
||||
if dbus_support.supported:
|
||||
def gnome_screensaver_ActiveChanged_cb(active):
|
||||
if not active:
|
||||
return
|
||||
for account in gajim.connections:
|
||||
if not gajim.sleeper_state.has_key(account) or \
|
||||
not gajim.sleeper_state[account]:
|
||||
continue
|
||||
if gajim.sleeper_state[account] == 'online':
|
||||
# we save out online status
|
||||
gajim.status_before_autoaway[account] = \
|
||||
gajim.connections[account].status
|
||||
# we go away (no auto status) [we pass True to auto param]
|
||||
auto_message = gajim.config.get('autoaway_message')
|
||||
if not auto_message:
|
||||
auto_message = gajim.connections[account].status
|
||||
self.roster.send_status(account, 'away', auto_message,
|
||||
auto=True)
|
||||
gajim.sleeper_state[account] = 'autoaway'
|
||||
|
||||
bus = dbus.SessionBus()
|
||||
bus.add_signal_receiver(gnome_screensaver_ActiveChanged_cb,
|
||||
'ActiveChanged', 'org.gnome.ScreenSaver')
|
||||
|
||||
self.show_vcard_when_connect = []
|
||||
|
||||
path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps', 'gajim.png')
|
||||
|
@ -2393,8 +2522,11 @@ class Interface:
|
|||
self.last_ftwindow_update = 0
|
||||
|
||||
gobject.timeout_add(100, self.autoconnect)
|
||||
gobject.timeout_add(200, self.process_connections)
|
||||
gobject.timeout_add(500, self.read_sleepy)
|
||||
if os.name == 'nt':
|
||||
gobject.timeout_add(200, self.process_connections)
|
||||
else:
|
||||
gobject.timeout_add(2000, self.process_connections)
|
||||
gobject.timeout_add(10000, self.read_sleepy)
|
||||
|
||||
if __name__ == '__main__':
|
||||
def sigint_cb(num, stack):
|
||||
|
|
|
@ -50,6 +50,7 @@ class GajimThemesWindow:
|
|||
self.italic_togglebutton = self.xml.get_widget('italic_togglebutton')
|
||||
self.themes_tree = self.xml.get_widget('themes_treeview')
|
||||
self.theme_options_vbox = self.xml.get_widget('theme_options_vbox')
|
||||
self.theme_options_table = self.xml.get_widget('theme_options_table')
|
||||
self.colorbuttons = {}
|
||||
for chatstate in ('inactive', 'composing', 'paused', 'gone',
|
||||
'muc_msg', 'muc_directed_msg'):
|
||||
|
@ -67,6 +68,7 @@ class GajimThemesWindow:
|
|||
self.current_theme = gajim.config.get('roster_theme')
|
||||
self.no_update = False
|
||||
self.fill_themes_treeview()
|
||||
self.select_active_theme()
|
||||
self.current_option = self.options[0]
|
||||
self.set_theme_options(self.current_theme, self.current_option)
|
||||
|
||||
|
@ -81,6 +83,8 @@ class GajimThemesWindow:
|
|||
return True # do NOT destroy the window
|
||||
|
||||
def on_close_button_clicked(self, widget):
|
||||
if gajim.interface.instances.has_key('preferences'):
|
||||
gajim.interface.instances['preferences'].update_theme_list()
|
||||
self.window.hide()
|
||||
|
||||
def on_theme_cell_edited(self, cell, row, new_name):
|
||||
|
@ -90,6 +94,11 @@ class GajimThemesWindow:
|
|||
new_name = new_name.decode('utf-8')
|
||||
if old_name == new_name:
|
||||
return
|
||||
if old_name == 'default':
|
||||
dialogs.ErrorDialog(
|
||||
_('You cannot make changes to the default theme'),
|
||||
_('Please create a clean new theme with your desired name.'))
|
||||
return
|
||||
new_config_name = new_name.replace(' ', '_')
|
||||
if new_config_name in gajim.config.get_per('themes'):
|
||||
return
|
||||
|
@ -110,28 +119,31 @@ class GajimThemesWindow:
|
|||
self.current_theme = new_name
|
||||
|
||||
def fill_themes_treeview(self):
|
||||
self.xml.get_widget('remove_button').set_sensitive(False)
|
||||
self.theme_options_vbox.set_sensitive(False)
|
||||
model = self.themes_tree.get_model()
|
||||
model.clear()
|
||||
for config_theme in gajim.config.get_per('themes'):
|
||||
theme = config_theme.replace('_', ' ')
|
||||
iter = model.append([theme])
|
||||
if gajim.config.get('roster_theme') == config_theme:
|
||||
self.themes_tree.get_selection().select_iter(iter)
|
||||
self.xml.get_widget('remove_button').set_sensitive(True)
|
||||
self.theme_options_vbox.set_sensitive(True)
|
||||
|
||||
def select_active_theme(self):
|
||||
model = self.themes_tree.get_model()
|
||||
iter = model.get_iter_root()
|
||||
active_theme = gajim.config.get('roster_theme')
|
||||
active_theme = gajim.config.get('roster_theme').replace('_', ' ')
|
||||
while iter:
|
||||
theme = model[iter][0]
|
||||
if theme == active_theme:
|
||||
self.themes_tree.get_selection().select_iter(iter)
|
||||
self.xml.get_widget('remove_button').set_sensitive(True)
|
||||
self.theme_options_vbox.set_sensitive(True)
|
||||
self.theme_options_table.set_sensitive(True)
|
||||
if active_theme == 'default':
|
||||
self.xml.get_widget('remove_button').set_sensitive(False)
|
||||
self.theme_options_vbox.set_sensitive(False)
|
||||
self.theme_options_table.set_sensitive(False)
|
||||
else:
|
||||
self.xml.get_widget('remove_button').set_sensitive(True)
|
||||
self.theme_options_vbox.set_sensitive(True)
|
||||
self.theme_options_table.set_sensitive(True)
|
||||
break
|
||||
iter = model.iter_next(iter)
|
||||
|
||||
|
@ -140,12 +152,19 @@ class GajimThemesWindow:
|
|||
selected = self.themes_tree.get_selection().get_selected_rows()
|
||||
if not iter or selected[1] == []:
|
||||
self.theme_options_vbox.set_sensitive(False)
|
||||
self.theme_options_table.set_sensitive(False)
|
||||
return
|
||||
self.xml.get_widget('remove_button').set_sensitive(True)
|
||||
self.theme_options_vbox.set_sensitive(True)
|
||||
self.current_theme = model.get_value(iter, 0).decode('utf-8')
|
||||
self.current_theme = self.current_theme.replace(' ', '_')
|
||||
self.set_theme_options(self.current_theme)
|
||||
if self.current_theme == 'default':
|
||||
self.xml.get_widget('remove_button').set_sensitive(False)
|
||||
self.theme_options_vbox.set_sensitive(False)
|
||||
self.theme_options_table.set_sensitive(False)
|
||||
else:
|
||||
self.xml.get_widget('remove_button').set_sensitive(True)
|
||||
self.theme_options_vbox.set_sensitive(True)
|
||||
self.theme_options_table.set_sensitive(True)
|
||||
|
||||
def on_add_button_clicked(self, widget):
|
||||
model = self.themes_tree.get_model()
|
||||
|
@ -173,6 +192,8 @@ class GajimThemesWindow:
|
|||
_('Please first choose another for your current theme.'))
|
||||
return
|
||||
self.theme_options_vbox.set_sensitive(False)
|
||||
self.theme_options_table.set_sensitive(False)
|
||||
self.xml.get_widget('remove_button').set_sensitive(False)
|
||||
gajim.config.del_per('themes', self.current_theme)
|
||||
model.remove(iter)
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
## Norman Rasmussen <norman@rasmussen.co.za>
|
||||
## Copyright (C) 2006 Travis Shirk <travis@pobox.com>
|
||||
## Copyright (C) 2005-2007 Nikos Kouremenos <kourem@gmail.com>
|
||||
## Copyright (C) 2007 Julien Pivotto <roidelapluie@gmail.com>
|
||||
## Copyright (C) 2007 Lukas Petrovicky <lukas@petrovicky.net>
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published
|
||||
|
@ -63,6 +65,12 @@ def tree_cell_data_func(column, renderer, model, iter, tv=None):
|
|||
# cell data func is global, because we don't want it to keep
|
||||
# reference to GroupchatControl instance (self)
|
||||
theme = gajim.config.get('roster_theme')
|
||||
# allocate space for avatar only if needed
|
||||
if isinstance(renderer, gtk.CellRendererPixbuf):
|
||||
if model[iter][C_AVATAR]:
|
||||
renderer.set_property('visible', True)
|
||||
else:
|
||||
renderer.set_property('visible', False)
|
||||
if model.iter_parent(iter):
|
||||
bgcolor = gajim.config.get_per('themes', theme, 'contactbgcolor')
|
||||
if bgcolor:
|
||||
|
@ -97,12 +105,14 @@ def tree_cell_data_func(column, renderer, model, iter, tv=None):
|
|||
class PrivateChatControl(ChatControl):
|
||||
TYPE_ID = message_control.TYPE_PM
|
||||
|
||||
def __init__(self, parent_win, gc_contact, contact, acct):
|
||||
def __init__(self, parent_win, gc_contact, contact, account):
|
||||
room_jid = contact.jid.split('/')[0]
|
||||
room_ctrl = gajim.interface.msg_win_mgr.get_control(room_jid, acct)
|
||||
room_ctrl = gajim.interface.msg_win_mgr.get_control(room_jid, account)
|
||||
if gajim.interface.minimized_controls[account].has_key(room_jid):
|
||||
room_ctrl = gajim.interface.minimized_controls[account][room_jid]
|
||||
self.room_name = room_ctrl.name
|
||||
self.gc_contact = gc_contact
|
||||
ChatControl.__init__(self, parent_win, contact, acct)
|
||||
ChatControl.__init__(self, parent_win, contact, account)
|
||||
self.TYPE_ID = 'pm'
|
||||
|
||||
def send_message(self, message):
|
||||
|
@ -127,7 +137,7 @@ class PrivateChatControl(ChatControl):
|
|||
return
|
||||
|
||||
ChatControl.send_message(self, message)
|
||||
|
||||
|
||||
def update_ui(self):
|
||||
if self.contact.show == 'offline':
|
||||
self.got_disconnected()
|
||||
|
@ -183,9 +193,8 @@ class GroupchatControl(ChatControlBase):
|
|||
self.nick = contact.name
|
||||
self.name = self.room_jid.split('@')[0]
|
||||
|
||||
hide_chat_buttons_always = gajim.config.get(
|
||||
'always_hide_groupchat_buttons')
|
||||
self.chat_buttons_set_visible(hide_chat_buttons_always)
|
||||
compact_view = gajim.config.get('compact_view')
|
||||
self.chat_buttons_set_visible(compact_view)
|
||||
self.widget_set_visible(self.xml.get_widget('banner_eventbox'),
|
||||
gajim.config.get('hide_groupchat_banner'))
|
||||
self.widget_set_visible(self.xml.get_widget('list_scrolledwindow'),
|
||||
|
@ -237,18 +246,14 @@ class GroupchatControl(ChatControlBase):
|
|||
self._on_change_subject_menuitem_activate)
|
||||
self.handlers[id] = self.change_subject_menuitem
|
||||
|
||||
self.compact_view_menuitem = xm.get_widget('compact_view_menuitem')
|
||||
id = self.compact_view_menuitem.connect('activate',
|
||||
self._on_compact_view_menuitem_activate)
|
||||
self.handlers[id] = self.compact_view_menuitem
|
||||
|
||||
widget = xm.get_widget('history_menuitem')
|
||||
id = widget.connect('activate', self._on_history_menuitem_activate)
|
||||
self.handlers[id] = widget
|
||||
|
||||
widget = xm.get_widget('minimize_menuitem')
|
||||
id = widget.connect('activate', self._on_minimize_menuitem_activate)
|
||||
self.handlers[id] = widget
|
||||
self.minimize_menuitem = xm.get_widget('minimize_menuitem')
|
||||
id = self.minimize_menuitem.connect('toggled',
|
||||
self.on_minimize_menuitem_toggled)
|
||||
self.handlers[id] = self.minimize_menuitem
|
||||
|
||||
self.gc_popup_menu = xm.get_widget('gc_control_popup_menu')
|
||||
|
||||
|
@ -285,14 +290,8 @@ class GroupchatControl(ChatControlBase):
|
|||
# first one img, second one text, third is sec pixbuf
|
||||
column = gtk.TreeViewColumn()
|
||||
|
||||
renderer_pixbuf = gtk.CellRendererPixbuf() # avatar image
|
||||
column.pack_start(renderer_pixbuf, expand = False)
|
||||
column.add_attribute(renderer_pixbuf, 'pixbuf', C_AVATAR)
|
||||
column.set_cell_data_func(renderer_pixbuf, tree_cell_data_func,
|
||||
self.list_treeview)
|
||||
renderer_pixbuf.set_property('xalign', 1) # align pixbuf to the right
|
||||
|
||||
renderer_image = cell_renderer_image.CellRendererImage(0, 0) # status img
|
||||
renderer_image.set_property('width', 26)
|
||||
column.pack_start(renderer_image, expand = False)
|
||||
column.add_attribute(renderer_image, 'image', C_IMG)
|
||||
column.set_cell_data_func(renderer_image, tree_cell_data_func,
|
||||
|
@ -301,9 +300,17 @@ class GroupchatControl(ChatControlBase):
|
|||
renderer_text = gtk.CellRendererText() # nickname
|
||||
column.pack_start(renderer_text, expand = True)
|
||||
column.add_attribute(renderer_text, 'markup', C_TEXT)
|
||||
renderer_text.set_property("ellipsize", pango.ELLIPSIZE_END)
|
||||
column.set_cell_data_func(renderer_text, tree_cell_data_func,
|
||||
self.list_treeview)
|
||||
|
||||
renderer_pixbuf = gtk.CellRendererPixbuf() # avatar image
|
||||
column.pack_start(renderer_pixbuf, expand = False)
|
||||
column.add_attribute(renderer_pixbuf, 'pixbuf', C_AVATAR)
|
||||
column.set_cell_data_func(renderer_pixbuf, tree_cell_data_func,
|
||||
self.list_treeview)
|
||||
renderer_pixbuf.set_property('xalign', 1) # align pixbuf to the right
|
||||
|
||||
self.list_treeview.append_column(column)
|
||||
|
||||
# workaround to avoid gtk arrows to be shown
|
||||
|
@ -483,10 +490,10 @@ class GroupchatControl(ChatControlBase):
|
|||
self.name_label.set_markup(text)
|
||||
|
||||
def prepare_context_menu(self):
|
||||
'''sets compact view menuitem active state
|
||||
sets sensitivity state for configure_room'''
|
||||
# Check compact view menuitem
|
||||
self.compact_view_menuitem.set_active(self.hide_chat_buttons_current)
|
||||
'''sets sensitivity state for configure_room'''
|
||||
if self.contact.jid in gajim.config.get_per('accounts', self.account,
|
||||
'minimized_gc').split(' '):
|
||||
self.minimize_menuitem.set_active(True)
|
||||
if gajim.gc_connected[self.account][self.room_jid]:
|
||||
c = gajim.contacts.get_gc_contact(self.account, self.room_jid,
|
||||
self.nick)
|
||||
|
@ -515,11 +522,13 @@ class GroupchatControl(ChatControlBase):
|
|||
else:
|
||||
# message from someone
|
||||
if has_timestamp:
|
||||
self.print_old_conversation(msg, nick, tim, xhtml)
|
||||
# don't print xhtml if it's an old message.
|
||||
# Like that xhtml messages are grayed too.
|
||||
self.print_old_conversation(msg, nick, tim, None)
|
||||
else:
|
||||
self.print_conversation(msg, nick, tim, xhtml)
|
||||
|
||||
def on_private_message(self, nick, msg, tim, xhtml):
|
||||
def on_private_message(self, nick, msg, tim, xhtml, msg_id = None):
|
||||
# Do we have a queue?
|
||||
fjid = self.room_jid + '/' + nick
|
||||
no_queue = len(gajim.events.get_events(self.account, fjid)) == 0
|
||||
|
@ -531,7 +540,7 @@ class GroupchatControl(ChatControlBase):
|
|||
return
|
||||
|
||||
event = gajim.events.create_event('pm', (msg, '', 'incoming', tim,
|
||||
False, '', None, xhtml))
|
||||
False, '', msg_id, xhtml))
|
||||
gajim.events.add_event(self.account, fjid, event)
|
||||
|
||||
autopopup = gajim.config.get('autopopup')
|
||||
|
@ -544,8 +553,8 @@ class GroupchatControl(ChatControlBase):
|
|||
model = self.list_treeview.get_model()
|
||||
state_images =\
|
||||
gajim.interface.roster.get_appropriate_state_images(
|
||||
self.room_jid, icon_name = 'message')
|
||||
image = state_images['message']
|
||||
self.room_jid, icon_name = 'event')
|
||||
image = state_images['event']
|
||||
model[iter][C_IMG] = image
|
||||
if self.parent_win:
|
||||
self.parent_win.show_title()
|
||||
|
@ -556,7 +565,10 @@ class GroupchatControl(ChatControlBase):
|
|||
self.list_treeview.expand_row(path[0:1], False)
|
||||
self.list_treeview.scroll_to_cell(path)
|
||||
self.list_treeview.set_cursor(path)
|
||||
gajim.interface.roster.draw_contact(self.room_jid, self.account)
|
||||
contact = gajim.contacts.get_contact_with_highest_priority(self.account, \
|
||||
self.room_jid)
|
||||
if contact:
|
||||
gajim.interface.roster.draw_contact(self.room_jid, self.account)
|
||||
|
||||
def get_contact_iter(self, nick):
|
||||
model = self.list_treeview.get_model()
|
||||
|
@ -662,8 +674,7 @@ class GroupchatControl(ChatControlBase):
|
|||
other_tags_for_text.append('gc_nickname_color_' + \
|
||||
str(self.gc_custom_colors[contact]))
|
||||
|
||||
if self.parent_win:
|
||||
self.check_and_possibly_add_focus_out_line()
|
||||
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, xhtml = xhtml)
|
||||
|
@ -697,7 +708,7 @@ class GroupchatControl(ChatControlBase):
|
|||
if self.needs_visual_notification(text):
|
||||
highlight = True
|
||||
if gajim.config.get_per('soundevents', 'muc_message_highlight',
|
||||
'enabled'):
|
||||
'enabled'):
|
||||
sound = 'highlight'
|
||||
|
||||
# Is it a history message? Don't want sound-floods when we join.
|
||||
|
@ -712,7 +723,7 @@ class GroupchatControl(ChatControlBase):
|
|||
it removes previous line first'''
|
||||
|
||||
win = gajim.interface.msg_win_mgr.get_window(self.room_jid, self.account)
|
||||
if self.room_jid == win.get_active_jid() and\
|
||||
if win and self.room_jid == win.get_active_jid() and\
|
||||
win.window.get_property('has-toplevel-focus') and\
|
||||
self.parent_win.get_active_control() == self:
|
||||
# it's the current room and it's the focused window.
|
||||
|
@ -780,7 +791,8 @@ class GroupchatControl(ChatControlBase):
|
|||
gc_contact.show = 'offline'
|
||||
gc_contact.status = ''
|
||||
ctrl.update_ui()
|
||||
ctrl.parent_win.redraw_tab(ctrl)
|
||||
if ctrl.parent_win:
|
||||
ctrl.parent_win.redraw_tab(ctrl)
|
||||
gajim.contacts.remove_gc_contact(self.account, gc_contact)
|
||||
gajim.gc_connected[self.account][self.room_jid] = False
|
||||
ChatControlBase.got_disconnected(self)
|
||||
|
@ -795,6 +807,8 @@ class GroupchatControl(ChatControlBase):
|
|||
self.add_contact_to_roster(nick, gc_contact.show, gc_contact.role,
|
||||
gc_contact.affiliation, gc_contact.status,
|
||||
gc_contact.jid)
|
||||
# Recalculate column width for ellipsizin
|
||||
self.list_treeview.columns_autosize()
|
||||
|
||||
def on_send_pm(self, widget = None, model = None, iter = None, nick = None,
|
||||
msg = None):
|
||||
|
@ -809,6 +823,11 @@ class GroupchatControl(ChatControlBase):
|
|||
gajim.interface.msg_win_mgr.get_control(fjid, self.account).\
|
||||
send_message(msg)
|
||||
|
||||
def on_send_file(self, widget, gc_contact):
|
||||
'''sends a file to a contact in the room'''
|
||||
gajim.interface.instances['file_transfers'].show_file_send_request(
|
||||
self.account, gc_contact)
|
||||
|
||||
def draw_contact(self, nick, selected=False, focus=False):
|
||||
iter = self.get_contact_iter(nick)
|
||||
if not iter:
|
||||
|
@ -818,7 +837,7 @@ class GroupchatControl(ChatControlBase):
|
|||
nick)
|
||||
state_images = gajim.interface.roster.jabber_state_images['16']
|
||||
if len(gajim.events.get_events(self.account, self.room_jid + '/' + nick)):
|
||||
image = state_images['message']
|
||||
image = state_images['event']
|
||||
else:
|
||||
image = state_images[gc_contact.show]
|
||||
|
||||
|
@ -867,66 +886,99 @@ class GroupchatControl(ChatControlBase):
|
|||
affiliation = 'none'
|
||||
fake_jid = self.room_jid + '/' + nick
|
||||
newly_created = False
|
||||
|
||||
# statusCode
|
||||
# http://www.xmpp.org/extensions/xep-0045.html#registrar-statuscodes-init
|
||||
if statusCode:
|
||||
if '100' in statusCode:
|
||||
# Can be a message (see handle_event_gc_config_change in gajim.py)
|
||||
self.print_conversation(\
|
||||
_('Any occupant is allowed to see your full JID'))
|
||||
if '170' in statusCode:
|
||||
# Can be a message (see handle_event_gc_config_change in gajim.py)
|
||||
self.print_conversation(_('Room logging is enabled'))
|
||||
if '201' in statusCode:
|
||||
self.print_conversation(_('A new room has been created'))
|
||||
if '210' in statusCode:
|
||||
self.print_conversation(\
|
||||
_('The server has assigned or modified your roomnick'))
|
||||
|
||||
if show in ('offline', 'error'):
|
||||
if statusCode == '307':
|
||||
if actor is None: # do not print 'kicked by None'
|
||||
s = _('%(nick)s has been kicked: %(reason)s') % {
|
||||
if statusCode:
|
||||
if '307' in statusCode:
|
||||
if actor is None: # do not print 'kicked by None'
|
||||
s = _('%(nick)s has been kicked: %(reason)s') % {
|
||||
'nick': nick,
|
||||
'reason': reason }
|
||||
else:
|
||||
s = _('%(nick)s has been kicked by %(who)s: %(reason)s') % {
|
||||
'nick': nick,
|
||||
'who': actor,
|
||||
'reason': reason }
|
||||
self.print_conversation(s, 'info', tim = tim)
|
||||
elif '301' in statusCode:
|
||||
if actor is None: # do not print 'banned by None'
|
||||
s = _('%(nick)s has been banned: %(reason)s') % {
|
||||
'nick': nick,
|
||||
'reason': reason }
|
||||
else:
|
||||
s = _('%(nick)s has been banned by %(who)s: %(reason)s') % {
|
||||
'nick': nick,
|
||||
'who': actor,
|
||||
'reason': reason }
|
||||
self.print_conversation(s, 'info', tim = tim)
|
||||
elif '303' in statusCode: # Someone changed his or her nick
|
||||
if new_nick == self.nick: # We changed our nick
|
||||
s = _('You are now known as %s') % new_nick
|
||||
else:
|
||||
s = _('%s is now known as %s') % (nick, new_nick)
|
||||
# We add new nick to muc roster here, so we don't see
|
||||
# that "new_nick has joined the room" when he just changed nick.
|
||||
# add_contact_to_roster will be called a second time
|
||||
# after that, but that doesn't hurt
|
||||
self.add_contact_to_roster(new_nick, show, role, affiliation,
|
||||
status, jid)
|
||||
if nick in self.attention_list:
|
||||
self.attention_list.remove(nick)
|
||||
# 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)
|
||||
puny_new_nick = helpers.sanitize_filename(new_nick)
|
||||
old_path = os.path.join(gajim.VCARD_PATH, puny_jid, puny_nick)
|
||||
new_path = os.path.join(gajim.VCARD_PATH, puny_jid, puny_new_nick)
|
||||
files = {old_path: new_path}
|
||||
path = os.path.join(gajim.AVATAR_PATH, puny_jid)
|
||||
# possible extensions
|
||||
for ext in ('.png', '.jpeg', '_notif_size_bw.png',
|
||||
'_notif_size_colored.png'):
|
||||
files[os.path.join(path, puny_nick + ext)] = \
|
||||
os.path.join(path, puny_new_nick + ext)
|
||||
for old_file in files:
|
||||
if os.path.exists(old_file):
|
||||
if os.path.exists(files[old_file]):
|
||||
# Windows require this
|
||||
os.remove(files[old_file])
|
||||
os.rename(old_file, files[old_file])
|
||||
self.print_conversation(s, 'info', tim)
|
||||
elif '321' in statusCode:
|
||||
s = _('%(nick)s has been removed from the room (%(reason)s)') % {
|
||||
'nick': nick, 'reason': _('affiliation changed') }
|
||||
self.print_conversation(s, 'info', tim = tim)
|
||||
elif '322' in statusCode:
|
||||
s = _('%(nick)s has been removed from the room (%(reason)s)') % {
|
||||
'nick': nick,
|
||||
'reason': reason }
|
||||
else:
|
||||
s = _('%(nick)s has been kicked by %(who)s: %(reason)s') % {
|
||||
'reason': _('room configuration changed to members-only') }
|
||||
self.print_conversation(s, 'info', tim = tim)
|
||||
elif '332' in statusCode:
|
||||
s = _('%(nick)s has been removed from the room (%(reason)s)') % {
|
||||
'nick': nick,
|
||||
'who': actor,
|
||||
'reason': reason }
|
||||
self.print_conversation(s, 'info', tim = tim)
|
||||
elif statusCode == '301':
|
||||
if actor is None: # do not print 'banned by None'
|
||||
s = _('%(nick)s has been banned: %(reason)s') % {
|
||||
'nick': nick,
|
||||
'reason': reason }
|
||||
else:
|
||||
s = _('%(nick)s has been banned by %(who)s: %(reason)s') % {
|
||||
'nick': nick,
|
||||
'who': actor,
|
||||
'reason': reason }
|
||||
self.print_conversation(s, 'info', tim = tim)
|
||||
elif statusCode == '303': # Someone changed his or her nick
|
||||
if nick == self.nick: # We changed our nick
|
||||
self.nick = new_nick
|
||||
s = _('You are now known as %s') % new_nick
|
||||
else:
|
||||
s = _('%s is now known as %s') % (nick, new_nick)
|
||||
# We add new nick to muc roster here, so we don't see
|
||||
# that "new_nick has joined the room" when he just changed nick.
|
||||
# add_contact_to_roster will be called a second time
|
||||
# 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)
|
||||
puny_new_nick = helpers.sanitize_filename(new_nick)
|
||||
old_path = os.path.join(gajim.VCARD_PATH, puny_jid, puny_nick)
|
||||
new_path = os.path.join(gajim.VCARD_PATH, puny_jid, puny_new_nick)
|
||||
files = {old_path: new_path}
|
||||
path = os.path.join(gajim.AVATAR_PATH, puny_jid)
|
||||
# possible extensions
|
||||
for ext in ('.png', '.jpeg', '_notif_size_bw.png',
|
||||
'_notif_size_colored.png'):
|
||||
files[os.path.join(path, puny_nick + ext)] = \
|
||||
os.path.join(path, puny_new_nick + ext)
|
||||
for old_file in files:
|
||||
if os.path.exists(old_file):
|
||||
if os.path.exists(files[old_file]):
|
||||
# Windows require this
|
||||
os.remove(files[old_file])
|
||||
os.rename(old_file, files[old_file])
|
||||
self.print_conversation(s, 'info', tim)
|
||||
elif statusCode == 'destroyed': # Room has been destroyed
|
||||
self.print_conversation(reason, 'info', tim)
|
||||
'reason': _('system shutdown') }
|
||||
self.print_conversation(s, 'info', tim = tim)
|
||||
elif 'destroyed' in statusCode: # Room has been destroyed
|
||||
self.print_conversation(reason, 'info', tim)
|
||||
|
||||
if len(gajim.events.get_events(self.account, fake_jid)) == 0:
|
||||
self.remove_contact(nick)
|
||||
|
@ -934,7 +986,8 @@ class GroupchatControl(ChatControlBase):
|
|||
c = gajim.contacts.get_gc_contact(self.account, self.room_jid, nick)
|
||||
c.show = show
|
||||
c.status = status
|
||||
if nick == self.nick and statusCode != '303': # We became offline
|
||||
if nick == self.nick and (not statusCode or \
|
||||
'303' not in statusCode): # We became offline
|
||||
self.got_disconnected()
|
||||
contact = gajim.contacts.\
|
||||
get_contact_with_highest_priority(self.account, self.room_jid)
|
||||
|
@ -948,7 +1001,7 @@ class GroupchatControl(ChatControlBase):
|
|||
iter = self.add_contact_to_roster(nick, show, role, affiliation,
|
||||
status, jid)
|
||||
newly_created = True
|
||||
if statusCode == '201': # We just created the room
|
||||
if statusCode and '201' in statusCode: # We just created the room
|
||||
gajim.connections[self.account].request_gc_config(self.room_jid)
|
||||
else:
|
||||
gc_c = gajim.contacts.get_gc_contact(self.account, self.room_jid,
|
||||
|
@ -965,7 +1018,9 @@ class GroupchatControl(ChatControlBase):
|
|||
real_jid = fake_jid
|
||||
if con.vcard_shas.has_key(fake_jid):
|
||||
if avatar_sha != con.vcard_shas[fake_jid]:
|
||||
con.request_vcard(real_jid, fake_jid)
|
||||
server = gajim.get_server_from_jid(self.room_jid)
|
||||
if not server.startswith('irc'):
|
||||
con.request_vcard(real_jid, fake_jid)
|
||||
else:
|
||||
cached_vcard = con.get_cached_vcard(fake_jid, True)
|
||||
if cached_vcard and cached_vcard.has_key('PHOTO') and \
|
||||
|
@ -976,7 +1031,9 @@ class GroupchatControl(ChatControlBase):
|
|||
if cached_sha != avatar_sha:
|
||||
# avatar has been updated
|
||||
# sha in mem will be updated later
|
||||
con.request_vcard(real_jid, fake_jid)
|
||||
server = gajim.get_server_from_jid(self.room_jid)
|
||||
if not server.startswith('irc'):
|
||||
con.request_vcard(real_jid, fake_jid)
|
||||
else:
|
||||
# save sha in mem NOW
|
||||
con.vcard_shas[fake_jid] = avatar_sha
|
||||
|
@ -997,7 +1054,8 @@ class GroupchatControl(ChatControlBase):
|
|||
if self.parent_win:
|
||||
self.parent_win.redraw_tab(self)
|
||||
if (time.time() - self.room_creation) > 30 and \
|
||||
nick != self.nick and statusCode != '303':
|
||||
nick != self.nick and (not statusCode or \
|
||||
'303' not in statusCode):
|
||||
st = ''
|
||||
print_status = None
|
||||
for bookmark in gajim.connections[self.account].bookmarks:
|
||||
|
@ -1011,8 +1069,11 @@ class GroupchatControl(ChatControlBase):
|
|||
# delete ressource
|
||||
simple_jid = gajim.get_jid_without_resource(jid)
|
||||
nick_jid += ' (%s)' % simple_jid
|
||||
if show == 'offline':
|
||||
if nick in self.attention_list:
|
||||
self.attention_list.remove(nick)
|
||||
if show == 'offline' and print_status in ('all', 'in_and_out') and \
|
||||
statusCode != '307':
|
||||
(not statusCode or '307' not in statusCode):
|
||||
st = _('%s has left') % nick_jid
|
||||
if reason:
|
||||
st += ' [%s]' % reason
|
||||
|
@ -1127,6 +1188,7 @@ class GroupchatControl(ChatControlBase):
|
|||
nick = message_array[0]
|
||||
nick = helpers.parse_resource(nick)
|
||||
gajim.connections[self.account].join_gc(nick, self.room_jid, None)
|
||||
self.nick = nick
|
||||
self.clear(self.msg_textview)
|
||||
else:
|
||||
self.get_command_help(command)
|
||||
|
@ -1408,9 +1470,31 @@ class GroupchatControl(ChatControlBase):
|
|||
nick = instance.input_entry.get_text().decode('utf-8')
|
||||
nick = helpers.parse_resource(nick)
|
||||
gajim.connections[self.account].join_gc(nick, self.room_jid, None)
|
||||
self.nick = nick
|
||||
instance = dialogs.InputDialog(title, prompt, proposed_nick,
|
||||
is_modal = False, ok_handler = on_ok)
|
||||
|
||||
def minimize(self, status='offline'):
|
||||
# Minimize it
|
||||
win = gajim.interface.msg_win_mgr.get_window(self.contact.jid,
|
||||
self.account)
|
||||
ctrl = win.get_control(self.contact.jid, self.account)
|
||||
|
||||
ctrl_page = win.notebook.page_num(ctrl.widget)
|
||||
control = win.notebook.get_nth_page(ctrl_page)
|
||||
|
||||
win.notebook.remove_page(ctrl_page)
|
||||
control.unparent()
|
||||
ctrl.parent_win = None
|
||||
|
||||
gajim.interface.minimized_controls[self.account][self.contact.jid] = \
|
||||
ctrl
|
||||
|
||||
del win._controls[self.account][self.contact.jid]
|
||||
|
||||
gajim.interface.roster.add_groupchat_to_roster(self.account,
|
||||
self.contact.jid, status = self.subject)
|
||||
|
||||
def shutdown(self, status='offline'):
|
||||
gajim.connections[self.account].send_gc_status(self.nick, self.room_jid,
|
||||
show='offline', status=status)
|
||||
|
@ -1441,13 +1525,15 @@ class GroupchatControl(ChatControlBase):
|
|||
gajim.events.remove_events(self.account, self.room_jid)
|
||||
|
||||
def allow_shutdown(self, method):
|
||||
'''If check_selection is True, '''
|
||||
if self.contact.jid in gajim.config.get_per('accounts', self.account,
|
||||
'minimized_gc').split(' '):
|
||||
return 'minimize'
|
||||
if method == self.parent_win.CLOSE_ESC:
|
||||
model, iter = self.list_treeview.get_selection().get_selected()
|
||||
if iter:
|
||||
self.list_treeview.get_selection().unselect_all()
|
||||
return False
|
||||
retval = True
|
||||
return 'no'
|
||||
retval = 'yes'
|
||||
includes = gajim.config.get('confirm_close_muc_rooms').split(' ')
|
||||
excludes = gajim.config.get('noconfirm_close_muc_rooms').split(' ')
|
||||
# whether to ask for comfirmation before closing muc
|
||||
|
@ -1463,7 +1549,7 @@ class GroupchatControl(ChatControlBase):
|
|||
_('Do _not ask me again'))
|
||||
|
||||
if dialog.get_response() != gtk.RESPONSE_OK:
|
||||
retval = False
|
||||
retval = 'no'
|
||||
|
||||
if dialog.is_checked(): # user does not want to be asked again
|
||||
gajim.config.set('confirm_close_muc', False)
|
||||
|
@ -1546,6 +1632,7 @@ class GroupchatControl(ChatControlBase):
|
|||
'name': self.name,
|
||||
'jid': self.room_jid,
|
||||
'autojoin': '0',
|
||||
'minimize': '0',
|
||||
'password': '',
|
||||
'nick': self.nick
|
||||
}
|
||||
|
@ -1566,8 +1653,25 @@ class GroupchatControl(ChatControlBase):
|
|||
_('Bookmark has been added successfully'),
|
||||
_('You can manage your bookmarks via Actions menu in your roster.'))
|
||||
|
||||
def _on_drag_data_received(self, widget, context, x, y, selection,
|
||||
target_type, timestamp):
|
||||
# Invite contact to groupchat
|
||||
treeview = gajim.interface.roster.tree
|
||||
model = treeview.get_model()
|
||||
if not selection.data:
|
||||
return
|
||||
data = selection.data
|
||||
path = treeview.get_selection().get_selected_rows()[1][0]
|
||||
iter = model.get_iter(path)
|
||||
type = model[iter][2]
|
||||
account = model[iter][4].decode('utf-8')
|
||||
if type != 'contact': # source is not a contact
|
||||
return
|
||||
contact_jid = data.decode('utf-8')
|
||||
gajim.connections[self.account].send_invite(self.room_jid, contact_jid)
|
||||
|
||||
def handle_message_textview_mykey_press(self, widget, event_keyval,
|
||||
event_keymod):
|
||||
event_keymod):
|
||||
# NOTE: handles mykeypress which is custom signal connected to this
|
||||
# CB in new_room(). for this singal see message_textview.py
|
||||
|
||||
|
@ -1800,13 +1904,21 @@ class GroupchatControl(ChatControlBase):
|
|||
item = xml.get_widget('add_to_roster_menuitem')
|
||||
if not jid:
|
||||
item.set_sensitive(False)
|
||||
id = item.connect('activate', self.on_add_to_roster, jid)
|
||||
self.handlers[id] = item
|
||||
else:
|
||||
id = item.connect('activate', self.on_add_to_roster, jid)
|
||||
self.handlers[id] = item
|
||||
|
||||
item = xml.get_widget('send_private_message_menuitem')
|
||||
id = item.connect('activate', self.on_send_pm, model, iter)
|
||||
self.handlers[id] = item
|
||||
|
||||
item = xml.get_widget('send_file_menuitem')
|
||||
if not c.resource:
|
||||
item.set_sensitive(False)
|
||||
else:
|
||||
id = item.connect('activate', self.on_send_file, c)
|
||||
self.handlers[id] = item
|
||||
|
||||
# show the popup now!
|
||||
menu = xml.get_widget('gc_occupants_menu')
|
||||
menu.show_all()
|
||||
|
@ -1835,7 +1947,7 @@ class GroupchatControl(ChatControlBase):
|
|||
else: # We want to send a private message
|
||||
nick = model[path][C_NICK].decode('utf-8')
|
||||
self._start_private_message(nick)
|
||||
|
||||
|
||||
def on_list_treeview_row_activated(self, widget, path, col = 0):
|
||||
'''When an iter is double clicked: open the chat window'''
|
||||
if not gajim.single_click:
|
||||
|
|
|
@ -584,9 +584,8 @@ def make_python_month_gtk_month(month):
|
|||
def make_color_string(color):
|
||||
'''create #aabbcc color string from gtk color'''
|
||||
col = '#'
|
||||
for i in (color.red, color.green, color.blue):
|
||||
# GTK sometime return a value > 256
|
||||
h = hex(i%256)[2:4]
|
||||
for i in ('red', 'green', 'blue'):
|
||||
h = hex(getattr(color, i) / (16*16)).split('x')[1]
|
||||
if len(h) == 1:
|
||||
h = '0' + h
|
||||
col += h
|
||||
|
|
|
@ -76,10 +76,7 @@ class HistoryManager:
|
|||
self.search_results_scrolledwindow = xml.get_widget(
|
||||
'search_results_scrolledwindow')
|
||||
self.welcome_label = xml.get_widget('welcome_label')
|
||||
|
||||
self.logs_scrolledwindow.set_no_show_all(True)
|
||||
self.search_results_scrolledwindow.set_no_show_all(True)
|
||||
|
||||
|
||||
self.jids_already_in = [] # holds jids that we already have in DB
|
||||
self.AT_LEAST_ONE_DELETION_DONE = False
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ class MessageControl:
|
|||
self.widget_name = widget_name
|
||||
self.contact = contact
|
||||
self.account = account
|
||||
self.hide_chat_buttons_current = False
|
||||
self.hide_chat_buttons = False
|
||||
self.resource = resource
|
||||
|
||||
gajim.last_message_time[self.account][self.get_full_jid()] = 0
|
||||
|
@ -56,9 +56,9 @@ class MessageControl:
|
|||
def allow_shutdown(self, method):
|
||||
'''Called to check is a control is allowed to shutdown.
|
||||
If a control is not in a suitable shutdown state this method
|
||||
should return False'''
|
||||
should return 'no', else 'yes' or 'minimize' '''
|
||||
# NOTE: Derived classes MAY implement this
|
||||
return True
|
||||
return 'yes'
|
||||
|
||||
def shutdown(self):
|
||||
# NOTE: Derived classes MUST implement this
|
||||
|
@ -99,7 +99,7 @@ class MessageControl:
|
|||
|
||||
def chat_buttons_set_visible(self, state):
|
||||
# NOTE: Derived classes MAY implement this
|
||||
self.hide_chat_buttons_current = state
|
||||
self.hide_chat_buttons = state
|
||||
|
||||
def got_connected(self):
|
||||
pass
|
||||
|
@ -111,7 +111,7 @@ class MessageControl:
|
|||
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,
|
||||
chatstate = None, msg_id = None, composing_xep = None, resource = None,
|
||||
user_nick = None):
|
||||
'''Send the given message to the active tab. Doesn't return None if error
|
||||
'''
|
||||
|
@ -119,5 +119,5 @@ class MessageControl:
|
|||
# Send and update history
|
||||
return gajim.connections[self.account].send_message(jid, message, keyID,
|
||||
type = type, chatstate = chatstate, msg_id = msg_id,
|
||||
composing_jep = composing_jep, resource = self.resource,
|
||||
composing_xep = composing_xep, resource = self.resource,
|
||||
user_nick = user_nick)
|
||||
|
|
|
@ -103,13 +103,13 @@ class MessageWindow:
|
|||
self.notebook.set_show_tabs(False)
|
||||
self.notebook.set_show_border(gajim.config.get('tabs_border'))
|
||||
|
||||
# set up DnD
|
||||
self.hid = self.notebook.connect('drag_data_received',
|
||||
self.on_tab_label_drag_data_received_cb)
|
||||
self.handlers[self.hid] = self.notebook
|
||||
|
||||
self.notebook.drag_dest_set(gtk.DEST_DEFAULT_ALL, self.DND_TARGETS,
|
||||
gtk.gdk.ACTION_MOVE)
|
||||
# if GTK+ version < 2.10, use OUR way to reorder tabs (set up DnD)
|
||||
if gtk.pygtk_version < (2, 10, 0) or gtk.gtk_version < (2, 10, 0):
|
||||
self.hid = self.notebook.connect('drag_data_received',
|
||||
self.on_tab_label_drag_data_received_cb)
|
||||
self.handlers[self.hid] = self.notebook
|
||||
self.notebook.drag_dest_set(gtk.DEST_DEFAULT_ALL, self.DND_TARGETS,
|
||||
gtk.gdk.ACTION_MOVE)
|
||||
|
||||
def change_account_name(self, old_name, new_name):
|
||||
if self._controls.has_key(old_name):
|
||||
|
@ -146,9 +146,16 @@ class MessageWindow:
|
|||
|
||||
def _on_window_delete(self, win, event):
|
||||
# Make sure all controls are okay with being deleted
|
||||
ctrl_to_minimize = []
|
||||
for ctrl in self.controls():
|
||||
if not ctrl.allow_shutdown(self.CLOSE_CLOSE_BUTTON):
|
||||
allow_shutdown = ctrl.allow_shutdown(self.CLOSE_CLOSE_BUTTON)
|
||||
if allow_shutdown == 'no':
|
||||
return True # halt the delete
|
||||
elif allow_shutdown == 'minimize':
|
||||
ctrl_to_minimize.append(ctrl)
|
||||
# If all are ok, minimize the one that need to be minimized
|
||||
for ctrl in ctrl_to_minimize:
|
||||
ctrl.minimize()
|
||||
return False
|
||||
|
||||
def _on_window_destroy(self, win):
|
||||
|
@ -191,7 +198,11 @@ class MessageWindow:
|
|||
control.handlers[id] = tab_label_box
|
||||
self.notebook.append_page(control.widget, tab_label_box)
|
||||
|
||||
self.setup_tab_dnd(control.widget)
|
||||
# If GTK+ version >= 2.10, use gtk native way to reorder tabs
|
||||
if gtk.pygtk_version >= (2, 10, 0) and gtk.gtk_version >= (2, 10, 0):
|
||||
self.notebook.set_tab_reorderable(control.widget, True)
|
||||
else:
|
||||
self.setup_tab_dnd(control.widget)
|
||||
|
||||
self.redraw_tab(control)
|
||||
self.window.show_all()
|
||||
|
@ -301,7 +312,12 @@ class MessageWindow:
|
|||
'''reason is only for gc (offline status message)
|
||||
if force is True, do not ask any confirmation'''
|
||||
# Shutdown the MessageControl
|
||||
if not force and not ctrl.allow_shutdown(method):
|
||||
allow_shutdown = ctrl.allow_shutdown(method)
|
||||
if not force and allow_shutdown == 'no':
|
||||
return
|
||||
if allow_shutdown == 'minimize' and method != self.CLOSE_COMMAND:
|
||||
ctrl.minimize()
|
||||
self.check_tabs()
|
||||
return
|
||||
if reason is not None: # We are leaving gc with a status message
|
||||
ctrl.shutdown(reason)
|
||||
|
@ -313,7 +329,10 @@ class MessageWindow:
|
|||
types = ['printed_msg', 'chat', 'gc_msg'])
|
||||
del gajim.last_message_time[ctrl.account][ctrl.get_full_jid()]
|
||||
|
||||
self.disconnect_tab_dnd(ctrl.widget)
|
||||
# Disconnect tab DnD only if GTK version < 2.10
|
||||
if gtk.pygtk_version < (2, 10, 0) or gtk.gtk_version < (2, 10, 0):
|
||||
self.disconnect_tab_dnd(ctrl.widget)
|
||||
|
||||
self.notebook.remove_page(self.notebook.page_num(ctrl.widget))
|
||||
|
||||
fjid = ctrl.get_full_jid()
|
||||
|
@ -533,7 +552,7 @@ class MessageWindow:
|
|||
(event.state & gtk.gdk.MOD1_MASK): # ALT + 1,2,3..
|
||||
self.notebook.set_current_page(st.index(event.string))
|
||||
elif event.keyval == gtk.keysyms.c: # ALT + C toggles chat buttons
|
||||
ctrl.chat_buttons_set_visible(not ctrl.hide_chat_buttons_current)
|
||||
ctrl.chat_buttons_set_visible(not ctrl.hide_chat_buttons)
|
||||
# Close tab bindings
|
||||
elif event.keyval == gtk.keysyms.Escape and \
|
||||
gajim.config.get('escape_key_closes'): # Escape
|
||||
|
|
|
@ -61,6 +61,8 @@ class MusicTrackListener(gobject.GObject):
|
|||
'NameOwnerChanged', 'org.freedesktop.DBus', arg0='org.gnome.Rhythmbox')
|
||||
bus.add_signal_receiver(self._player_playing_changed_cb,
|
||||
'playingChanged', 'org.gnome.Rhythmbox.Player')
|
||||
bus.add_signal_receiver(self._player_playing_song_property_changed_cb,
|
||||
'playingSongPropertyChanged', 'org.gnome.Rhythmbox.Player')
|
||||
|
||||
## Banshee
|
||||
banshee_bus = dbus.SessionBus()
|
||||
|
@ -77,7 +79,7 @@ class MusicTrackListener(gobject.GObject):
|
|||
# Otherwise, it opens Banshee!
|
||||
self.banshee_props ={}
|
||||
gobject.timeout_add(1000, self._banshee_check_track_status)
|
||||
|
||||
|
||||
def _check_if_banshee_bus(self):
|
||||
if self.dubus_methods.NameHasOwner('org.gnome.Banshee'):
|
||||
self._get_banshee_bus()
|
||||
|
@ -86,7 +88,6 @@ class MusicTrackListener(gobject.GObject):
|
|||
self.banshee_is_here = False
|
||||
return True
|
||||
|
||||
|
||||
def _get_banshee_bus(self):
|
||||
bus = dbus.SessionBus()
|
||||
banshee = bus.get_object('org.gnome.Banshee', '/org/gnome/Banshee/Player')
|
||||
|
@ -106,6 +107,10 @@ class MusicTrackListener(gobject.GObject):
|
|||
else:
|
||||
self.emit('music-track-changed', None)
|
||||
|
||||
def _player_playing_song_property_changed_cb(self, a, b, c, d):
|
||||
if b == 'rb:stream-song-title':
|
||||
self.emit('music-track-changed', self._last_playing_music)
|
||||
|
||||
def _muine_properties_extract(self, song_string):
|
||||
d = dict((x.strip() for x in s1.split(':', 1)) for s1 in \
|
||||
song_string.split('\n'))
|
||||
|
|
|
@ -27,23 +27,25 @@ def device_no_longer_active(self, *args):
|
|||
'listen_to_network_manager') and connection.connected > 1:
|
||||
connection._disconnectedReconnCB()
|
||||
|
||||
supported = False
|
||||
|
||||
from common.dbus_support import system_bus
|
||||
try:
|
||||
from common.dbus_support import system_bus
|
||||
|
||||
import dbus
|
||||
import dbus.glib
|
||||
bus = system_bus.SystemBus()
|
||||
|
||||
bus = system_bus.SystemBus()
|
||||
|
||||
bus.add_signal_receiver(device_no_longer_active,
|
||||
'DeviceNoLongerActive',
|
||||
'org.freedesktop.NetworkManager',
|
||||
'org.freedesktop.NetworkManager',
|
||||
'/org/freedesktop/NetworkManager')
|
||||
|
||||
bus.add_signal_receiver(device_now_active,
|
||||
'DeviceNowActive',
|
||||
'org.freedesktop.NetworkManager',
|
||||
'org.freedesktop.NetworkManager',
|
||||
'/org/freedesktop/NetworkManager')
|
||||
if 'org.freedesktop.NetworkManager' in bus.list_names():
|
||||
supported = True
|
||||
bus.add_signal_receiver(device_no_longer_active,
|
||||
'DeviceNoLongerActive',
|
||||
'org.freedesktop.NetworkManager',
|
||||
'org.freedesktop.NetworkManager',
|
||||
'/org/freedesktop/NetworkManager')
|
||||
|
||||
bus.add_signal_receiver(device_now_active,
|
||||
'DeviceNowActive',
|
||||
'org.freedesktop.NetworkManager',
|
||||
'org.freedesktop.NetworkManager',
|
||||
'/org/freedesktop/NetworkManager')
|
||||
except:
|
||||
pass
|
||||
|
|
|
@ -154,7 +154,11 @@ def notify(event, jid, account, parameters, advanced_notif_num = None):
|
|||
message_type = parameters[0]
|
||||
is_first_message = parameters[1]
|
||||
nickname = parameters[2]
|
||||
message = parameters[3]
|
||||
if gajim.config.get('notification_preview_message'):
|
||||
message = parameters[3]
|
||||
else:
|
||||
# We don't want message preview, do_preview = False
|
||||
message = ''
|
||||
if helpers.allow_showing_notification(account, 'notify_on_new_message',
|
||||
advanced_notif_num, is_first_message):
|
||||
do_popup = True
|
||||
|
@ -235,8 +239,12 @@ def notify(event, jid, account, parameters, advanced_notif_num = None):
|
|||
img = os.path.join(gajim.DATA_DIR, 'pixmaps', 'events',
|
||||
'priv_msg_recv.png')
|
||||
title = _('New Private Message from group chat %s') % room_name
|
||||
text = _('%(nickname)s: %(message)s') % {'nickname': nickname,
|
||||
'message': message}
|
||||
if message:
|
||||
text = _('%(nickname)s: %(message)s') % {'nickname': nickname,
|
||||
'message': message}
|
||||
else:
|
||||
text = _('Messaged by %(nickname)s') % {'nickname': nickname}
|
||||
|
||||
else: # chat message
|
||||
event_type = _('New Message')
|
||||
img = os.path.join(gajim.DATA_DIR, 'pixmaps', 'events',
|
||||
|
@ -299,7 +307,8 @@ def popup(event_type, jid, account, msg_type = '', path_to_image = None,
|
|||
gajim.log.debug(str(e))
|
||||
# we failed to speak to notification daemon via D-Bus
|
||||
if USER_HAS_PYNOTIFY: # try via libnotify
|
||||
if not text:
|
||||
if not text and event_type == 'new_message':
|
||||
# empty text for new_message means do_preview = False
|
||||
text = gajim.get_name_from_jid(account, jid) # default value of text
|
||||
if not title:
|
||||
title = event_type
|
||||
|
@ -408,8 +417,9 @@ class DesktopNotification:
|
|||
self.jid = jid
|
||||
self.msg_type = msg_type
|
||||
|
||||
if not text:
|
||||
# default value of text
|
||||
# default value of text
|
||||
if not text and event_type == 'new_message':
|
||||
# empty text for new_message means do_preview = False
|
||||
self.text = gajim.get_name_from_jid(account, jid)
|
||||
|
||||
if not title:
|
||||
|
|
|
@ -77,10 +77,6 @@ class ProfileWindow:
|
|||
# Create Image for avatar button
|
||||
image = gtk.Image()
|
||||
self.xml.get_widget('PHOTO_button').set_image(image)
|
||||
text_button = self.xml.get_widget('NOPHOTO_button')
|
||||
# We use 2 buttons because some GTK theme don't show images in buttons
|
||||
text_button.set_no_show_all(True)
|
||||
text_button.hide()
|
||||
self.xml.signal_autoconnect(self)
|
||||
self.window.show_all()
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
## Copyright (C) 2005-2006 Nikos Kouremenos <kourem@gmail.com>
|
||||
## Copyright (C) 2005-2006 Dimitur Kirov <dkirov@gmail.com>
|
||||
## Copyright (C) 2005-2006 Andrew Sayman <lorien420@myrealbox.com>
|
||||
## Copyright (C) 2007 Lukas Petrovicky <lukas@petrovicky.net>
|
||||
## Copyright (C) 2007 Julien Pivotto <roidelapluie@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
|
||||
|
@ -223,6 +225,31 @@ class SignalObject(dbus.service.Object):
|
|||
|
||||
return connected_account, contact
|
||||
|
||||
def _get_account_for_groupchat(self, account, room_jid):
|
||||
'''get the account which is connected to groupchat (if not given)
|
||||
or check if the given account is connected to the groupchat'''
|
||||
connected_account = None
|
||||
accounts = gajim.contacts.get_accounts()
|
||||
# if there is only one account in roster, take it as default
|
||||
# if user did not ask for account
|
||||
if not account and len(accounts) == 1:
|
||||
account = accounts[0]
|
||||
if account:
|
||||
if gajim.connections[account].connected > 1 and \
|
||||
room_jid in gajim.gc_connected[account] and \
|
||||
gajim.gc_connected[account][room_jid]:
|
||||
# account and groupchat are connected
|
||||
connected_account = account
|
||||
else:
|
||||
for account in accounts:
|
||||
if gajim.connections[account].connected > 1 and \
|
||||
room_jid in gajim.gc_connected[account] and \
|
||||
gajim.gc_connected[account][room_jid]:
|
||||
# account and groupchat are connected
|
||||
connected_account = account
|
||||
break
|
||||
return connected_account
|
||||
|
||||
@dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
|
||||
def send_file(self, file_path, jid, account):
|
||||
'''send file, located at 'file_path' to 'jid', using account
|
||||
|
@ -269,6 +296,19 @@ class SignalObject(dbus.service.Object):
|
|||
jid = self._get_real_jid(jid, account)
|
||||
return self._send_message(jid, message, keyID, account, type, subject)
|
||||
|
||||
@dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
|
||||
def send_groupchat_message(self, room_jid, message, account):
|
||||
'''Send 'message' to groupchat 'room_jid',
|
||||
using account (optional) 'account'.'''
|
||||
if not room_jid or not message:
|
||||
return DBUS_BOOLEAN(False)
|
||||
connected_account = self._get_account_for_groupchat(account, room_jid)
|
||||
if connected_account:
|
||||
connection = gajim.connections[connected_account]
|
||||
connection.send_gc_message(room_jid, message)
|
||||
return DBUS_BOOLEAN(True)
|
||||
return DBUS_BOOLEAN(False)
|
||||
|
||||
@dbus.service.method(INTERFACE, in_signature='ss', out_signature='b')
|
||||
def open_chat(self, jid, account):
|
||||
'''Shows the tabbed window for new message to 'jid', using account
|
||||
|
@ -410,7 +450,7 @@ class SignalObject(dbus.service.Object):
|
|||
if acct in accounts:
|
||||
for jid in gajim.contacts.get_jid_list(acct):
|
||||
item = self._contacts_as_dbus_structure(
|
||||
gajim.contacts.get_contact(acct, jid))
|
||||
gajim.contacts.get_contacts(acct, jid))
|
||||
if item:
|
||||
result.append(item)
|
||||
return result
|
||||
|
@ -503,7 +543,7 @@ class SignalObject(dbus.service.Object):
|
|||
accounts = [account]
|
||||
contact_exists = False
|
||||
for account in accounts:
|
||||
contacts = gajim.contacts.get_contact(account, jid)
|
||||
contacts = gajim.contacts.get_contacts(account, jid)
|
||||
if contacts:
|
||||
gajim.connections[account].unsubscribe(jid)
|
||||
for contact in contacts:
|
||||
|
@ -531,12 +571,12 @@ class SignalObject(dbus.service.Object):
|
|||
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):
|
||||
if gajim.contacts.get_contacts(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_)
|
||||
c = gajim.contacts.get_contacts(account, jid_)
|
||||
if c[0].name == jid:
|
||||
nick_in_roster = jid_
|
||||
break
|
||||
|
|
1127
src/roster_window.py
|
@ -19,6 +19,8 @@ from common import xmpp, gajim, dataforms
|
|||
|
||||
import gtkgui_helpers
|
||||
import dialogs
|
||||
import vcard
|
||||
import config
|
||||
import dataforms_widget
|
||||
|
||||
class SearchWindow:
|
||||
|
@ -32,12 +34,10 @@ class SearchWindow:
|
|||
# retrieving widgets from xml
|
||||
self.xml = gtkgui_helpers.get_glade('search_window.glade')
|
||||
self.window = self.xml.get_widget('search_window')
|
||||
for name in ('label', 'progressbar', 'search_vbox', 'search_button'):
|
||||
for name in ('label', 'progressbar', 'search_vbox', 'search_button',
|
||||
'add_contact_button', 'information_button'):
|
||||
self.__dict__[name] = self.xml.get_widget(name)
|
||||
|
||||
self.data_form_widget = dataforms_widget.DataFormWidget()
|
||||
self.table = None
|
||||
|
||||
# displaying the window
|
||||
self.xml.signal_autoconnect(self)
|
||||
self.window.show_all()
|
||||
|
@ -45,10 +45,9 @@ class SearchWindow:
|
|||
self.pulse_id = gobject.timeout_add(80, self.pulse_callback)
|
||||
|
||||
self.is_form = None
|
||||
|
||||
# for non-dataform forms
|
||||
self.entries = {}
|
||||
self.info = {}
|
||||
|
||||
# Is there a jid column in results ? if -1: no, else column number
|
||||
self.jid_column = -1
|
||||
|
||||
def request_form(self):
|
||||
gajim.connections[self.account].request_search_fields(self.jid)
|
||||
|
@ -74,15 +73,14 @@ class SearchWindow:
|
|||
self.data_form_widget.data_form.type = 'submit'
|
||||
gajim.connections[self.account].send_search_form(self.jid,
|
||||
self.data_form_widget.data_form, True)
|
||||
self.search_vbox.remove(self.data_form_widget)
|
||||
else:
|
||||
for name in self.entries.keys():
|
||||
self.infos[name] = self.entries[name].get_text().decode('utf-8')
|
||||
if self.infos.has_key('instructions'):
|
||||
del self.infos['instructions']
|
||||
gajim.connections[self.account].send_search_form(self.jid, self.infos,
|
||||
infos = self.data_form_widget.get_infos()
|
||||
if infos.has_key('instructions'):
|
||||
del infos['instructions']
|
||||
gajim.connections[self.account].send_search_form(self.jid, infos,
|
||||
False)
|
||||
self.search_vbox.remove(self.table)
|
||||
|
||||
self.search_vbox.remove(self.data_form_widget)
|
||||
|
||||
self.progressbar.show()
|
||||
self.label.set_text(_('Waiting for results'))
|
||||
|
@ -90,58 +88,66 @@ class SearchWindow:
|
|||
self.pulse_id = gobject.timeout_add(80, self.pulse_callback)
|
||||
self.search_button.hide()
|
||||
|
||||
def on_add_contact_button_clicked(self, widget):
|
||||
(model, iter) = self.result_treeview.get_selection().get_selected()
|
||||
if not iter:
|
||||
return
|
||||
jid = model[iter][self.jid_column]
|
||||
dialogs.AddNewContactWindow(self.account, jid)
|
||||
|
||||
def on_information_button_clicked(self, widget):
|
||||
(model, iter) = self.result_treeview.get_selection().get_selected()
|
||||
if not iter:
|
||||
return
|
||||
jid = model[iter][self.jid_column]
|
||||
if gajim.interface.instances[self.account]['infos'].has_key(jid):
|
||||
gajim.interface.instances[self.account]['infos'][jid].window.present()
|
||||
else:
|
||||
contact = gajim.contacts.create_contact(jid = jid, name='', groups=[],
|
||||
show='', status='', sub='', ask='', resource='', priority=0,
|
||||
keyID='', our_chatstate=None, chatstate=None)
|
||||
gajim.interface.instances[self.account]['infos'][jid] = \
|
||||
vcard.VcardWindow(contact, self.account)
|
||||
|
||||
def on_form_arrived(self, form, is_form):
|
||||
if self.pulse_id:
|
||||
gobject.source_remove(self.pulse_id)
|
||||
self.progressbar.hide()
|
||||
self.label.hide()
|
||||
|
||||
if not is_form:
|
||||
self.is_form = False
|
||||
self.infos = form
|
||||
nbrow = 0
|
||||
if self.infos.has_key('instructions'):
|
||||
self.label.set_text(self.infos['instructions'])
|
||||
if is_form:
|
||||
self.is_form = True
|
||||
self.data_form_widget = dataforms_widget.DataFormWidget()
|
||||
self.dataform = dataforms.ExtendForm(node = form)
|
||||
self.data_form_widget.set_sensitive(True)
|
||||
try:
|
||||
self.data_form_widget.data_form = self.dataform
|
||||
except dataforms.Error:
|
||||
self.label.set_text(_('Error in received dataform'))
|
||||
self.label.show()
|
||||
self.table = gtk.Table()
|
||||
for name in self.infos.keys():
|
||||
if not name:
|
||||
continue
|
||||
if name == 'instructions':
|
||||
continue
|
||||
|
||||
nbrow = nbrow + 1
|
||||
self.table.resize(rows = nbrow, columns = 2)
|
||||
label = gtk.Label(name.capitalize() + ':')
|
||||
self.table.attach(label, 0, 1, nbrow - 1, nbrow, 0, 0, 0, 0)
|
||||
entry = gtk.Entry()
|
||||
entry.set_activates_default(True)
|
||||
if self.infos[name]:
|
||||
entry.set_text(self.infos[name])
|
||||
if name == 'password':
|
||||
entry.set_visibility(False)
|
||||
self.table.attach(entry, 1, 2, nbrow - 1, nbrow, 0, 0, 0, 0)
|
||||
self.entries[name] = entry
|
||||
self.table.show_all()
|
||||
self.search_vbox.pack_start(self.table)
|
||||
return
|
||||
|
||||
self.dataform = dataforms.ExtendForm(node = form)
|
||||
|
||||
self.data_form_widget.set_sensitive(True)
|
||||
try:
|
||||
self.data_form_widget.data_form = self.dataform
|
||||
except dataforms.Error:
|
||||
self.label.set_text(_('Error in received dataform'))
|
||||
self.label.show()
|
||||
return
|
||||
self.is_form = True
|
||||
return
|
||||
if self.data_form_widget.title:
|
||||
self.window.set_title('%s - Search - Gajim' % \
|
||||
self.data_form_widget.title)
|
||||
else:
|
||||
self.is_form = False
|
||||
self.data_form_widget = config.FakeDataForm(form)
|
||||
|
||||
self.data_form_widget.show_all()
|
||||
self.search_vbox.pack_start(self.data_form_widget)
|
||||
self.data_form_widget.show()
|
||||
if self.data_form_widget.title:
|
||||
self.window.set_title('%s - Search - Gajim' % \
|
||||
self.data_form_widget.title)
|
||||
|
||||
def on_result_treeview_cursor_changed(self, treeview):
|
||||
if self.jid_column == -1:
|
||||
return
|
||||
(model, iter) = treeview.get_selection().get_selected()
|
||||
if not iter:
|
||||
return
|
||||
if model[iter][self.jid_column]:
|
||||
self.add_contact_button.set_sensitive(True)
|
||||
self.information_button.set_sensitive(True)
|
||||
else:
|
||||
self.add_contact_button.set_sensitive(False)
|
||||
self.information_button.set_sensitive(False)
|
||||
|
||||
def on_result_arrived(self, form, is_form):
|
||||
if self.pulse_id:
|
||||
|
@ -157,8 +163,10 @@ class SearchWindow:
|
|||
# We suppose all items have the same fields
|
||||
sw = gtk.ScrolledWindow()
|
||||
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
treeview = gtk.TreeView()
|
||||
sw.add(treeview)
|
||||
self.result_treeview = gtk.TreeView()
|
||||
self.result_treeview.connect('cursor-changed',
|
||||
self.on_result_treeview_cursor_changed)
|
||||
sw.add(self.result_treeview)
|
||||
# Create model
|
||||
fieldtypes = [str]*len(form[0])
|
||||
model = gtk.ListStore(*fieldtypes)
|
||||
|
@ -168,13 +176,18 @@ class SearchWindow:
|
|||
# Create columns
|
||||
counter = 0
|
||||
for field in form[0].keys():
|
||||
treeview.append_column(
|
||||
self.result_treeview.append_column(
|
||||
gtk.TreeViewColumn(field, gtk.CellRendererText(),
|
||||
text = counter))
|
||||
if field == 'jid':
|
||||
self.jid_column = counter
|
||||
counter += 1
|
||||
treeview.set_model(model)
|
||||
self.result_treeview.set_model(model)
|
||||
sw.show_all()
|
||||
self.search_vbox.pack_start(sw)
|
||||
if self.jid_column > -1:
|
||||
self.add_contact_button.show()
|
||||
self.information_button.show()
|
||||
return
|
||||
|
||||
self.dataform = dataforms.ExtendForm(node = form)
|
||||
|
@ -187,8 +200,23 @@ class SearchWindow:
|
|||
self.label.show()
|
||||
return
|
||||
|
||||
self.result_treeview = self.data_form_widget.records_treeview
|
||||
selection = self.result_treeview.get_selection()
|
||||
selection.set_mode(gtk.SELECTION_SINGLE)
|
||||
self.result_treeview.connect('cursor-changed',
|
||||
self.on_result_treeview_cursor_changed)
|
||||
|
||||
counter = 0
|
||||
for field in self.dataform.items[0].fields:
|
||||
if field.var == 'jid':
|
||||
self.jid_column = counter
|
||||
break
|
||||
counter += 1
|
||||
self.search_vbox.pack_start(self.data_form_widget)
|
||||
self.data_form_widget.show()
|
||||
if self.jid_column > -1:
|
||||
self.add_contact_button.show()
|
||||
self.information_button.show()
|
||||
if self.data_form_widget.title:
|
||||
self.window.set_title('%s - Search - Gajim' % \
|
||||
self.data_form_widget.title)
|
||||
|
|