merge with trunk

This commit is contained in:
Yann Leboulanger 2010-07-19 19:53:29 +02:00
commit 796213c9cb
179 changed files with 132277 additions and 90687 deletions

10
AUTHORS
View File

@ -1,13 +1,8 @@
CURRENT DEVELOPERS: CURRENT DEVELOPERS:
Alexander Cherniuk (ts33kr AT gmail.com) Alexander Cherniuk (ts33kr AT gmail.com)
Nikos Kouremenos (kourem AT gmail.com)
Yann Leboulanger (asterix AT lagaule.org) Yann Leboulanger (asterix AT lagaule.org)
Julien Pivotto (roidelapluie AT gmail.com)
Jonathan Schleifer (js-gajim AT webkeks.org) Jonathan Schleifer (js-gajim AT webkeks.org)
Travis Shirk (travis AT pobox.com)
Brendan Taylor (whateley AT gmail.com)
Jean-Marie Traissard (jim AT lapin.org)
PAST DEVELOPERS: PAST DEVELOPERS:
@ -15,3 +10,8 @@ Stefan Bethge (stefan AT lanpartei.de)
Stephan Erb (steve-e AT h3c.de) Stephan Erb (steve-e AT h3c.de)
Vincent Hanquez (tab AT snarc.org) Vincent Hanquez (tab AT snarc.org)
Dimitur Kirov (dkirov AT gmail.com) Dimitur Kirov (dkirov AT gmail.com)
Nikos Kouremenos (kourem AT gmail.com)
Julien Pivotto (roidelapluie AT gmail.com)
Travis Shirk (travis AT pobox.com)
Brendan Taylor (whateley AT gmail.com)
Jean-Marie Traissard (jim AT lapin.org)

View File

@ -23,7 +23,7 @@
<h2>Optional Runtime Requirements</h2> <h2>Optional Runtime Requirements</h2>
<ul> <ul>
<li><a href="http://pyopenssl.sourceforge.net/">PyOpenSSL</a> (python-pyopenssl package in Debian) for <em>secure</em> SSL/TLS. Python's default SSL is insecure, so this package is highly recommended!</li> <li><a href="http://pyopenssl.sourceforge.net/">PyOpenSSL</a> (python-pyopenssl package in Debian) (>=0.9) for <em>secure</em> SSL/TLS. Python's default SSL is insecure, so this package is highly recommended!</li>
<li>python-crypto to enable End to end encryption</li> <li>python-crypto to enable End to end encryption</li>
<li>For idle module, libxss library</li> <li>For idle module, libxss library</li>
<li>For zeroconf (bonjour), the "enable link-local messaging" checkbox, you need dbus-glib, python-avahi</li> <li>For zeroconf (bonjour), the "enable link-local messaging" checkbox, you need dbus-glib, python-avahi</li>
@ -63,7 +63,7 @@
<p>To specify where to install do:</p> <p>To specify where to install do:</p>
<pre> <pre>
su -c make PREFIX=custom_path install ./configure --prefix=custom_path
</pre> </pre>
<h2>Running Gajim</h2> <h2>Running Gajim</h2>
@ -98,7 +98,8 @@ or if you didn't 'make install' you can also run from gajim folder with<em>./lau
If you want to remove it from custom directory provide it as: If you want to remove it from custom directory provide it as:
</p> </p>
<pre> <pre>
make PREFIX=custom_path uninstall ./configure --prefix=custom_path
make uninstall
</pre> </pre>
<h2>Miscellaneous</h2> <h2>Miscellaneous</h2>
@ -119,7 +120,7 @@ Wiki can be found at <a href="http://trac.gajim.org/wiki">http://trac.gajim.org/
<br/> <br/>
<br/> <br/>
<br/> <br/>
(C) 2003-200888888888<br/> (C) 2003-2010<br/>
The Gajim Team<br/> The Gajim Team<br/>
http://gajim.org<br/> http://gajim.org<br/>
<br/> <br/>

11
README.transifex Normal file
View File

@ -0,0 +1,11 @@
Transifex.net Token Verification
=================================
The list of tokens bellow guarantee the respective users to be able to enable
submission on components using the following repository url:
ssh://hg.gajim.org/gajim
Tokens:
JzQjKFEfvEhybB3vKxvsNYfusnpxWth3 / asterix

View File

@ -8,7 +8,9 @@
fi fi
echo "[encoding: UTF-8]" > po/POTFILES.in \ echo "[encoding: UTF-8]" > po/POTFILES.in \
&& ls -1 data/gajim.desktop.in.in data/gui/*.ui \ && for p in `ls data/gui/*.ui`; do echo "[type: gettext/glade]$p" >> \
po/POTFILES.in; done \
&& ls -1 data/gajim.desktop.in.in \
src/*py src/common/*py src/common/zeroconf/*.py | grep -v ipython_view.py >> \ src/*py src/common/*py src/common/zeroconf/*.py | grep -v ipython_view.py >> \
po/POTFILES.in || exit 1 po/POTFILES.in || exit 1
if test -z `which pkg-config 2>/dev/null`;then if test -z `which pkg-config 2>/dev/null`;then

View File

@ -5,7 +5,7 @@
<object class="GtkMenu" id="account_context_menu"> <object class="GtkMenu" id="account_context_menu">
<child> <child>
<object class="GtkImageMenuItem" id="status_menuitem"> <object class="GtkImageMenuItem" id="status_menuitem">
<property name="label">_Status</property> <property name="label" translatable="yes">_Status</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image1</property> <property name="image">image1</property>
@ -14,7 +14,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="pep_menuitem"> <object class="GtkImageMenuItem" id="pep_menuitem">
<property name="label">_Personal Events</property> <property name="label" translatable="yes">_Personal Events</property>
<property name="visible">True</property> <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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
@ -30,7 +30,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="start_chat_menuitem"> <object class="GtkImageMenuItem" id="start_chat_menuitem">
<property name="label">_Start Chat...</property> <property name="label" translatable="yes">_Start Chat...</property>
<property name="visible">True</property> <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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
@ -40,7 +40,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="join_group_chat_menuitem"> <object class="GtkImageMenuItem" id="join_group_chat_menuitem">
<property name="label">Join _Group Chat...</property> <property name="label" translatable="yes">Join _Group Chat...</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image4</property> <property name="image">image4</property>
@ -54,7 +54,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="add_contact_menuitem"> <object class="GtkImageMenuItem" id="add_contact_menuitem">
<property name="label">_Add Contact...</property> <property name="label" translatable="yes">_Add Contact...</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image5</property> <property name="image">image5</property>
@ -63,7 +63,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="service_discovery_menuitem"> <object class="GtkImageMenuItem" id="service_discovery_menuitem">
<property name="label">_Discover Services</property> <property name="label" translatable="yes">_Discover Services</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image6</property> <property name="image">image6</property>
@ -72,7 +72,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="execute_command_menuitem"> <object class="GtkImageMenuItem" id="execute_command_menuitem">
<property name="label">_Execute Command...</property> <property name="label" translatable="yes">_Execute Command...</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image7</property> <property name="image">image7</property>
@ -93,7 +93,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="edit_account_menuitem"> <object class="GtkImageMenuItem" id="edit_account_menuitem">
<property name="label">_Modify Account</property> <property name="label" translatable="yes">_Modify Account</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image8</property> <property name="image">image8</property>

View File

@ -4,7 +4,7 @@
<!-- interface-naming-policy toplevel-contextual --> <!-- interface-naming-policy toplevel-contextual -->
<object class="GtkListStore" id="liststore1"> <object class="GtkListStore" id="liststore1">
<columns> <columns>
<!-- column-name item text --> <!-- column-name item -->
<column type="gchararray"/> <column type="gchararray"/>
</columns> </columns>
<data> <data>
@ -203,7 +203,7 @@
<object class="GtkTable" id="table1"> <object class="GtkTable" id="table1">
<property name="visible">True</property> <property name="visible">True</property>
<property name="border_width">6</property> <property name="border_width">6</property>
<property name="n_rows">5</property> <property name="n_rows">6</property>
<property name="n_columns">3</property> <property name="n_columns">3</property>
<property name="column_spacing">6</property> <property name="column_spacing">6</property>
<property name="row_spacing">6</property> <property name="row_spacing">6</property>
@ -445,6 +445,68 @@
<property name="y_options"></property> <property name="y_options"></property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkExpander" id="expander2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkHBox" id="hbox2">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="label28">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Client Cert File:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">cert_entry1</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="cert_entry1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">The path to the client certificate and key in PKCS#12 format</property>
<property name="invisible_char">&#x25CF;</property>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="browse_for_client_cert_button">
<property name="label" translatable="yes">Browse...</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Choose Client Cert</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="label" translatable="yes">Client certificate</property>
</object>
</child>
</object>
<packing>
<property name="right_attach">3</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
</object> </object>
</child> </child>
<child type="tab"> <child type="tab">

View File

@ -358,6 +358,22 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="spacing">12</property> <property name="spacing">12</property>
<property name="layout_style">end</property> <property name="layout_style">end</property>
<child>
<object class="GtkButton" id="restart_button">
<property name="label">gtk-goto-first</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_restart_button_clicked"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="label">gtk-go-back</property> <property name="label">gtk-go-back</property>
@ -371,7 +387,7 @@
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="position">0</property> <property name="position">1</property>
</packing> </packing>
</child> </child>
<child> <child>
@ -387,7 +403,7 @@
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="position">1</property> <property name="position">2</property>
</packing> </packing>
</child> </child>
<child> <child>
@ -403,7 +419,7 @@
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="position">2</property> <property name="position">3</property>
</packing> </packing>
</child> </child>
<child> <child>
@ -419,7 +435,7 @@
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="position">3</property> <property name="position">4</property>
</packing> </packing>
</child> </child>
</object> </object>

View File

@ -26,7 +26,7 @@
<object class="GtkMenu" id="administrator_menuitem_menu"> <object class="GtkMenu" id="administrator_menuitem_menu">
<child> <child>
<object class="GtkImageMenuItem" id="send_server_message_menuitem"> <object class="GtkImageMenuItem" id="send_server_message_menuitem">
<property name="label">_Send Server Message...</property> <property name="label" translatable="yes">_Send Server Message...</property>
<property name="tooltip_text" translatable="yes">Sends a message to users currently connected to this server</property> <property name="tooltip_text" translatable="yes">Sends a message to users currently connected to this server</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image1</property> <property name="image">image1</property>
@ -54,7 +54,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="delete_motd_menuitem"> <object class="GtkImageMenuItem" id="delete_motd_menuitem">
<property name="label">Delete MOTD</property> <property name="label" translatable="yes">Delete MOTD</property>
<property name="tooltip_text" translatable="yes">Deletes Message of the Day</property> <property name="tooltip_text" translatable="yes">Deletes Message of the Day</property>
<property name="image">image2</property> <property name="image">image2</property>
<property name="use_stock">False</property> <property name="use_stock">False</property>

View File

@ -65,7 +65,7 @@
<child> <child>
<object class="GtkLabel" id="label1"> <object class="GtkLabel" id="label1">
<property name="visible">True</property> <property name="visible">True</property>
<property name="label">_Unblock</property> <property name="label" translatable="yes">_Unblock</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
</object> </object>
<packing> <packing>

View File

@ -5,7 +5,7 @@
<object class="GtkMenu" id="chat_context_menu"> <object class="GtkMenu" id="chat_context_menu">
<child> <child>
<object class="GtkImageMenuItem" id="copy_link_location_menuitem"> <object class="GtkImageMenuItem" id="copy_link_location_menuitem">
<property name="label">_Copy Link Location</property> <property name="label" translatable="yes">_Copy Link Location</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image1</property> <property name="image">image1</property>
@ -14,7 +14,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="open_link_in_browser_menuitem"> <object class="GtkImageMenuItem" id="open_link_in_browser_menuitem">
<property name="label">_Open Link in Browser</property> <property name="label" translatable="yes">_Open Link in Browser</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image2</property> <property name="image">image2</property>
@ -23,7 +23,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="copy_email_address_menuitem"> <object class="GtkImageMenuItem" id="copy_email_address_menuitem">
<property name="label">_Copy JID/Email Address</property> <property name="label" translatable="yes">_Copy JID/Email Address</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image3</property> <property name="image">image3</property>
@ -32,7 +32,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="open_email_composer_menuitem"> <object class="GtkImageMenuItem" id="open_email_composer_menuitem">
<property name="label">_Open Email Composer</property> <property name="label" translatable="yes">_Open Email Composer</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image4</property> <property name="image">image4</property>
@ -46,7 +46,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="start_chat_menuitem"> <object class="GtkImageMenuItem" id="start_chat_menuitem">
<property name="label">_Start Chat</property> <property name="label" translatable="yes">_Start Chat</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image5</property> <property name="image">image5</property>
@ -55,7 +55,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="join_group_chat_menuitem"> <object class="GtkImageMenuItem" id="join_group_chat_menuitem">
<property name="label">Join _Group Chat</property> <property name="label" translatable="yes">Join _Group Chat</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image6</property> <property name="image">image6</property>
@ -65,7 +65,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="add_to_roster_menuitem"> <object class="GtkImageMenuItem" id="add_to_roster_menuitem">
<property name="label">_Add to Roster...</property> <property name="label" translatable="yes">_Add to Roster...</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image7</property> <property name="image">image7</property>

File diff suppressed because it is too large Load Diff

View File

@ -41,9 +41,6 @@ Select the contacts you want to invite</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="headers_visible">False</property> <property name="headers_visible">False</property>
<signal name="drag_end" handler="on_guests_treeview_drag_end"/>
<signal name="drag_data_get" handler="on_guests_treeview_drag_data_get"/>
<signal name="drag_data_received" handler="on_guests_treeview_drag_data_received"/>
</object> </object>
</child> </child>
</object> </object>

View File

@ -251,7 +251,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="continue_menuitem"> <object class="GtkImageMenuItem" id="continue_menuitem">
<property name="label">_Continue</property> <property name="label" translatable="yes">_Continue</property>
<property name="no_show_all">True</property> <property name="no_show_all">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
@ -261,7 +261,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="pause_menuitem"> <object class="GtkImageMenuItem" id="pause_menuitem">
<property name="label">_Pause</property> <property name="label" translatable="yes">_Pause</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<property name="accel_group">accelgroup1</property> <property name="accel_group">accelgroup1</property>
@ -284,7 +284,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="open_folder_menuitem"> <object class="GtkImageMenuItem" id="open_folder_menuitem">
<property name="label">_Open Containing Folder</property> <property name="label" translatable="yes">_Open Containing Folder</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<property name="accel_group">accelgroup1</property> <property name="accel_group">accelgroup1</property>

View File

@ -5,7 +5,7 @@
<object class="GtkMenu" id="gc_control_popup_menu"> <object class="GtkMenu" id="gc_control_popup_menu">
<child> <child>
<object class="GtkImageMenuItem" id="change_nick_menuitem"> <object class="GtkImageMenuItem" id="change_nick_menuitem">
<property name="label">Change _Nickname...</property> <property name="label" translatable="yes">Change _Nickname...</property>
<property name="no_show_all">True</property> <property name="no_show_all">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image1</property> <property name="image">image1</property>
@ -14,7 +14,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="manage_room_menuitem"> <object class="GtkImageMenuItem" id="manage_room_menuitem">
<property name="label">_Manage Room</property> <property name="label" translatable="yes">_Manage Room</property>
<property name="visible">True</property> <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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
@ -26,7 +26,7 @@
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child> <child>
<object class="GtkImageMenuItem" id="change_subject_menuitem"> <object class="GtkImageMenuItem" id="change_subject_menuitem">
<property name="label">Change _Subject...</property> <property name="label" translatable="yes">Change _Subject...</property>
<property name="no_show_all">True</property> <property name="no_show_all">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image2</property> <property name="image">image2</property>
@ -35,7 +35,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="configure_room_menuitem"> <object class="GtkImageMenuItem" id="configure_room_menuitem">
<property name="label">Configure _Room...</property> <property name="label" translatable="yes">Configure _Room...</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image3</property> <property name="image">image3</property>
<property name="use_stock">False</property> <property name="use_stock">False</property>
@ -48,7 +48,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="destroy_room_menuitem"> <object class="GtkImageMenuItem" id="destroy_room_menuitem">
<property name="label">_Destroy Room</property> <property name="label" translatable="yes">_Destroy Room</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image4</property> <property name="image">image4</property>
@ -73,7 +73,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="bookmark_room_menuitem"> <object class="GtkImageMenuItem" id="bookmark_room_menuitem">
<property name="label">_Bookmark</property> <property name="label" translatable="yes">_Bookmark</property>
<property name="no_show_all">True</property> <property name="no_show_all">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image6</property> <property name="image">image6</property>
@ -87,7 +87,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="history_menuitem"> <object class="GtkImageMenuItem" id="history_menuitem">
<property name="label">_History</property> <property name="label" translatable="yes">_History</property>
<property name="no_show_all">True</property> <property name="no_show_all">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image7</property> <property name="image">image7</property>

View File

@ -5,7 +5,7 @@
<object class="GtkMenu" id="gc_occupants_menu"> <object class="GtkMenu" id="gc_occupants_menu">
<child> <child>
<object class="GtkImageMenuItem" id="send_private_message_menuitem"> <object class="GtkImageMenuItem" id="send_private_message_menuitem">
<property name="label">_Send Private Message</property> <property name="label" translatable="yes">_Send Private Message</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image1</property> <property name="image">image1</property>
@ -15,7 +15,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="send_file_menuitem"> <object class="GtkImageMenuItem" id="send_file_menuitem">
<property name="label">Send _File</property> <property name="label" translatable="yes">Send _File</property>
<property name="visible">True</property> <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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
@ -101,7 +101,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="add_to_roster_menuitem"> <object class="GtkImageMenuItem" id="add_to_roster_menuitem">
<property name="label">_Add to Roster</property> <property name="label" translatable="yes">_Add to Roster</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image3</property> <property name="image">image3</property>
@ -111,7 +111,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="block_menuitem"> <object class="GtkImageMenuItem" id="block_menuitem">
<property name="label">_Block</property> <property name="label" translatable="yes">_Block</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image4</property> <property name="image">image4</property>
@ -121,7 +121,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="unblock_menuitem"> <object class="GtkImageMenuItem" id="unblock_menuitem">
<property name="label">_Unblock</property> <property name="label" translatable="yes">_Unblock</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image5</property> <property name="image">image5</property>
@ -145,7 +145,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="history_menuitem"> <object class="GtkImageMenuItem" id="history_menuitem">
<property name="label">_History</property> <property name="label" translatable="yes">_History</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image6</property> <property name="image">image6</property>

View File

@ -75,6 +75,85 @@
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkHPaned" id="hpaned">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="border_width">3</property>
<property name="position">495</property>
<property name="position_set">True</property>
<child>
<object class="GtkVBox" id="gc_textviews_vbox">
<property name="width_request">0</property>
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkScrolledWindow" id="conversation_scrolledwindow">
<property name="width_request">200</property>
<property name="height_request">60</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<property name="shadow_type">in</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="message_scrolledwindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="vscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="resize">False</property>
<property name="shrink">False</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="list_scrolledwindow">
<property name="width_request">100</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="vscrollbar_policy">automatic</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="list_treeview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="border_width">1</property>
<property name="headers_visible">False</property>
</object>
</child>
</object>
<packing>
<property name="resize">False</property>
<property name="shrink">False</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child> <child>
<object class="GtkHBox" id="actions_hbox"> <object class="GtkHBox" id="actions_hbox">
<property name="visible">True</property> <property name="visible">True</property>
@ -133,7 +212,6 @@
<object class="GtkVSeparator" id="vseparator2"> <object class="GtkVSeparator" id="vseparator2">
<property name="visible">True</property> <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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="orientation">vertical</property>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@ -233,7 +311,6 @@
<object class="GtkVSeparator" id="vseparator4"> <object class="GtkVSeparator" id="vseparator4">
<property name="visible">True</property> <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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="orientation">vertical</property>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@ -269,6 +346,14 @@
<property name="position">8</property> <property name="position">8</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkComboBox" id="label_selector">
<property name="visible">True</property>
</object>
<packing>
<property name="position">9</property>
</packing>
</child>
<child> <child>
<object class="GtkAlignment" id="alignment2"> <object class="GtkAlignment" id="alignment2">
<property name="visible">True</property> <property name="visible">True</property>
@ -278,7 +363,7 @@
</child> </child>
</object> </object>
<packing> <packing>
<property name="position">9</property> <property name="position">10</property>
</packing> </packing>
</child> </child>
<child> <child>
@ -326,7 +411,7 @@
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="position">10</property> <property name="position">11</property>
</packing> </packing>
</child> </child>
</object> </object>
@ -335,94 +420,5 @@
<property name="position">2</property> <property name="position">2</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkHPaned" id="hpaned">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="border_width">3</property>
<property name="position">495</property>
<property name="position_set">True</property>
<child>
<object class="GtkVBox" id="vbox108">
<property name="width_request">0</property>
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkVBox" id="vbox109">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkScrolledWindow" id="conversation_scrolledwindow">
<property name="width_request">200</property>
<property name="height_request">60</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<property name="shadow_type">in</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="message_scrolledwindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="vscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="resize">False</property>
<property name="shrink">False</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="list_scrolledwindow">
<property name="width_request">100</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="vscrollbar_policy">automatic</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="list_treeview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="border_width">1</property>
<property name="headers_visible">False</property>
</object>
</child>
</object>
<packing>
<property name="resize">False</property>
<property name="shrink">False</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</object> </object>
</interface> </interface>

View File

@ -281,7 +281,7 @@ If you plan to do massive deletions, please make sure Gajim is not running. Gene
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="delete_menuitem"> <object class="GtkImageMenuItem" id="delete_menuitem">
<property name="label">Delete</property> <property name="label" translatable="yes">Delete</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>

View File

@ -7,6 +7,7 @@
<property name="type_hint">dialog</property> <property name="type_hint">dialog</property>
<property name="has_separator">False</property> <property name="has_separator">False</property>
<signal name="destroy" handler="on_input_dialog_destroy"/> <signal name="destroy" handler="on_input_dialog_destroy"/>
<signal name="delete_event" handler="on_input_dialog_delete_event"/>
<child internal-child="vbox"> <child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox10"> <object class="GtkVBox" id="dialog-vbox10">
<property name="visible">True</property> <property name="visible">True</property>

View File

@ -15,7 +15,7 @@
<child> <child>
<object class="GtkTable" id="table15"> <object class="GtkTable" id="table15">
<property name="visible">True</property> <property name="visible">True</property>
<property name="n_rows">7</property> <property name="n_rows">8</property>
<property name="n_columns">2</property> <property name="n_columns">2</property>
<property name="column_spacing">12</property> <property name="column_spacing">12</property>
<property name="row_spacing">6</property> <property name="row_spacing">6</property>
@ -110,8 +110,8 @@
<property name="label" translatable="yes">Password:</property> <property name="label" translatable="yes">Password:</property>
</object> </object>
<packing> <packing>
<property name="top_attach">4</property> <property name="top_attach">5</property>
<property name="bottom_attach">5</property> <property name="bottom_attach">6</property>
<property name="x_options">GTK_FILL</property> <property name="x_options">GTK_FILL</property>
<property name="y_options"></property> <property name="y_options"></property>
</packing> </packing>
@ -126,14 +126,14 @@
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
<property name="right_attach">2</property> <property name="right_attach">2</property>
<property name="top_attach">4</property> <property name="top_attach">5</property>
<property name="bottom_attach">5</property> <property name="bottom_attach">6</property>
<property name="y_options"></property> <property name="y_options"></property>
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkCheckButton" id="auto_join_checkbutton"> <object class="GtkCheckButton" id="auto_join_checkbutton">
<property name="label" translatable="yes">Join this room automatically when I connect</property> <property name="label" translatable="yes">Join this room _automatically when I connect</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="sensitive">False</property> <property name="sensitive">False</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
@ -143,8 +143,8 @@
</object> </object>
<packing> <packing>
<property name="right_attach">2</property> <property name="right_attach">2</property>
<property name="top_attach">6</property> <property name="top_attach">7</property>
<property name="bottom_attach">7</property> <property name="bottom_attach">8</property>
<property name="x_options">GTK_FILL</property> <property name="x_options">GTK_FILL</property>
<property name="y_options"></property> <property name="y_options"></property>
</packing> </packing>
@ -174,21 +174,69 @@
</child> </child>
<child> <child>
<object class="GtkCheckButton" id="bookmark_checkbutton"> <object class="GtkCheckButton" id="bookmark_checkbutton">
<property name="label" translatable="yes">Bookmark this room</property> <property name="label" translatable="yes">_Bookmark this room</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">False</property> <property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property> <property name="draw_indicator">True</property>
<signal name="toggled" handler="on_bookmark_checkbutton_toggled"/> <signal name="toggled" handler="on_bookmark_checkbutton_toggled"/>
</object> </object>
<packing> <packing>
<property name="right_attach">2</property> <property name="right_attach">2</property>
<property name="top_attach">5</property> <property name="top_attach">6</property>
<property name="bottom_attach">6</property> <property name="bottom_attach">7</property>
<property name="x_options">GTK_FILL</property> <property name="x_options">GTK_FILL</property>
<property name="y_options"></property> <property name="y_options"></property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Server:</property>
</object>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<object class="GtkComboBoxEntry" id="server_comboboxentry">
<property name="visible">True</property>
<property name="model">liststore1</property>
<property name="text_column">0</property>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="browse_rooms_button">
<property name="label" translatable="yes">Bro_wse Rooms</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">image1</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="on_browse_rooms_button_clicked"/>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</object>
<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>
</packing>
</child>
</object> </object>
<packing> <packing>
<property name="position">0</property> <property name="position">0</property>
@ -275,4 +323,14 @@
</object> </object>
</child> </child>
</object> </object>
<object class="GtkListStore" id="liststore1">
<columns>
<!-- column-name gchararray1 -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="stock">gtk-find</property>
</object>
</interface> </interface>

View File

@ -4,7 +4,7 @@
<!-- interface-naming-policy toplevel-contextual --> <!-- interface-naming-policy toplevel-contextual -->
<object class="GtkListStore" id="liststore1"> <object class="GtkListStore" id="liststore1">
<columns> <columns>
<!-- column-name item text --> <!-- column-name item -->
<column type="gchararray"/> <column type="gchararray"/>
</columns> </columns>
</object> </object>
@ -13,7 +13,6 @@
<property name="title" translatable="yes">Manage Bookmarks</property> <property name="title" translatable="yes">Manage Bookmarks</property>
<property name="default_width">550</property> <property name="default_width">550</property>
<property name="default_height">300</property> <property name="default_height">300</property>
<signal name="button_press_event" handler="on_manage_bookmarks_window_button_press_event"/>
<child> <child>
<object class="GtkVBox" id="vbox86"> <object class="GtkVBox" id="vbox86">
<property name="visible">True</property> <property name="visible">True</property>

View File

@ -14,6 +14,7 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="scrollable">True</property> <property name="scrollable">True</property>
<property name="tab_border">0</property>
</object> </object>
</child> </child>
</object> </object>
@ -43,6 +44,7 @@
<property name="xalign">0</property> <property name="xalign">0</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="ellipsize">end</property> <property name="ellipsize">end</property>
<property name="max_width_chars">9</property>
</object> </object>
<packing> <packing>
<property name="position">1</property> <property name="position">1</property>
@ -59,7 +61,6 @@
<child> <child>
<object class="GtkImage" id="image1329"> <object class="GtkImage" id="image1329">
<property name="visible">True</property> <property name="visible">True</property>
<property name="ypad">6</property>
<property name="stock">gtk-close</property> <property name="stock">gtk-close</property>
<property name="icon-size">1</property> <property name="icon-size">1</property>
</object> </object>

View File

@ -44,7 +44,7 @@
<object class="GtkLabel" id="event_type_label"> <object class="GtkLabel" id="event_type_label">
<property name="width_request">196</property> <property name="width_request">196</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="label">Event Type</property> <property name="label" translatable="yes">Event Type</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="wrap">True</property> <property name="wrap">True</property>
</object> </object>
@ -85,7 +85,7 @@
<property name="width_request">218</property> <property name="width_request">218</property>
<property name="height_request">64</property> <property name="height_request">64</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="label">Event desc</property> <property name="label" translatable="yes">Event desc</property>
<property name="wrap">True</property> <property name="wrap">True</property>
</object> </object>
<packing> <packing>

View File

@ -2136,7 +2136,7 @@ $T will be replaced by auto-not-available timeout</property>
<child> <child>
<object class="GtkTable" id="table8"> <object class="GtkTable" id="table8">
<property name="visible">True</property> <property name="visible">True</property>
<property name="n_rows">2</property> <property name="n_rows">4</property>
<property name="n_columns">2</property> <property name="n_columns">2</property>
<property name="column_spacing">6</property> <property name="column_spacing">6</property>
<property name="row_spacing">6</property> <property name="row_spacing">6</property>
@ -2184,6 +2184,52 @@ $T will be replaced by auto-not-available timeout</property>
<property name="bottom_attach">2</property> <property name="bottom_attach">2</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkLabel" id="label26">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Video framerate</property>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label27">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Video size</property>
</object>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="video_framerate_combobox">
<property name="visible">True</property>
<signal name="changed" handler="on_video_framerate_combobox_changed"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="video_size_combobox">
<property name="visible">True</property>
<signal name="changed" handler="on_video_size_combobox_changed"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
</object> </object>
</child> </child>
</object> </object>

View File

@ -432,6 +432,7 @@
<object class="GtkEntry" id="BDAY_entry"> <object class="GtkEntry" id="BDAY_entry">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<signal name="focus_out_event" handler="on_BDAY_entry_focus_out_event"/>
</object> </object>
<packing> <packing>
<property name="left_attach">3</property> <property name="left_attach">3</property>

View File

@ -34,7 +34,7 @@
<object class="GtkMenu" id="actions_menu_menu"> <object class="GtkMenu" id="actions_menu_menu">
<child> <child>
<object class="GtkImageMenuItem" id="new_chat_menuitem"> <object class="GtkImageMenuItem" id="new_chat_menuitem">
<property name="label">_Start Chat...</property> <property name="label" translatable="yes">_Start Chat...</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image1</property> <property name="image">image1</property>
@ -44,7 +44,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="send_single_message_menuitem"> <object class="GtkImageMenuItem" id="send_single_message_menuitem">
<property name="label">_Send Single Message...</property> <property name="label" translatable="yes">_Send Single Message...</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image2</property> <property name="image">image2</property>
<property name="use_stock">False</property> <property name="use_stock">False</property>
@ -53,9 +53,9 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="join_gc_menuitem"> <object class="GtkImageMenuItem" id="join_gc_menuitem">
<property name="label">Join _Group Chat...</property> <property name="label" translatable="yes">Join _Group Chat...</property>
<property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="visible">True</property>
<property name="image">image3</property> <property name="image">image3</property>
<property name="use_stock">False</property> <property name="use_stock">False</property>
<property name="accel_group">accelgroup1</property> <property name="accel_group">accelgroup1</property>
@ -68,9 +68,9 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="add_new_contact_menuitem"> <object class="GtkImageMenuItem" id="add_new_contact_menuitem">
<property name="label">Add _Contact...</property> <property name="label" translatable="yes">Add _Contact...</property>
<property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="visible">True</property>
<property name="image">image4</property> <property name="image">image4</property>
<property name="use_stock">False</property> <property name="use_stock">False</property>
<property name="accel_group">accelgroup1</property> <property name="accel_group">accelgroup1</property>
@ -78,7 +78,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="service_disco_menuitem"> <object class="GtkImageMenuItem" id="service_disco_menuitem">
<property name="label">_Discover Services</property> <property name="label" translatable="yes">_Discover Services</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image5</property> <property name="image">image5</property>
@ -123,7 +123,7 @@
<object class="GtkMenu" id="edit_menu_menu"> <object class="GtkMenu" id="edit_menu_menu">
<child> <child>
<object class="GtkImageMenuItem" id="accounts_menuitem"> <object class="GtkImageMenuItem" id="accounts_menuitem">
<property name="label">_Accounts</property> <property name="label" translatable="yes">_Accounts</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image6</property> <property name="image">image6</property>
@ -135,7 +135,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="profile_avatar_menuitem"> <object class="GtkImageMenuItem" id="profile_avatar_menuitem">
<property name="label">Profile, A_vatar</property> <property name="label" translatable="yes">Profile, A_vatar</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image7</property> <property name="image">image7</property>
@ -159,16 +159,6 @@
<signal name="activate" handler="on_preferences_menuitem_activate"/> <signal name="activate" handler="on_preferences_menuitem_activate"/>
</object> </object>
</child> </child>
<child>
<object class="GtkImageMenuItem" id="plugins_menuitem">
<property name="label" translatable="yes">P_lugins</property>
<property name="visible">True</property>
<property name="use_underline">True</property>
<property name="image">image13</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_plugins_menuitem_activate"/>
</object>
</child>
</object> </object>
</child> </child>
</object> </object>
@ -225,7 +215,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="file_transfers_menuitem"> <object class="GtkImageMenuItem" id="file_transfers_menuitem">
<property name="label">File _Transfers</property> <property name="label" translatable="yes">File _Transfers</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image8</property> <property name="image">image8</property>
@ -237,7 +227,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="history_menuitem"> <object class="GtkImageMenuItem" id="history_menuitem">
<property name="label">_History</property> <property name="label" translatable="yes">_History</property>
<property name="visible">True</property> <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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
@ -260,7 +250,7 @@
<object class="GtkMenu" id="help_menu_menu"> <object class="GtkMenu" id="help_menu_menu">
<child> <child>
<object class="GtkImageMenuItem" id="contents_menuitem"> <object class="GtkImageMenuItem" id="contents_menuitem">
<property name="label">_Contents</property> <property name="label" translatable="yes">_Contents</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="tooltip_text" translatable="yes">Help online</property> <property name="tooltip_text" translatable="yes">Help online</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
@ -272,7 +262,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="faq_menuitem"> <object class="GtkImageMenuItem" id="faq_menuitem">
<property name="label">_FAQ</property> <property name="label" translatable="yes">_FAQ</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="tooltip_text" translatable="yes">Frequently Asked Questions (online)</property> <property name="tooltip_text" translatable="yes">Frequently Asked Questions (online)</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
@ -289,7 +279,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="features_menuitem"> <object class="GtkImageMenuItem" id="features_menuitem">
<property name="label">Fea_tures</property> <property name="label" translatable="yes">Fea_tures</property>
<property name="visible">True</property> <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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
@ -447,9 +437,4 @@
<property name="stock">gtk-properties</property> <property name="stock">gtk-properties</property>
<property name="icon-size">1</property> <property name="icon-size">1</property>
</object> </object>
<object class="GtkImage" id="image13">
<property name="visible">True</property>
<property name="stock">gtk-disconnect</property>
<property name="icon-size">1</property>
</object>
</interface> </interface>

View File

@ -4,7 +4,7 @@
<!-- interface-naming-policy toplevel-contextual --> <!-- interface-naming-policy toplevel-contextual -->
<object class="GtkListStore" id="liststore1"> <object class="GtkListStore" id="liststore1">
<columns> <columns>
<!-- column-name item text --> <!-- column-name item -->
<column type="gchararray"/> <column type="gchararray"/>
</columns> </columns>
</object> </object>
@ -70,14 +70,8 @@ Agent JID - node</property>
<object class="GtkComboBoxEntry" id="address_comboboxentry"> <object class="GtkComboBoxEntry" id="address_comboboxentry">
<property name="visible">True</property> <property name="visible">True</property>
<property name="model">liststore1</property> <property name="model">liststore1</property>
<property name="text_column">0</property>
<signal name="changed" handler="on_address_comboboxentry_changed"/> <signal name="changed" handler="on_address_comboboxentry_changed"/>
<signal name="key_press_event" handler="on_address_comboboxentry_key_press_event"/>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>

View File

@ -5,7 +5,7 @@
<object class="GtkMenu" id="subscription_request_popup_menu"> <object class="GtkMenu" id="subscription_request_popup_menu">
<child> <child>
<object class="GtkImageMenuItem" id="start_chat_menuitem"> <object class="GtkImageMenuItem" id="start_chat_menuitem">
<property name="label">_Start Chat</property> <property name="label" translatable="yes">_Start Chat</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image1</property> <property name="image">image1</property>

View File

@ -5,7 +5,7 @@
<object class="GtkMenu" id="systray_context_menu"> <object class="GtkMenu" id="systray_context_menu">
<child> <child>
<object class="GtkImageMenuItem" id="status_menu"> <object class="GtkImageMenuItem" id="status_menu">
<property name="label">Sta_tus</property> <property name="label" translatable="yes">Sta_tus</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image1</property> <property name="image">image1</property>
@ -15,7 +15,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="chat_with_menuitem"> <object class="GtkImageMenuItem" id="chat_with_menuitem">
<property name="label">_Start Chat</property> <property name="label" translatable="yes">_Start Chat</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image2</property> <property name="image">image2</property>
@ -25,7 +25,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="join_gc_menuitem"> <object class="GtkImageMenuItem" id="join_gc_menuitem">
<property name="label">_Group Chat</property> <property name="label" translatable="yes">_Group Chat</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image3</property> <property name="image">image3</property>
@ -35,7 +35,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="single_message_menuitem"> <object class="GtkImageMenuItem" id="single_message_menuitem">
<property name="label">Send Single _Message</property> <property name="label" translatable="yes">Send Single _Message</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image4</property> <property name="image">image4</property>
@ -66,13 +66,11 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="show_roster_menuitem"> <object class="GtkImageMenuItem" id="show_roster_menuitem">
<property name="label">Show _Roster</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image5</property> <property name="image">image5</property>
<property name="use_stock">False</property> <property name="use_stock">False</property>
<property name="accel_group">accelgroup1</property> <property name="accel_group">accelgroup1</property>
<signal name="activate" handler="on_show_roster_menuitem_activate"/>
</object> </object>
</child> </child>
<child> <child>

View File

@ -6,7 +6,7 @@
<property name="border_width">12</property> <property name="border_width">12</property>
<property name="default_width">550</property> <property name="default_width">550</property>
<property name="default_height">450</property> <property name="default_height">450</property>
<signal name="delete_event" handler="on_xml_console_window_delete_event"/> <signal name="destroy" handler="on_xml_console_window_destroy"/>
<child> <child>
<object class="GtkVBox" id="vbox"> <object class="GtkVBox" id="vbox">
<property name="visible">True</property> <property name="visible">True</property>
@ -50,7 +50,7 @@
<property name="visible">True</property> <property name="visible">True</property>
<child> <child>
<object class="GtkCheckButton" id="enable_checkbutton"> <object class="GtkCheckButton" id="enable_checkbutton">
<property name="label" translatable="yes" comments="XML Console enable checkbutton">Enable</property> <property name="label" translatable="yes" comments="XML Console enable checkbutton">_Enable</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">False</property> <property name="receives_default">False</property>

View File

@ -5,7 +5,7 @@
<object class="GtkMenu" id="zeroconf_context_menu"> <object class="GtkMenu" id="zeroconf_context_menu">
<child> <child>
<object class="GtkImageMenuItem" id="status_menuitem"> <object class="GtkImageMenuItem" id="status_menuitem">
<property name="label">_Status</property> <property name="label" translatable="yes">_Status</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image1</property> <property name="image">image1</property>
@ -20,7 +20,7 @@
</child> </child>
<child> <child>
<object class="GtkImageMenuItem" id="zeroconf_properties_menuitem"> <object class="GtkImageMenuItem" id="zeroconf_properties_menuitem">
<property name="label">_Modify Account...</property> <property name="label" translatable="yes">_Modify Account...</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="image">image2</property> <property name="image">image2</property>

23
debian/changelog vendored
View File

@ -1,3 +1,26 @@
gajim (0.13.4-1) unstable; urgency=low
* New upstream release.
* Fix flood when trying to join a full MUC. Closes: #575688
-- Yann Leboulanger <asterix@lagaule.org> Fri, 02 Apr 2010 10:19:59 +0200
gajim (0.13.3-1) unstable; urgency=low
* New upstream release.
* Fix connection to facebook. Closes: #569767
-- Yann Leboulanger <asterix@lagaule.org> Tue, 23 Feb 2010 21:00:41 +0100
gajim (0.13.2-1) unstable; urgency=low
* New upstream release.
* Fix gnomekeyring usage. Closes: #562913
* Fix completion. Closes: #563930
* Fix typo in suggests list. Closes: #564754
-- Yann Leboulanger <asterix@lagaule.org> Thu, 14 Jan 2010 21:23:36 +0100
gajim (0.13.1-1) unstable; urgency=low gajim (0.13.1-1) unstable; urgency=low
* New upstream release. Closes: #559905 * New upstream release. Closes: #559905

6
debian/control vendored
View File

@ -2,9 +2,9 @@ Source: gajim
Section: net Section: net
Priority: optional Priority: optional
Maintainer: Yann Leboulanger <asterix@lagaule.org> Maintainer: Yann Leboulanger <asterix@lagaule.org>
Build-Depends: debhelper (>= 7), cdbs (>= 0.4.43), python-support (>= 0.7.1), python-dev, libgtk2.0-dev, python-gtk2-dev, gettext (>= 0.17-4), intltool (>= 0.40.1), imagemagick, python-central (>= 0.5) Build-Depends: debhelper (>= 7), cdbs (>= 0.4.43), python-support (>= 0.7.1), python-dev, libgtk2.0-dev, python-gtk2-dev, gettext (>= 0.17-4), intltool (>= 0.40.1), imagemagick
Build-Conflicts: python2.3 Build-Conflicts: python2.3
XS-Python-Version: >= 2.4 XS-Python-Version: >= 2.5
Standards-Version: 3.8.3 Standards-Version: 3.8.3
Homepage: http://www.gajim.org Homepage: http://www.gajim.org
Vcs-Hg: http://hg.gajim.org/gajim/ Vcs-Hg: http://hg.gajim.org/gajim/
@ -15,7 +15,7 @@ Architecture: any
XB-Python-Version: ${python:Versions} XB-Python-Version: ${python:Versions}
Depends: ${misc:Depends}, ${shlibs:Depends}, ${python:Depends}, python-support (>= 0.7.1), python-glade2 (>= 2.12.0), python-gtk2 (>= 2.12.0), dnsutils Depends: ${misc:Depends}, ${shlibs:Depends}, ${python:Depends}, python-support (>= 0.7.1), python-glade2 (>= 2.12.0), python-gtk2 (>= 2.12.0), dnsutils
Recommends: dbus, python-dbus, notification-daemon, python-gnupginterface, python-openssl, python-crypto Recommends: dbus, python-dbus, notification-daemon, python-gnupginterface, python-openssl, python-crypto
Suggests: python-gconf, python-gnome2, nautilus-sendto, avahi-daemon, python-avahi, network-manager, libgtkspell0, aspell-en, python-gnomekeyring, gnome-keyring, python-kerberos (>= 1.1), texlive-latex-base, dvipng Suggests: python-gconf, python-gnome2, nautilus-sendto, avahi-daemon, python-avahi, network-manager, libgtkspell0, aspell-en, python-gnomekeyring, gnome-keyring, python-sexy, python-kerberos (>= 1.1), texlive-latex-base, dvipng
Description: Jabber client written in PyGTK Description: Jabber client written in PyGTK
Gajim is a Jabber client. It has a tabbed user interface with normal chats, Gajim is a Jabber client. It has a tabbed user interface with normal chats,
group chats, and has many features such as, TLS, GPG, SSL, multiple accounts, group chats, and has many features such as, TLS, GPG, SSL, multiple accounts,

6
debian/copyright vendored
View File

@ -5,12 +5,12 @@ It was downloaded from:
http://www.gajim.org/downloads/ http://www.gajim.org/downloads/
Upstream Authors: Upstream Authors:
- Alexander Cherniuk <ts33kr@gmail.com>
- Yann Le Boulanger <asterix@lagaule.org> - Yann Le Boulanger <asterix@lagaule.org>
- Jean-Marie Traissard <jim@lapin.org> - Jonathan Schleifer <js-gajim@webkeks.org>
- Stephan Erb <steve-e@h3c.de>
Copyright: (c) 2003-2009 Gajim Team Copyright: (c) 2003-2010 Gajim Team
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

1
debian/pycompat vendored
View File

@ -1 +0,0 @@
2

2
debian/pyversions vendored
View File

@ -1 +1 @@
2.4 2.5-

5
debian/rules vendored
View File

@ -7,10 +7,9 @@ include /usr/share/cdbs/1/rules/debhelper.mk
include /usr/share/cdbs/1/rules/simple-patchsys.mk include /usr/share/cdbs/1/rules/simple-patchsys.mk
include /usr/share/cdbs/1/class/autotools.mk include /usr/share/cdbs/1/class/autotools.mk
PYTHONVER = 2.5
DEB_CONFIGURE_EXTRA_FLAGS := --prefix=/usr DEB_CONFIGURE_EXTRA_FLAGS := --prefix=/usr
DEB_MAKE_BUILD_TARGET := all PYTHON=python$(PYTHONVER) DEB_MAKE_BUILD_TARGET := all
DEB_MAKE_INSTALL_TARGET = install PYTHON=python$(PYTHONVER) DESTDIR=$(DEB_DESTDIR) DEB_MAKE_INSTALL_TARGET = install DESTDIR=$(DEB_DESTDIR)
binary-install/gajim:: binary-install/gajim::
rm $(DEB_DESTDIR)/usr/share/gajim/src/common/GnuPGInterface.py* rm $(DEB_DESTDIR)/usr/share/gajim/src/common/GnuPGInterface.py*

8
debian/watch vendored Normal file
View File

@ -0,0 +1,8 @@
# Control file for uscan
# Run the "uscan" command to check for upstream updates and more.
# See uscan(1) for format
# Compulsory line, this is a version 3 file
version=3
http://www.gajim.org/downloads/([\d.]*)/gajim-([\d\.]*)\.tar\.gz

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 760 B

View File

@ -29,3 +29,5 @@ gl
lt lt
da da
uk uk
ja
kk

4762
po/be.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

4835
po/bg.po

File diff suppressed because it is too large Load Diff

8352
po/br.po

File diff suppressed because it is too large Load Diff

9457
po/cs.po

File diff suppressed because it is too large Load Diff

4845
po/da.po

File diff suppressed because it is too large Load Diff

9843
po/de.po

File diff suppressed because it is too large Load Diff

4741
po/el.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

4796
po/eo.po

File diff suppressed because it is too large Load Diff

4760
po/es.po

File diff suppressed because it is too large Load Diff

4800
po/eu.po

File diff suppressed because it is too large Load Diff

9503
po/fr.po

File diff suppressed because it is too large Load Diff

4704
po/gl.po

File diff suppressed because it is too large Load Diff

4827
po/hr.po

File diff suppressed because it is too large Load Diff

4810
po/it.po

File diff suppressed because it is too large Load Diff

10374
po/ja.po Normal file

File diff suppressed because it is too large Load Diff

9846
po/kk.po Normal file

File diff suppressed because it is too large Load Diff

4760
po/lt.po

File diff suppressed because it is too large Load Diff

4866
po/nb.po

File diff suppressed because it is too large Load Diff

8413
po/nl.po

File diff suppressed because it is too large Load Diff

4866
po/no.po

File diff suppressed because it is too large Load Diff

9756
po/pl.po

File diff suppressed because it is too large Load Diff

4711
po/pt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

9976
po/ru.po

File diff suppressed because it is too large Load Diff

5670
po/sk.po

File diff suppressed because it is too large Load Diff

4815
po/sr.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

4870
po/sv.po

File diff suppressed because it is too large Load Diff

9439
po/tr.po Normal file

File diff suppressed because it is too large Load Diff

9442
po/uk.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -7,4 +7,4 @@ import sys
if os.getcwd().endswith('dev'): if os.getcwd().endswith('dev'):
os.chdir('../../src/') # we were in scripts/dev os.chdir('../../src/') # we were in scripts/dev
os.system("pylint --indent-string='\t' --additional-builtins='_' --disable-msg=C0111,C0103,C0111,C0112 --disable-checker=design " + "".join(sys.argv[1:])) os.system("pylint --include-ids=y --additional-builtins='_' --disable-msg=C0103,C0111,W0703,W0511,W0142,W0613,R0201 --disable-checker=design " + "".join(sys.argv[1:]))

View File

@ -1,6 +1,6 @@
## setup_win32.py (run me as python setup_win32.py py2exe -O2) ## setup_win32.py (run me as python setup_win32.py py2exe -O2)
## ##
## Copyright (C) 2003-2008 Yann Leboulanger <asterix AT lagaule.org> ## Copyright (C) 2003-2010 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2005-2006 Nikos Kouremenos <kourem AT gmail.com> ## Copyright (C) 2005-2006 Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org> ## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
## ##

View File

@ -3,7 +3,7 @@
## ##
## Copyright (C) 2006 Nikos Kouremenos <kourem AT gmail.com> ## Copyright (C) 2006 Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2006-2007 Tomasz Melcer <liori AT exroot.org> ## Copyright (C) 2006-2007 Tomasz Melcer <liori AT exroot.org>
## Copyright (C) 2006-2008 Yann Leboulanger <asterix AT lagaule.org> ## Copyright (C) 2006-2010 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org> ## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
## Stephan Erb <steve-e AT h3c.de> ## Stephan Erb <steve-e AT h3c.de>
## ##
@ -55,21 +55,15 @@ class CommandWindow:
# an account object # an account object
self.account = gajim.connections[account] self.account = gajim.connections[account]
self.jid = jid self.jid = jid
self.pulse_id=None # to satisfy self.setup_pulsing()
self.commandlist=None # a list of (commandname, commanddescription)
# command's data
self.commandnode = commandnode self.commandnode = commandnode
self.sessionid = None self.data_form_widget = None
self.dataform = None
self.allow_stage3_close = False
# retrieving widgets from xml # retrieving widgets from xml
self.xml = gtkgui_helpers.get_gtk_builder('adhoc_commands_window.ui') self.xml = gtkgui_helpers.get_gtk_builder('adhoc_commands_window.ui')
self.window = self.xml.get_object('adhoc_commands_window') self.window = self.xml.get_object('adhoc_commands_window')
self.window.connect('delete-event', self.on_adhoc_commands_window_delete_event) self.window.connect('delete-event',
for name in ('back_button', 'forward_button', self.on_adhoc_commands_window_delete_event)
for name in ('restart_button', 'back_button', 'forward_button',
'execute_button', 'close_button', 'stages_notebook', 'execute_button', 'close_button', 'stages_notebook',
'retrieving_commands_stage_vbox', 'retrieving_commands_stage_vbox',
'command_list_stage_vbox', 'command_list_vbox', 'command_list_stage_vbox', 'command_list_vbox',
@ -78,7 +72,22 @@ class CommandWindow:
'error_description_label'): 'error_description_label'):
self.__dict__[name] = self.xml.get_object(name) self.__dict__[name] = self.xml.get_object(name)
self.initiate()
def initiate(self):
self.pulse_id = None # to satisfy self.setup_pulsing()
self.commandlist = None # a list of (commandname, commanddescription)
# command's data
self.sessionid = None
self.dataform = None
self.allow_stage3_close = False
# creating data forms widget # creating data forms widget
if self.data_form_widget:
self.sending_form_stage_vbox.remove(self.data_form_widget)
self.data_form_widget.destroy()
self.data_form_widget = dataforms_widget.DataFormWidget() self.data_form_widget = dataforms_widget.DataFormWidget()
self.data_form_widget.show() self.data_form_widget.show()
self.sending_form_stage_vbox.pack_start(self.data_form_widget) self.sending_form_stage_vbox.pack_start(self.data_form_widget)
@ -94,6 +103,8 @@ class CommandWindow:
self.xml.connect_signals(self) self.xml.connect_signals(self)
self.window.show_all() self.window.show_all()
self.restart_button.set_sensitive(False)
# These functions are set up by appropriate stageX methods. # These functions are set up by appropriate stageX methods.
def stage_finish(self, *anything): def stage_finish(self, *anything):
pass pass
@ -130,7 +141,7 @@ class CommandWindow:
return self.stage_close_button_clicked(*anything) return self.stage_close_button_clicked(*anything)
def on_adhoc_commands_window_destroy(self, *anything): def on_adhoc_commands_window_destroy(self, *anything):
# TODO: do all actions that are needed to remove this object from memory... # TODO: do all actions that are needed to remove this object from memory
self.remove_pulsing() self.remove_pulsing()
def on_adhoc_commands_window_delete_event(self, *anything): def on_adhoc_commands_window_delete_event(self, *anything):
@ -167,7 +178,8 @@ class CommandWindow:
# setup the callbacks # setup the callbacks
self.stage_finish = self.stage1_finish self.stage_finish = self.stage1_finish
self.stage_close_button_clicked = self.stage1_close_button_clicked self.stage_close_button_clicked = self.stage1_close_button_clicked
self.stage_adhoc_commands_window_delete_event = self.stage1_adhoc_commands_window_delete_event self.stage_adhoc_commands_window_delete_event = \
self.stage1_adhoc_commands_window_delete_event
def stage1_finish(self): def stage1_finish(self):
self.remove_pulsing() self.remove_pulsing()
@ -196,8 +208,7 @@ class CommandWindow:
assert len(self.commandlist)>0 assert len(self.commandlist)>0
self.stages_notebook.set_current_page( self.stages_notebook.set_current_page(
self.stages_notebook.page_num( self.stages_notebook.page_num(self.command_list_stage_vbox))
self.command_list_stage_vbox))
self.close_button.set_sensitive(True) self.close_button.set_sensitive(True)
self.back_button.set_sensitive(False) self.back_button.set_sensitive(False)
@ -208,7 +219,8 @@ class CommandWindow:
first_radio = None first_radio = None
for (commandnode, commandname) in self.commandlist: for (commandnode, commandname) in self.commandlist:
radio = gtk.RadioButton(first_radio, label=commandname) radio = gtk.RadioButton(first_radio, label=commandname)
radio.connect("toggled", self.on_command_radiobutton_toggled, commandnode) radio.connect("toggled", self.on_command_radiobutton_toggled,
commandnode)
if not first_radio: if not first_radio:
first_radio = radio first_radio = radio
self.commandnode = commandnode self.commandnode = commandnode
@ -266,7 +278,8 @@ class CommandWindow:
self.stage_forward_button_clicked = self.stage3_forward_button_clicked self.stage_forward_button_clicked = self.stage3_forward_button_clicked
self.stage_execute_button_clicked = self.stage3_execute_button_clicked self.stage_execute_button_clicked = self.stage3_execute_button_clicked
self.stage_close_button_clicked = self.stage3_close_button_clicked self.stage_close_button_clicked = self.stage3_close_button_clicked
self.stage_adhoc_commands_window_delete_event = self.stage3_close_button_clicked self.stage_adhoc_commands_window_delete_event = \
self.stage3_close_button_clicked
def stage3_finish(self): def stage3_finish(self):
pass pass
@ -276,10 +289,10 @@ class CommandWindow:
We are in the middle of executing command. Ask user if he really want to We are in the middle of executing command. Ask user if he really want to
cancel the process, then cancel it cancel the process, then cancel it
""" """
# this works also as a handler for window_delete_event, so we have to return appropriate # this works also as a handler for window_delete_event, so we have to
# values # return appropriate values
if self.form_status == 'completed': if self.form_status == 'completed':
if widget!=self.window: if widget != self.window:
self.window.destroy() self.window.destroy()
return False return False
@ -291,10 +304,10 @@ class CommandWindow:
self.allow_stage3_close = True self.allow_stage3_close = True
self.window.destroy() self.window.destroy()
dialog = dialogs.HigDialog(self.window, gtk.DIALOG_DESTROY_WITH_PARENT | \ dialog = dialogs.HigDialog(self.window, gtk.DIALOG_DESTROY_WITH_PARENT \
gtk.DIALOG_MODAL, gtk.BUTTONS_YES_NO, _('Cancel confirmation'), | gtk.DIALOG_MODAL, gtk.BUTTONS_YES_NO, _('Cancel confirmation'),
_('You are in process of executing command. Do you really want to ' _('You are in process of executing command. Do you really want to '
'cancel it?'), on_response_yes=on_yes) 'cancel it?'), on_response_yes=on_yes)
dialog.popup() dialog.popup()
return True # Block event, don't close window return True # Block event, don't close window
@ -310,7 +323,7 @@ class CommandWindow:
def stage3_submit_form(self, action='execute'): def stage3_submit_form(self, action='execute'):
self.data_form_widget.set_sensitive(False) self.data_form_widget.set_sensitive(False)
if self.data_form_widget.get_data_form(): if self.data_form_widget.get_data_form():
self.data_form_widget.data_form.type='submit' self.data_form_widget.data_form.type = 'submit'
else: else:
self.data_form_widget.hide() self.data_form_widget.hide()
@ -346,9 +359,10 @@ class CommandWindow:
self.data_form_widget.set_sensitive(True) self.data_form_widget.set_sensitive(True)
try: try:
self.data_form_widget.data_form=self.dataform self.data_form_widget.data_form = self.dataform
except dataforms.Error: except dataforms.Error:
self.stage5(error=_('Service sent malformed data'), senderror=True) self.stage5(error=_('Service sent malformed data'),
senderror=True)
return return
self.data_form_widget.show() self.data_form_widget.show()
if self.data_form_widget.title: if self.data_form_widget.title:
@ -362,7 +376,8 @@ class CommandWindow:
# actions, actions, actions... # actions, actions, actions...
self.close_button.set_sensitive(True) self.close_button.set_sensitive(True)
self.back_button.set_sensitive(actions.getTag('prev') is not None) self.back_button.set_sensitive(actions.getTag('prev') is not None)
self.forward_button.set_sensitive(actions.getTag('next') is not None) self.forward_button.set_sensitive(
actions.getTag('next') is not None)
self.execute_button.set_sensitive(True) self.execute_button.set_sensitive(True)
else: else:
self.close_button.set_sensitive(True) self.close_button.set_sensitive(True)
@ -372,11 +387,13 @@ class CommandWindow:
if self.form_status == 'completed': if self.form_status == 'completed':
self.close_button.set_sensitive(True) self.close_button.set_sensitive(True)
self.restart_button.set_sensitive(True)
self.back_button.hide() self.back_button.hide()
self.forward_button.hide() self.forward_button.hide()
self.execute_button.hide() self.execute_button.hide()
self.close_button.show() self.close_button.show()
self.stage_adhoc_commands_window_delete_event = self.stage3_close_button_clicked self.stage_adhoc_commands_window_delete_event = \
self.stage3_close_button_clicked
note = command.getTag('note') note = command.getTag('note')
if note: if note:
@ -387,6 +404,10 @@ class CommandWindow:
self.notes_label.set_no_show_all(True) self.notes_label.set_no_show_all(True)
self.notes_label.hide() self.notes_label.hide()
def on_restart_button_clicked(self, widget):
self.commandnode = None
self.initiate()
# stage 4: no commands are exposed # stage 4: no commands are exposed
def stage4(self): def stage4(self):
""" """
@ -396,8 +417,7 @@ class CommandWindow:
self.stage_finish() self.stage_finish()
self.stages_notebook.set_current_page( self.stages_notebook.set_current_page(
self.stages_notebook.page_num( self.stages_notebook.page_num(self.no_commands_stage_vbox))
self.no_commands_stage_vbox))
self.close_button.set_sensitive(True) self.close_button.set_sensitive(True)
self.back_button.set_sensitive(False) self.back_button.set_sensitive(False)
@ -442,8 +462,7 @@ class CommandWindow:
assert False assert False
self.stages_notebook.set_current_page( self.stages_notebook.set_current_page(
self.stages_notebook.page_num( self.stages_notebook.page_num(self.error_stage_vbox))
self.error_stage_vbox))
self.close_button.set_sensitive(True) self.close_button.set_sensitive(True)
self.back_button.hide() self.back_button.hide()
@ -481,14 +500,15 @@ class CommandWindow:
""" """
if self.pulse_id: if self.pulse_id:
gobject.source_remove(self.pulse_id) gobject.source_remove(self.pulse_id)
self.pulse_id=None self.pulse_id = None
# handling xml stanzas # handling xml stanzas
def request_command_list(self): def request_command_list(self):
""" """
Request the command list. Change stage on delivery Request the command list. Change stage on delivery
""" """
query = xmpp.Iq(typ='get', to=xmpp.JID(self.jid), queryNS=xmpp.NS_DISCO_ITEMS) query = xmpp.Iq(typ='get', to=xmpp.JID(self.jid),
queryNS=xmpp.NS_DISCO_ITEMS)
query.setQuerynode(xmpp.NS_COMMANDS) query.setQuerynode(xmpp.NS_COMMANDS)
def callback(response): def callback(response):
@ -512,7 +532,8 @@ class CommandWindow:
self.commandlist = [] self.commandlist = []
self.stage4() self.stage4()
else: else:
self.commandlist = [(t.getAttr('node'), t.getAttr('name')) for t in items] self.commandlist = [(t.getAttr('node'), t.getAttr('name')) \
for t in items]
self.stage2() self.stage2()
self.account.connection.SendAndCallForResponse(query, callback) self.account.connection.SendAndCallForResponse(query, callback)
@ -533,9 +554,6 @@ class CommandWindow:
cmdnode.setAttr('sessionid', self.sessionid) cmdnode.setAttr('sessionid', self.sessionid)
if self.data_form_widget.data_form: if self.data_form_widget.data_form:
# cmdnode.addChild(node=dataforms.DataForm(tofill=self.data_form_widget.data_form))
# FIXME: simplified form to send
cmdnode.addChild(node=self.data_form_widget.data_form) cmdnode.addChild(node=self.data_form_widget.data_form)
def callback(response): def callback(response):
@ -564,6 +582,6 @@ class CommandWindow:
self.account.connection.send(stanza) self.account.connection.send(stanza)
else: else:
# we did not received any reply from service; FIXME: we should wait and # we did not received any reply from service;
# then send cancel; for now we do nothing # FIXME: we should wait and then send cancel; for now we do nothing
pass pass

View File

@ -3,8 +3,8 @@
## ##
## Copyright (C) 2005 Travis Shirk <travis AT pobox.com> ## Copyright (C) 2005 Travis Shirk <travis AT pobox.com>
## Vincent Hanquez <tab AT snarc.org> ## Vincent Hanquez <tab AT snarc.org>
## Copyright (C) 2005-2007 Yann Leboulanger <asterix AT lagaule.org> ## Copyright (C) 2005-2010 Yann Leboulanger <asterix AT lagaule.org>
## Nikos Kouremenos <kourem AT gmail.com> ## Copyright (C) 2005-2007 Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2006 Dimitur Kirov <dkirov AT gmail.com> ## Copyright (C) 2006 Dimitur Kirov <dkirov AT gmail.com>
## Copyright (C) 2006-2007 Jean-Marie Traissard <jim AT lapin.org> ## Copyright (C) 2006-2007 Jean-Marie Traissard <jim AT lapin.org>
## ##

View File

@ -2,7 +2,7 @@
## src/atom_window.py ## src/atom_window.py
## ##
## Copyright (C) 2006 Tomasz Melcer <liori AT exroot.org> ## Copyright (C) 2006 Tomasz Melcer <liori AT exroot.org>
## Copyright (C) 2006-2007 Yann Leboulanger <asterix AT lagaule.org> ## Copyright (C) 2006-2010 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2007 Nikos Kouremenos <kourem AT gmail.com> ## Copyright (C) 2007 Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org> ## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
## ##
@ -53,15 +53,16 @@ class AtomWindow:
""" """
Create new window... only if we have anything to show Create new window... only if we have anything to show
""" """
assert len(self.__class__.entries)>0 assert len(self.__class__.entries)
self.entry = None # the entry actually displayed self.entry = None # the entry actually displayed
self.xml = gtkgui_helpers.get_gtk_builder('atom_entry_window.ui') self.xml = gtkgui_helpers.get_gtk_builder('atom_entry_window.ui')
self.window = self.xml.get_object('atom_entry_window') self.window = self.xml.get_object('atom_entry_window')
for name in ('new_entry_label', 'feed_title_label', 'feed_title_eventbox', for name in ('new_entry_label', 'feed_title_label',
'feed_tagline_label', 'entry_title_label', 'entry_title_eventbox', 'feed_title_eventbox', 'feed_tagline_label', 'entry_title_label',
'last_modified_label', 'close_button', 'next_button'): 'entry_title_eventbox', 'last_modified_label', 'close_button',
'next_button'):
self.__dict__[name] = self.xml.get_object(name) self.__dict__[name] = self.xml.get_object(name)
self.displayNextEntry() self.displayNextEntry()
@ -83,23 +84,26 @@ class AtomWindow:
# fill the fields # fill the fields
if newentry.feed_link is not None: if newentry.feed_link is not None:
self.feed_title_label.set_markup( self.feed_title_label.set_markup(
u'<span foreground="blue" underline="single">%s</span>' % \ u'<span foreground="blue" underline="single">%s</span>' % \
gobject.markup_escape_text(newentry.feed_title)) gobject.markup_escape_text(newentry.feed_title))
else: else:
self.feed_title_label.set_markup( self.feed_title_label.set_markup(
gobject.markup_escape_text(newentry.feed_title)) gobject.markup_escape_text(newentry.feed_title))
self.feed_tagline_label.set_markup( self.feed_tagline_label.set_markup(
u'<small>%s</small>' % \ u'<small>%s</small>' % \
gobject.markup_escape_text(newentry.feed_tagline)) gobject.markup_escape_text(newentry.feed_tagline))
if newentry.uri is not None: if newentry.title:
self.entry_title_label.set_markup( if newentry.uri is not None:
self.entry_title_label.set_markup(
u'<span foreground="blue" underline="single">%s</span>' % \ u'<span foreground="blue" underline="single">%s</span>' % \
gobject.markup_escape_text(newentry.title)) gobject.markup_escape_text(newentry.title))
else: else:
self.entry_title_label.set_markup( self.entry_title_label.set_markup(
gobject.markup_escape_text(newentry.title)) gobject.markup_escape_text(newentry.title))
else:
self.entry_title_label.set_markup('')
self.last_modified_label.set_text(newentry.updated) self.last_modified_label.set_text(newentry.updated)
@ -114,11 +118,11 @@ class AtomWindow:
changed changed
""" """
count = len(self.__class__.entries) count = len(self.__class__.entries)
if count>0: if count:
self.new_entry_label.set_text(i18n.ngettext( self.new_entry_label.set_text(i18n.ngettext(
'You have received new entries (and %d not displayed):', 'You have received new entries (and %d not displayed):',
'You have received new entries (and %d not displayed):', count, 'You have received new entries (and %d not displayed):', count,
count, count)) count, count))
self.next_button.set_sensitive(True) self.next_button.set_sensitive(True)
else: else:
self.new_entry_label.set_text(_('You have received new entry:')) self.new_entry_label.set_text(_('You have received new entry:'))
@ -131,7 +135,7 @@ class AtomWindow:
def on_next_button_clicked(self, widget): def on_next_button_clicked(self, widget):
self.displayNextEntry() self.displayNextEntry()
def on_entry_title_button_press_event(self, widget, event): def on_entry_title_eventbox_button_press_event(self, widget, event):
#FIXME: make it using special gtk2.10 widget #FIXME: make it using special gtk2.10 widget
if event.button == 1: # left click if event.button == 1: # left click
uri = self.entry.uri uri = self.entry.uri
@ -139,7 +143,7 @@ class AtomWindow:
helpers.launch_browser_mailer('url', uri) helpers.launch_browser_mailer('url', uri)
return True return True
def on_feed_title_button_press_event(self, widget, event): def on_feed_title_eventbox_button_press_event(self, widget, event):
#FIXME: make it using special gtk2.10 widget #FIXME: make it using special gtk2.10 widget
if event.button == 1: # left click if event.button == 1: # left click
uri = self.entry.feed_uri uri = self.entry.feed_uri

View File

@ -1,7 +1,7 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*-
## src/cell_renderer_image.py ## src/cell_renderer_image.py
## ##
## Copyright (C) 2003-2008 Yann Leboulanger <asterix AT lagaule.org> ## Copyright (C) 2003-2010 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2005 Vincent Hanquez <tab AT snarc.org> ## Copyright (C) 2005 Vincent Hanquez <tab AT snarc.org>
## Copyright (C) 2005-2007 Nikos Kouremenos <kourem AT gmail.com> ## Copyright (C) 2005-2007 Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2006 Travis Shirk <travis AT pobox.com> ## Copyright (C) 2006 Travis Shirk <travis AT pobox.com>

View File

@ -2,8 +2,8 @@
## src/chat_control.py ## src/chat_control.py
## ##
## Copyright (C) 2006 Dimitur Kirov <dkirov AT gmail.com> ## Copyright (C) 2006 Dimitur Kirov <dkirov AT gmail.com>
## Copyright (C) 2006-2008 Yann Leboulanger <asterix AT lagaule.org> ## Copyright (C) 2006-2010 Yann Leboulanger <asterix AT lagaule.org>
## Jean-Marie Traissard <jim AT lapin.org> ## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
## Nikos Kouremenos <kourem AT gmail.com> ## Nikos Kouremenos <kourem AT gmail.com>
## Travis Shirk <travis AT pobox.com> ## Travis Shirk <travis AT pobox.com>
## Copyright (C) 2007 Lukas Petrovicky <lukas AT petrovicky.net> ## Copyright (C) 2007 Lukas Petrovicky <lukas AT petrovicky.net>
@ -94,6 +94,15 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
A base class containing a banner, ConversationTextview, MessageTextView A base class containing a banner, ConversationTextview, MessageTextView
""" """
keymap = gtk.gdk.keymap_get_default()
try:
keycode_c = keymap.get_entries_for_keyval(gtk.keysyms.c)[0][0]
except TypeError:
keycode_c = 54
try:
keycode_ins = keymap.get_entries_for_keyval(gtk.keysyms.Insert)[0][0]
except TypeError:
keycode_ins = 118
def make_href(self, match): def make_href(self, match):
url_color = gajim.config.get('urlmsgcolor') url_color = gajim.config.get('urlmsgcolor')
url = match.group() url = match.group()
@ -147,7 +156,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
self.draw_banner_text() self.draw_banner_text()
self._update_banner_state_image() self._update_banner_state_image()
gajim.plugin_manager.gui_extension_point('chat_control_base_draw_banner', gajim.plugin_manager.gui_extension_point('chat_control_base_draw_banner',
self) self)
def draw_banner_text(self): def draw_banner_text(self):
""" """
@ -231,6 +240,29 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
def status_url_clicked(self, widget, url): def status_url_clicked(self, widget, url):
helpers.launch_browser_mailer('url', url) helpers.launch_browser_mailer('url', url)
def setup_seclabel(self, combo):
self.seclabel_combo = combo
self.seclabel_combo.hide()
self.seclabel_combo.set_no_show_all(True)
lb = gtk.ListStore(str)
self.seclabel_combo.set_model(lb)
cell = gtk.CellRendererText()
cell.set_property('xpad', 5) # padding for status text
self.seclabel_combo.pack_start(cell, True)
# text to show is in in first column of liststore
self.seclabel_combo.add_attribute(cell, 'text', 0)
if gajim.connections[self.account].seclabel_supported:
gajim.connections[self.account].seclabel_catalogue(self.contact.jid, self.on_seclabels_ready)
def on_seclabels_ready(self):
lb = self.seclabel_combo.get_model()
lb.clear()
for label in gajim.connections[self.account].seclabel_catalogues[self.contact.jid][2]:
lb.append([label])
self.seclabel_combo.set_active(0)
self.seclabel_combo.set_no_show_all(False)
self.seclabel_combo.show_all()
def __init__(self, type_id, parent_win, widget_name, contact, acct, def __init__(self, type_id, parent_win, widget_name, contact, acct,
resource=None): resource=None):
# Undo needs this variable to know if space has been pressed. # Undo needs this variable to know if space has been pressed.
@ -383,7 +415,6 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
# instance object (also subclasses, eg. ChatControl or GroupchatControl) # instance object (also subclasses, eg. ChatControl or GroupchatControl)
gajim.plugin_manager.gui_extension_point('chat_control_base', self) gajim.plugin_manager.gui_extension_point('chat_control_base', self)
def set_speller(self): def set_speller(self):
# now set the one the user selected # now set the one the user selected
per_type = 'contacts' per_type = 'contacts'
@ -419,7 +450,6 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
i += 1 i += 1
menu.show_all() menu.show_all()
def shutdown(self): def shutdown(self):
# PluginSystem: removing GUI extension points connected with ChatControlBase # PluginSystem: removing GUI extension points connected with ChatControlBase
# instance object # instance object
@ -568,8 +598,11 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
self.connect_style_event(widget, opts[0], opts[1]) self.connect_style_event(widget, opts[0], opts[1])
def _conv_textview_key_press_event(self, widget, event): def _conv_textview_key_press_event(self, widget, event):
if (event.state & gtk.gdk.CONTROL_MASK and event.keyval in (gtk.keysyms.c, # translate any layout to latin_layout
gtk.keysyms.Insert)) or (event.state & gtk.gdk.SHIFT_MASK and \ keymap = gtk.gdk.keymap_get_default()
keycode = keymap.get_entries_for_keyval(event.keyval)[0][0]
if (event.state & gtk.gdk.CONTROL_MASK and keycode in (self.keycode_c,
self.keycode_ins)) or (event.state & gtk.gdk.SHIFT_MASK and \
event.keyval in (gtk.keysyms.Page_Down, gtk.keysyms.Page_Up)): event.keyval in (gtk.keysyms.Page_Down, gtk.keysyms.Page_Up)):
return False return False
self.parent_win.notebook.emit('key_press_event', event) self.parent_win.notebook.emit('key_press_event', event)
@ -729,6 +762,16 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
self.drag_entered_conv = True self.drag_entered_conv = True
self.conv_textview.tv.set_editable(True) self.conv_textview.tv.set_editable(True)
def get_seclabel(self):
label = None
if self.seclabel_combo is not None:
idx = self.seclabel_combo.get_active()
if idx != -1:
cat = gajim.connections[self.account].seclabel_catalogues[self.contact.jid]
lname = cat[2][idx]
label = cat[1][lname]
return label
def send_message(self, message, keyID='', type_='chat', chatstate=None, def send_message(self, message, keyID='', type_='chat', chatstate=None,
msg_id=None, composing_xep=None, resource=None, xhtml=None, msg_id=None, composing_xep=None, resource=None, xhtml=None,
callback=None, callback_args=[], process_commands=True): callback=None, callback_args=[], process_commands=True):
@ -741,9 +784,11 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
if process_commands and self.process_as_command(message): if process_commands and self.process_as_command(message):
return return
label = self.get_seclabel()
MessageControl.send_message(self, message, keyID, type_=type_, MessageControl.send_message(self, message, keyID, type_=type_,
chatstate=chatstate, msg_id=msg_id, composing_xep=composing_xep, chatstate=chatstate, msg_id=msg_id, composing_xep=composing_xep,
resource=resource, user_nick=self.user_nick, xhtml=xhtml, resource=resource, user_nick=self.user_nick, xhtml=xhtml,
label=label,
callback=callback, callback_args=callback_args) callback=callback, callback_args=callback_args)
# Record message history # Record message history
@ -777,7 +822,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
other_tags_for_name=[], other_tags_for_time=[], other_tags_for_name=[], other_tags_for_time=[],
other_tags_for_text=[], count_as_new=True, subject=None, other_tags_for_text=[], count_as_new=True, subject=None,
old_kind=None, xhtml=None, simple=False, xep0184_id=None, old_kind=None, xhtml=None, simple=False, xep0184_id=None,
graphics=True): graphics=True, displaymarking=None):
""" """
Print 'chat' type messages Print 'chat' type messages
""" """
@ -789,7 +834,8 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
end = True end = True
textview.print_conversation_line(text, jid, kind, name, tim, textview.print_conversation_line(text, jid, kind, name, tim,
other_tags_for_name, other_tags_for_time, other_tags_for_text, other_tags_for_name, other_tags_for_time, other_tags_for_text,
subject, old_kind, xhtml, simple=simple, graphics=graphics) subject, old_kind, xhtml, simple=simple, graphics=graphics,
displaymarking=displaymarking)
if xep0184_id is not None: if xep0184_id is not None:
textview.show_xep0184_warning(xep0184_id) textview.show_xep0184_warning(xep0184_id)
@ -1267,13 +1313,12 @@ class ChatControl(ChatControlBase):
A control for standard 1-1 chat A control for standard 1-1 chat
""" """
( (
JINGLE_STATE_NOT_AVAILABLE, JINGLE_STATE_NULL,
JINGLE_STATE_AVAILABLE,
JINGLE_STATE_CONNECTING, JINGLE_STATE_CONNECTING,
JINGLE_STATE_CONNECTION_RECEIVED, JINGLE_STATE_CONNECTION_RECEIVED,
JINGLE_STATE_CONNECTED, JINGLE_STATE_CONNECTED,
JINGLE_STATE_ERROR JINGLE_STATE_ERROR
) = range(6) ) = range(5)
TYPE_ID = message_control.TYPE_CHAT TYPE_ID = message_control.TYPE_CHAT
old_msg_kind = None # last kind of the printed message old_msg_kind = None # last kind of the printed message
@ -1360,9 +1405,11 @@ class ChatControl(ChatControlBase):
self._audio_banner_image = self.xml.get_object('audio_banner_image') self._audio_banner_image = self.xml.get_object('audio_banner_image')
self._video_banner_image = self.xml.get_object('video_banner_image') self._video_banner_image = self.xml.get_object('video_banner_image')
self.audio_sid = None self.audio_sid = None
self.audio_state = self.JINGLE_STATE_NOT_AVAILABLE self.audio_state = self.JINGLE_STATE_NULL
self.audio_available = False
self.video_sid = None self.video_sid = None
self.video_state = self.JINGLE_STATE_NOT_AVAILABLE self.video_state = self.JINGLE_STATE_NULL
self.video_available = False
self.update_toolbar() self.update_toolbar()
@ -1420,6 +1467,15 @@ class ChatControl(ChatControlBase):
id_ = widget.connect('released', self.on_num_button_released) id_ = widget.connect('released', self.on_num_button_released)
self.handlers[id_] = widget self.handlers[id_] = widget
self.dtmf_window = self.xml.get_object('dtmf_window')
id_ = self.dtmf_window.connect('focus-out-event',
self.on_dtmf_window_focus_out_event)
self.handlers[id_] = self.dtmf_window
widget = self.xml.get_object('dtmf_button')
id_ = widget.connect('clicked', self.on_dtmf_button_clicked)
self.handlers[id_] = widget
widget = self.xml.get_object('mic_hscale') widget = self.xml.get_object('mic_hscale')
id_ = widget.connect('value_changed', self.on_mic_hscale_value_changed) id_ = widget.connect('value_changed', self.on_mic_hscale_value_changed)
self.handlers[id_] = widget self.handlers[id_] = widget
@ -1436,6 +1492,7 @@ class ChatControl(ChatControlBase):
session = gajim.connections[self.account].find_controlless_session( session = gajim.connections[self.account].find_controlless_session(
self.contact.jid, resource) self.contact.jid, resource)
self.setup_seclabel(self.xml.get_object('label_selector'))
if session: if session:
session.control = self session.control = self
self.session = session self.session = session
@ -1488,38 +1545,24 @@ class ChatControl(ChatControlBase):
# Jingle detection # Jingle detection
if self.contact.supports(NS_JINGLE_ICE_UDP) and \ if self.contact.supports(NS_JINGLE_ICE_UDP) and \
gajim.HAVE_FARSIGHT and self.contact.resource: gajim.HAVE_FARSIGHT and self.contact.resource:
if self.contact.supports(NS_JINGLE_RTP_AUDIO): self.audio_available = self.contact.supports(NS_JINGLE_RTP_AUDIO)
if self.audio_state == self.JINGLE_STATE_NOT_AVAILABLE: self.video_available = self.contact.supports(NS_JINGLE_RTP_VIDEO)
self.set_audio_state('available')
else:
self.set_audio_state('not_available')
if self.contact.supports(NS_JINGLE_RTP_VIDEO):
if self.video_state == self.JINGLE_STATE_NOT_AVAILABLE:
self.set_video_state('available')
else:
self.set_video_state('not_available')
else: else:
if self.audio_state != self.JINGLE_STATE_NOT_AVAILABLE: if self.video_available or self.audio_available:
self.set_audio_state('not_available') self.stop_jingle()
if self.video_state != self.JINGLE_STATE_NOT_AVAILABLE: self.video_available = False
self.set_video_state('not_available') self.audio_available = False
# Audio buttons # Audio buttons
if self.audio_state == self.JINGLE_STATE_NOT_AVAILABLE: self._audio_button.set_sensitive(self.audio_available)
self._audio_button.set_sensitive(False)
else:
self._audio_button.set_sensitive(True)
# Video buttons # Video buttons
if self.video_state == self.JINGLE_STATE_NOT_AVAILABLE: self._video_button.set_sensitive(self.video_available)
self._video_button.set_sensitive(False)
else:
self._video_button.set_sensitive(True)
# Send file # Send file
if self.contact.supports(NS_FILE) and self.contact.resource: if self.contact.supports(NS_FILE) and self.contact.resource:
self._send_file_button.set_sensitive(True) self._send_file_button.set_sensitive(True)
self._send_file_button.set_tooltip_text('')
else: else:
self._send_file_button.set_sensitive(False) self._send_file_button.set_sensitive(False)
if not self.contact.supports(NS_FILE): if not self.contact.supports(NS_FILE):
@ -1554,18 +1597,16 @@ class ChatControl(ChatControlBase):
else: else:
img.hide() img.hide()
# PluginSystem: adding GUI extension point for this ChatControl # PluginSystem: adding GUI extension point for this ChatControl
# instance object # instance object
gajim.plugin_manager.gui_extension_point('chat_control', self) gajim.plugin_manager.gui_extension_point('chat_control', self)
def _update_jingle(self, jingle_type): def _update_jingle(self, jingle_type):
if jingle_type not in ('audio', 'video'): if jingle_type not in ('audio', 'video'):
return return
banner_image = getattr(self, '_' + jingle_type + '_banner_image') banner_image = getattr(self, '_' + jingle_type + '_banner_image')
state = getattr(self, jingle_type + '_state') state = getattr(self, jingle_type + '_state')
if state in (self.JINGLE_STATE_NOT_AVAILABLE, if state == self.JINGLE_STATE_NULL:
self.JINGLE_STATE_AVAILABLE):
banner_image.hide() banner_image.hide()
else: else:
banner_image.show() banner_image.show()
@ -1585,7 +1626,7 @@ class ChatControl(ChatControlBase):
def update_audio(self): def update_audio(self):
self._update_jingle('audio') self._update_jingle('audio')
vbox = self.xml.get_object('audio_vbox') hbox = self.xml.get_object('audio_buttons_hbox')
if self.audio_state == self.JINGLE_STATE_CONNECTED: if self.audio_state == self.JINGLE_STATE_CONNECTED:
# Set volume from config # Set volume from config
input_vol = gajim.config.get('audio_input_volume') input_vol = gajim.config.get('audio_input_volume')
@ -1595,11 +1636,11 @@ class ChatControl(ChatControlBase):
self.xml.get_object('mic_hscale').set_value(input_vol) self.xml.get_object('mic_hscale').set_value(input_vol)
self.xml.get_object('sound_hscale').set_value(output_vol) self.xml.get_object('sound_hscale').set_value(output_vol)
# Show vbox # Show vbox
vbox.set_no_show_all(False) hbox.set_no_show_all(False)
vbox.show_all() hbox.show_all()
elif not self.audio_sid: elif not self.audio_sid:
vbox.set_no_show_all(True) hbox.set_no_show_all(True)
vbox.hide() hbox.hide()
def update_video(self): def update_video(self):
self._update_jingle('video') self._update_jingle('video')
@ -1617,43 +1658,42 @@ class ChatControl(ChatControlBase):
# update MessageWindow._controls # update MessageWindow._controls
self.parent_win.change_jid(self.account, old_full_jid, new_full_jid) self.parent_win.change_jid(self.account, old_full_jid, new_full_jid)
def stop_jingle(self, sid=None, reason=None):
if self.audio_sid and sid in (self.audio_sid, None):
self.close_jingle_content('audio')
if self.video_sid and sid in (self.video_sid, None):
self.close_jingle_content('video')
def _set_jingle_state(self, jingle_type, state, sid=None, reason=None): def _set_jingle_state(self, jingle_type, state, sid=None, reason=None):
if jingle_type not in ('audio', 'video'): if jingle_type not in ('audio', 'video'):
return return
if state in ('connecting', 'connected', 'stop') and reason: if state in ('connecting', 'connected', 'stop', 'error') and reason:
str = _('%(type)s state : %(state)s, reason: %(reason)s') % { str = _('%(type)s state : %(state)s, reason: %(reason)s') % {
'type': jingle_type.capitalize(), 'state': state, 'reason': reason} 'type': jingle_type.capitalize(), 'state': state, 'reason': reason}
self.print_conversation(str, 'info') self.print_conversation(str, 'info')
states = {'not_available': self.JINGLE_STATE_NOT_AVAILABLE, states = {'connecting': self.JINGLE_STATE_CONNECTING,
'available': self.JINGLE_STATE_AVAILABLE,
'connecting': self.JINGLE_STATE_CONNECTING,
'connection_received': self.JINGLE_STATE_CONNECTION_RECEIVED, 'connection_received': self.JINGLE_STATE_CONNECTION_RECEIVED,
'connected': self.JINGLE_STATE_CONNECTED, 'connected': self.JINGLE_STATE_CONNECTED,
'stop': self.JINGLE_STATE_AVAILABLE, 'stop': self.JINGLE_STATE_NULL,
'error': self.JINGLE_STATE_ERROR} 'error': self.JINGLE_STATE_ERROR}
if state in states: jingle_state = states[state]
jingle_state = states[state] if getattr(self, jingle_type + '_state') == jingle_state or state == 'error':
if getattr(self, jingle_type + '_state') == jingle_state: return
return
setattr(self, jingle_type + '_state', jingle_state)
# Destroy existing session with the user when he signs off if state == 'stop' and getattr(self, jingle_type + '_sid') not in (None, sid):
# We need to do that before modifying the sid return
if state == 'not_available':
gajim.connections[self.account].delete_jingle_session(
self.contact.get_full_jid(), getattr(self, jingle_type + '_sid'))
if state in ('not_available', 'available', 'stop'): setattr(self, jingle_type + '_state', jingle_state)
if jingle_state == self.JINGLE_STATE_NULL:
setattr(self, jingle_type + '_sid', None) setattr(self, jingle_type + '_sid', None)
if state in ('connection_received', 'connecting'): if state in ('connection_received', 'connecting'):
setattr(self, jingle_type + '_sid', sid) setattr(self, jingle_type + '_sid', sid)
if state in ('connecting', 'connected', 'connection_received'): getattr(self, '_' + jingle_type + '_button').set_active(jingle_state != self.JINGLE_STATE_NULL)
getattr(self, '_' + jingle_type + '_button').set_active(True)
elif state in ('not_available', 'stop'):
getattr(self, '_' + jingle_type + '_button').set_active(False)
getattr(self, 'update_' + jingle_type)() getattr(self, 'update_' + jingle_type)()
@ -1674,19 +1714,21 @@ class ChatControl(ChatControlBase):
def on_num_button_released(self, released): def on_num_button_released(self, released):
self._get_audio_content()._stop_dtmf() self._get_audio_content()._stop_dtmf()
def on_mic_hscale_value_changed(self, widget): def on_dtmf_button_clicked(self, widget):
value = widget.get_value() self.dtmf_window.show_all()
def on_dtmf_window_focus_out_event(self, widget, event):
self.dtmf_window.hide()
def on_mic_hscale_value_changed(self, widget, value):
self._get_audio_content().set_mic_volume(value / 100) self._get_audio_content().set_mic_volume(value / 100)
# Save volume to config # Save volume to config
# FIXME: Putting it here is maybe not the right thing to do?
gajim.config.set('audio_input_volume', value) gajim.config.set('audio_input_volume', value)
def on_sound_hscale_value_changed(self, widget): def on_sound_hscale_value_changed(self, widget, value):
value = widget.get_value()
self._get_audio_content().set_out_volume(value / 100) self._get_audio_content().set_out_volume(value / 100)
# Save volume to config # Save volume to config
# FIXME: Putting it here is maybe not the right thing to do?
gajim.config.set('audio_output_volume', value) gajim.config.set('audio_output_volume', value)
def on_avatar_eventbox_enter_notify_event(self, widget, event): def on_avatar_eventbox_enter_notify_event(self, widget, event):
@ -1708,6 +1750,8 @@ class ChatControl(ChatControlBase):
# do we have something bigger to show? # do we have something bigger to show?
if avatar_w > scaled_buf_w or avatar_h > scaled_buf_h: if avatar_w > scaled_buf_w or avatar_h > scaled_buf_h:
# wait for 0.5 sec in case we leave earlier # wait for 0.5 sec in case we leave earlier
if self.show_bigger_avatar_timeout_id is not None:
gobject.source_remove(self.show_bigger_avatar_timeout_id)
self.show_bigger_avatar_timeout_id = gobject.timeout_add(500, self.show_bigger_avatar_timeout_id = gobject.timeout_add(500,
self.show_bigger_avatar, widget) self.show_bigger_avatar, widget)
@ -1718,6 +1762,7 @@ class ChatControl(ChatControlBase):
# did we add a timeout? if yes remove it # did we add a timeout? if yes remove it
if self.show_bigger_avatar_timeout_id is not None: if self.show_bigger_avatar_timeout_id is not None:
gobject.source_remove(self.show_bigger_avatar_timeout_id) gobject.source_remove(self.show_bigger_avatar_timeout_id)
self.show_bigger_avatar_timeout_id = None
def on_avatar_eventbox_button_press_event(self, widget, event): def on_avatar_eventbox_button_press_event(self, widget, event):
""" """
@ -1727,8 +1772,8 @@ class ChatControl(ChatControlBase):
menu = gtk.Menu() menu = gtk.Menu()
menuitem = gtk.ImageMenuItem(gtk.STOCK_SAVE_AS) menuitem = gtk.ImageMenuItem(gtk.STOCK_SAVE_AS)
id_ = menuitem.connect('activate', id_ = menuitem.connect('activate',
gtkgui_helpers.on_avatar_save_as_menuitem_activate, gtkgui_helpers.on_avatar_save_as_menuitem_activate,
self.contact.jid, self.account, self.contact.get_shown_name()) self.contact.jid, self.contact.get_shown_name())
self.handlers[id_] = menuitem self.handlers[id_] = menuitem
menu.append(menuitem) menu.append(menuitem)
menu.show_all() menu.show_all()
@ -1899,12 +1944,16 @@ class ChatControl(ChatControlBase):
sid = getattr(self, jingle_type + '_sid') sid = getattr(self, jingle_type + '_sid')
if not sid: if not sid:
return return
setattr(self, jingle_type + '_sid', None)
setattr(self, jingle_type + '_state', self.JINGLE_STATE_NULL)
session = gajim.connections[self.account].get_jingle_session( session = gajim.connections[self.account].get_jingle_session(
self.contact.get_full_jid(), sid) self.contact.get_full_jid(), sid)
if session: if session:
content = session.get_content(jingle_type) content = session.get_content(jingle_type)
if content: if content:
session.remove_content(content.creator, content.name) session.remove_content(content.creator, content.name)
getattr(self, '_' + jingle_type + '_button').set_active(False)
getattr(self, 'update_' + jingle_type)()
def on_jingle_button_toggled(self, widget, jingle_type): def on_jingle_button_toggled(self, widget, jingle_type):
img_name = 'gajim-%s_%s' % ({'audio': 'mic', 'video': 'cam'}[jingle_type], img_name = 'gajim-%s_%s' % ({'audio': 'mic', 'video': 'cam'}[jingle_type],
@ -1913,7 +1962,7 @@ class ChatControl(ChatControlBase):
if widget.get_active(): if widget.get_active():
if getattr(self, jingle_type + '_state') == \ if getattr(self, jingle_type + '_state') == \
self.JINGLE_STATE_AVAILABLE: self.JINGLE_STATE_NULL:
sid = getattr(gajim.connections[self.account], sid = getattr(gajim.connections[self.account],
'start_' + jingle_type)(self.contact.get_full_jid()) 'start_' + jingle_type)(self.contact.get_full_jid())
getattr(self, 'set_' + jingle_type + '_state')('connecting', sid) getattr(self, 'set_' + jingle_type + '_state')('connecting', sid)
@ -2069,20 +2118,23 @@ class ChatControl(ChatControlBase):
gobject.source_remove(self.possible_inactive_timeout_id) gobject.source_remove(self.possible_inactive_timeout_id)
self._schedule_activity_timers() self._schedule_activity_timers()
def _on_sent(id_, contact, message, encrypted, xhtml): def _on_sent(id_, contact, message, encrypted, xhtml, label):
if contact.supports(NS_RECEIPTS) and gajim.config.get_per('accounts', if contact.supports(NS_RECEIPTS) and gajim.config.get_per('accounts',
self.account, 'request_receipt'): self.account, 'request_receipt'):
xep0184_id = id_ xep0184_id = id_
else: else:
xep0184_id = None xep0184_id = None
if label:
displaymarking = label.getTag('displaymarking')
else:
displaymarking = None
self.print_conversation(message, self.contact.jid, encrypted=encrypted, self.print_conversation(message, self.contact.jid, encrypted=encrypted,
xep0184_id=xep0184_id, xhtml=xhtml) xep0184_id=xep0184_id, xhtml=xhtml, displaymarking=displaymarking)
ChatControlBase.send_message(self, message, keyID, type_='chat', ChatControlBase.send_message(self, message, keyID, type_='chat',
chatstate=chatstate_to_send, composing_xep=composing_xep, chatstate=chatstate_to_send, composing_xep=composing_xep,
xhtml=xhtml, callback=_on_sent, xhtml=xhtml, callback=_on_sent,
callback_args=[contact, message, encrypted, xhtml], callback_args=[contact, message, encrypted, xhtml, self.get_seclabel()],
process_commands=process_commands) process_commands=process_commands)
def check_for_possible_paused_chatstate(self, arg): def check_for_possible_paused_chatstate(self, arg):
@ -2171,7 +2223,8 @@ class ChatControl(ChatControlBase):
self.session.is_loggable(), self.session and self.session.verified_identity) self.session.is_loggable(), self.session and self.session.verified_identity)
def print_conversation(self, text, frm='', tim=None, encrypted=False, def print_conversation(self, text, frm='', tim=None, encrypted=False,
subject=None, xhtml=None, simple=False, xep0184_id=None): subject=None, xhtml=None, simple=False, xep0184_id=None,
displaymarking=None):
""" """
Print a line in the conversation Print a line in the conversation
@ -2234,7 +2287,7 @@ class ChatControl(ChatControlBase):
xhtml = '<body xmlns="%s">%s</body>' % (NS_XHTML, xhtml) xhtml = '<body xmlns="%s">%s</body>' % (NS_XHTML, xhtml)
ChatControlBase.print_conversation_line(self, text, kind, name, tim, ChatControlBase.print_conversation_line(self, text, kind, name, tim,
subject=subject, old_kind=self.old_msg_kind, xhtml=xhtml, subject=subject, old_kind=self.old_msg_kind, xhtml=xhtml,
simple=simple, xep0184_id=xep0184_id) simple=simple, xep0184_id=xep0184_id, displaymarking=displaymarking)
if text.startswith('/me ') or text.startswith('/me\n'): if text.startswith('/me ') or text.startswith('/me\n'):
self.old_msg_kind = None self.old_msg_kind = None
else: else:
@ -2423,9 +2476,8 @@ class ChatControl(ChatControlBase):
super(ChatControl, self).shutdown() super(ChatControl, self).shutdown()
# PluginSystem: removing GUI extension points connected with ChatControl # PluginSystem: removing GUI extension points connected with ChatControl
# instance object # instance object
gajim.plugin_manager.remove_gui_extension_point('chat_control', self) gajim.plugin_manager.remove_gui_extension_point('chat_control', self) # Send 'gone' chatstate
# Send 'gone' chatstate
self.send_chatstate('gone', self.contact) self.send_chatstate('gone', self.contact)
self.contact.chatstate = None self.contact.chatstate = None
self.contact.our_chatstate = None self.contact.our_chatstate = None
@ -2688,8 +2740,12 @@ class ChatControl(ChatControlBase):
kind = 'info' kind = 'info'
else: else:
kind = 'print_queue' kind = 'print_queue'
dm = None
if len(data) > 10:
dm = data[10]
self.print_conversation(data[0], kind, tim = data[3], self.print_conversation(data[0], kind, tim = data[3],
encrypted = data[4], subject = data[1], xhtml = data[7]) encrypted = data[4], subject = data[1], xhtml = data[7],
displaymarking=dm)
if len(data) > 6 and isinstance(data[6], int): if len(data) > 6 and isinstance(data[6], int):
message_ids.append(data[6]) message_ids.append(data[6])

View File

@ -1,4 +1,4 @@
# Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com> # Copyright (C) 2009-2010 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -14,7 +14,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
The command system providing scalable, clean and convenient architecture in The command system providing scalable, clean and convenient architecture
combination with declarative way of defining commands and a fair amount of in combination with declarative way of defining commands and a fair
automatization for routine processes. amount of automatization for routine processes.
""" """

View File

@ -1,4 +1,4 @@
# Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com> # Copyright (C) 2009-2010 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -14,9 +14,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
The backbone of the command system. Provides automatic dispatching which does The backbone of the command system. Provides automatic dispatching which
not require explicit registering commands or containers and remains active even does not require explicit registering commands or containers and remains
after everything is done, so new commands can be added during the runtime. active even after everything is done, so new commands can be added
during the runtime.
""" """
from types import NoneType from types import NoneType

View File

@ -1,4 +1,4 @@
# Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com> # Copyright (C) 2009-2010 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -15,8 +15,9 @@
class BaseError(Exception): class BaseError(Exception):
""" """
Common base for errors which relate to a specific command. Encapsulates Common base for errors which relate to a specific command.
everything needed to identify a command, by either its object or name. Encapsulates everything needed to identify a command, by either its
object or name.
""" """
def __init__(self, message, command=None, name=None): def __init__(self, message, command=None, name=None):
@ -44,3 +45,9 @@ class CommandError(BaseError):
Used to indicate errors occured during command execution. Used to indicate errors occured during command execution.
""" """
pass pass
class NoCommandError(BaseError):
"""
Used to indicate an inability to find the specified command.
"""
pass

View File

@ -1,4 +1,4 @@
# Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com> # Copyright (C) 2009-2010 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -14,8 +14,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
Provides a tiny framework with simple, yet powerful and extensible architecture Provides a tiny framework with simple, yet powerful and extensible
to implement commands in a streight and flexible, declarative way. architecture to implement commands in a streight and flexible,
declarative way.
""" """
import re import re
@ -24,46 +25,47 @@ from inspect import getargspec
from dispatching import Dispatcher, HostDispatcher, ContainerDispatcher from dispatching import Dispatcher, HostDispatcher, ContainerDispatcher
from mapping import parse_arguments, adapt_arguments from mapping import parse_arguments, adapt_arguments
from errors import DefinitionError, CommandError from errors import DefinitionError, CommandError, NoCommandError
class CommandHost(object): class CommandHost(object):
""" """
Command host is a hub between numerous command processors and command Command host is a hub between numerous command processors and
containers. Aimed to participate in a dispatching process in order to command containers. Aimed to participate in a dispatching process in
provide clean and transparent architecture. order to provide clean and transparent architecture.
""" """
__metaclass__ = HostDispatcher __metaclass__ = HostDispatcher
class CommandContainer(object): class CommandContainer(object):
""" """
Command container is an entity which holds defined commands, allowing them Command container is an entity which holds defined commands,
to be dispatched and proccessed correctly. Each command container may be allowing them to be dispatched and proccessed correctly. Each
bound to a one or more command hosts. command container may be bound to a one or more command hosts.
Bounding is controlled by the HOSTS variable, which must be defined in the Bounding is controlled by the HOSTS variable, which must be defined
body of the command container. This variable should contain a list of hosts in the body of the command container. This variable should contain a
to bound to, as a tuple or list. list of hosts to bound to, as a tuple or list.
""" """
__metaclass__ = ContainerDispatcher __metaclass__ = ContainerDispatcher
class CommandProcessor(object): class CommandProcessor(object):
""" """
Command processor is an immediate command emitter. It does not participate Command processor is an immediate command emitter. It does not
in the dispatching process directly, but must define a host to bound to. participate in the dispatching process directly, but must define a
host to bound to.
Bounding is controlled by the COMMAND_HOST variable, which must be defined Bounding is controlled by the COMMAND_HOST variable, which must be
in the body of the command processor. This variable should be set to a defined in the body of the command processor. This variable should
specific command host. be set to a specific command host.
""" """
# This defines a command prefix (or an initializer), which should preceede a # This defines a command prefix (or an initializer), which should
# a text in order it to be processed as a command. # preceede a a text in order it to be processed as a command.
COMMAND_PREFIX = '/' COMMAND_PREFIX = '/'
def process_as_command(self, text): def process_as_command(self, text):
""" """
Try to process text as a command. Returns True if it has been processed Try to process text as a command. Returns True if it has been
as a command and False otherwise. processed as a command and False otherwise.
""" """
prefix = text.startswith(self.COMMAND_PREFIX) prefix = text.startswith(self.COMMAND_PREFIX)
length = len(text) > len(self.COMMAND_PREFIX) length = len(text) > len(self.COMMAND_PREFIX)
@ -97,28 +99,28 @@ class CommandProcessor(object):
def command_preprocessor(self, command, name, arguments, args, kwargs): def command_preprocessor(self, command, name, arguments, args, kwargs):
""" """
Redefine this method in the subclass to execute custom code before Redefine this method in the subclass to execute custom code
command gets executed. before command gets executed.
If returns True then command execution will be interrupted and command If returns True then command execution will be interrupted and
will not be executed. command will not be executed.
""" """
pass pass
def command_postprocessor(self, command, name, arguments, args, kwargs, value): def command_postprocessor(self, command, name, arguments, args, kwargs, value):
""" """
Redefine this method in the subclass to execute custom code after Redefine this method in the subclass to execute custom code
command gets executed. after command gets executed.
""" """
pass pass
def looks_like_command(self, text, body, name, arguments): def looks_like_command(self, text, body, name, arguments):
""" """
This hook is being called before any processing, but after it was This hook is being called before any processing, but after it
determined that text looks like a command. was determined that text looks like a command.
If returns value other then None - then further processing will be If returns value other then None - then further processing will
interrupted and that value will be used to return from be interrupted and that value will be used to return from
process_as_command. process_as_command.
""" """
pass pass
@ -126,7 +128,7 @@ class CommandProcessor(object):
def get_command(self, name): def get_command(self, name):
command = Dispatcher.get_command(self.COMMAND_HOST, name) command = Dispatcher.get_command(self.COMMAND_HOST, name)
if not command: if not command:
raise CommandError("Command does not exist", name=name) raise NoCommandError("Command does not exist", name=name)
return command return command
def list_commands(self): def list_commands(self):
@ -136,8 +138,9 @@ class CommandProcessor(object):
class Command(object): class Command(object):
# These two regular expression patterns control how command documentation # These two regular expression patterns control how command
# will be formatted to be transformed to a normal, readable state. # documentation will be formatted to be transformed to a normal,
# readable state.
DOC_STRIP_PATTERN = re.compile(r'(?:^[ \t]+|\A\n)', re.MULTILINE) DOC_STRIP_PATTERN = re.compile(r'(?:^[ \t]+|\A\n)', re.MULTILINE)
DOC_FORMAT_PATTERN = re.compile(r'(?<!\n)\n(?!\n)', re.MULTILINE) DOC_FORMAT_PATTERN = re.compile(r'(?<!\n)\n(?!\n)', re.MULTILINE)
@ -145,8 +148,8 @@ class Command(object):
self.handler = handler self.handler = handler
self.names = names self.names = names
# Automatically set all the properties passed to a constructor by the # Automatically set all the properties passed to a constructor
# command decorator. # by the command decorator.
for key, value in properties.iteritems(): for key, value in properties.iteritems():
setattr(self, key, value) setattr(self, key, value)
@ -154,18 +157,20 @@ class Command(object):
try: try:
return self.handler(*args, **kwargs) return self.handler(*args, **kwargs)
# This allows to use a shortcuted way of raising an exception inside a # This allows to use a shortcuted way of raising an exception
# handler. That is to raise a CommandError without command or name # inside a handler. That is to raise a CommandError without
# attributes set. They will be set to a corresponding values right here # command or name attributes set. They will be set to a
# in case if they was not set by the one who raised an exception. # corresponding values right here in case if they was not set by
# the one who raised an exception.
except CommandError, error: except CommandError, error:
if not error.command and not error.name: if not error.command and not error.name:
raise CommandError(error.message, self) raise CommandError(error.message, self)
raise raise
# This one is a little bit too wide, but as Python does not have # This one is a little bit too wide, but as Python does not have
# anything more constrained - there is no other choice. Take a look here # anything more constrained - there is no other choice. Take a
# if command complains about invalid arguments while they are ok. # look here if command complains about invalid arguments while
# they are ok.
except TypeError: except TypeError:
raise CommandError("Command received invalid arguments", self) raise CommandError("Command received invalid arguments", self)
@ -185,8 +190,8 @@ class Command(object):
def extract_documentation(self): def extract_documentation(self):
""" """
Extract handler's documentation which is a doc-string and transform it Extract handler's documentation which is a doc-string and
to a usable format. transform it to a usable format.
Transformation is done based on the DOC_STRIP_PATTERN and Transformation is done based on the DOC_STRIP_PATTERN and
DOC_FORMAT_PATTERN regular expression patterns. DOC_FORMAT_PATTERN regular expression patterns.
@ -211,19 +216,19 @@ class Command(object):
def extract_specification(self): def extract_specification(self):
""" """
Extract handler's arguments specification, as it was defined preserving Extract handler's arguments specification, as it was defined
their order. preserving their order.
""" """
names, var_args, var_kwargs, defaults = getargspec(self.handler) names, var_args, var_kwargs, defaults = getargspec(self.handler)
# Behavior of this code need to be checked. Might yield incorrect # Behavior of this code need to be checked. Might yield
# results on some rare occasions. # incorrect results on some rare occasions.
spec_args = names[:-len(defaults) if defaults else len(names)] spec_args = names[:-len(defaults) if defaults else len(names)]
spec_kwargs = list(zip(names[-len(defaults):], defaults)) if defaults else {} spec_kwargs = list(zip(names[-len(defaults):], defaults)) if defaults else {}
# Removing self from arguments specification. Command handler should # Removing self from arguments specification. Command handler
# receive the processors as a first argument, which should be self by # should receive the processors as a first argument, which
# the canonical means. # should be self by the canonical means.
if spec_args.pop(0) != 'self': if spec_args.pop(0) != 'self':
raise DefinitionError("First argument must be self", self) raise DefinitionError("First argument must be self", self)
@ -231,44 +236,47 @@ class Command(object):
def command(*names, **properties): def command(*names, **properties):
""" """
A decorator for defining commands in a declarative way. Provides facilities A decorator for defining commands in a declarative way. Provides
for setting command's names and properties. facilities for setting command's names and properties.
Names should contain a set of names (aliases) by which the command can be Names should contain a set of names (aliases) by which the command
reached. If no names are given - the the native name (the one extracted from can be reached. If no names are given - the the native name (the one
the command handler) will be used. extracted from the command handler) will be used.
If include_native=True is given (default) and names is non-empty - then the If include_native=True is given (default) and names is non-empty -
native name of the command will be prepended in addition to the given names. then the native name of the command will be prepended in addition to
the given names.
If usage=True is given (default) - then command help will be appended with If usage=True is given (default) - then command help will be
autogenerated usage info, based of the command handler arguments appended with autogenerated usage info, based of the command handler
introspection. arguments introspection.
If source=True is given - then the first argument of the command will If source=True is given - then the first argument of the command
receive the source arguments, as a raw, unprocessed string. The further will receive the source arguments, as a raw, unprocessed string. The
mapping of arguments and options will not be affected. further mapping of arguments and options will not be affected.
If raw=True is given - then command considered to be raw and should define If raw=True is given - then command considered to be raw and should
positional arguments only. If it defines only one positional argument - this define positional arguments only. If it defines only one positional
argument will receive all the raw and unprocessed arguments. If the command argument - this argument will receive all the raw and unprocessed
defines more then one positional argument - then all the arguments except arguments. If the command defines more then one positional argument
the last one will be processed normally; the last argument will get what is - then all the arguments except the last one will be processed
left after the processing as raw and unprocessed string. normally; the last argument will get what is left after the
processing as raw and unprocessed string.
If empty=True is given - this will allow to call a raw command without If empty=True is given - this will allow to call a raw command
arguments. without arguments.
If extra=True is given - then all the extra arguments passed to a command If extra=True is given - then all the extra arguments passed to a
will be collected into a sequence and given to the last positional argument. command will be collected into a sequence and given to the last
positional argument.
If overlap=True is given - then all the extra arguments will be mapped as if If overlap=True is given - then all the extra arguments will be
they were values for the keyword arguments. mapped as if they were values for the keyword arguments.
If expand_short=True is given (default) - then short, one-letter options If expand_short=True is given (default) - then short, one-letter
will be expanded to a verbose ones, based of the comparison of the first options will be expanded to a verbose ones, based of the comparison
letter. If more then one option with the same first letter is given - then of the first letter. If more then one option with the same first
only first one will be used in the expansion. letter is given - then only first one will be used in the expansion.
""" """
names = list(names) names = list(names)
@ -300,34 +308,32 @@ def command(*names, **properties):
def decorator(handler): def decorator(handler):
""" """
Decorator which receives handler as a first argument and then wraps it Decorator which receives handler as a first argument and then
in the command which then returns back. wraps it in the command which then returns back.
""" """
command = Command(handler, *names, **properties) command = Command(handler, *names, **properties)
# Extract and inject a native name if either no other names are # Extract and inject a native name if either no other names are
# specified or include_native property is enabled, while making sure it # specified or include_native property is enabled, while making
# is going to be the first one in the list. # sure it is going to be the first one in the list.
if not names or include_native: if not names or include_native:
names.insert(0, command.native_name) names.insert(0, command.native_name)
command.names = tuple(names) command.names = tuple(names)
return command return command
# Workaround if we are getting called without parameters. Keep in mind that # Workaround if we are getting called without parameters. Keep in
# in that case - first item in the names will be the handler. # mind that in that case - first item in the names will be the
# handler.
if names and isinstance(names[0], FunctionType): if names and isinstance(names[0], FunctionType):
return decorator(names.pop(0)) return decorator(names.pop(0))
return decorator return decorator
def documentation(text): def doc(text):
""" """
This decorator is used to bind a documentation (a help) to a command. This decorator is used to bind a documentation (a help) to a
command.
Though this can be done easily by using doc-strings in a declarative and
Pythonic way - some of Gajim's developers are against it because of the
scaffolding needed to support the tranlation of such documentation.
""" """
def decorator(target): def decorator(target):
if isinstance(target, Command): if isinstance(target, Command):

View File

@ -1,4 +1,4 @@
# Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com> # Copyright (C) 2009-2010 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -14,6 +14,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
The implementation and auxilary systems which implement the standard Gajim The implementation and auxilary systems which implement the standard
commands and also provide an infrastructure for adding custom commands. Gajim commands and also provide an infrastructure for adding custom
commands.
""" """

View File

@ -1,4 +1,4 @@
# Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com> # Copyright (C) 2009-2010 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -14,21 +14,22 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
The module contains examples of how to create your own commands, by creating a The module contains examples of how to create your own commands, by
new command container and definding a set of commands. creating a new command container and definding a set of commands.
Keep in mind that this module is not being loaded, so the code will not be Keep in mind that this module is not being loaded, so the code will not
executed and commands defined here will not be detected. be executed and commands defined here will not be detected.
""" """
from ..framework import CommandContainer, command, documentation from ..framework import CommandContainer, command, doc
from hosts import ChatCommands, PrivateChatCommands, GroupChatCommands from hosts import ChatCommands, PrivateChatCommands, GroupChatCommands
class CustomCommonCommands(CommandContainer): class CustomCommonCommands(CommandContainer):
""" """
This command container bounds to all three available in the default This command container bounds to all three available in the default
implementation command hosts. This means that commands defined in this implementation command hosts. This means that commands defined in
container will be available to all - chat, private chat and a group chat. this container will be available to all - chat, private chat and a
group chat.
""" """
HOSTS = (ChatCommands, PrivateChatCommands, GroupChatCommands) HOSTS = (ChatCommands, PrivateChatCommands, GroupChatCommands)
@ -39,12 +40,13 @@ class CustomCommonCommands(CommandContainer):
First line of the doc string is called a description and will be First line of the doc string is called a description and will be
programmatically extracted and formatted. programmatically extracted and formatted.
After that you can give more help, like explanation of the options. This After that you can give more help, like explanation of the
one will be programatically extracted and formatted too. options. This one will be programatically extracted and
formatted too.
After all the documentation - there will be autogenerated (based on the After all the documentation - there will be autogenerated (based
method signature) usage information appended. You can turn it off on the method signature) usage information appended. You can
though, if you want. turn it off though, if you want.
""" """
return "I can't dance, you stupid fuck, I'm just a command system! A cool one, though..." return "I can't dance, you stupid fuck, I'm just a command system! A cool one, though..."
@ -56,15 +58,16 @@ class CustomChatCommands(CommandContainer):
HOSTS = (ChatCommands,) HOSTS = (ChatCommands,)
@documentation(_("The same as using a doc-string, except it supports translation")) @doc(_("The same as using a doc-string, except it supports translation"))
@command @command
def sing(self): def sing(self):
return "Are you phreaking kidding me? Buy yourself a damn stereo..." return "Are you phreaking kidding me? Buy yourself a damn stereo..."
class CustomPrivateChatCommands(CommandContainer): class CustomPrivateChatCommands(CommandContainer):
""" """
This command container bounds only to the PrivateChatCommands command host. This command container bounds only to the PrivateChatCommands
Therefore command defined here will be available only to a private chat. command host. Therefore command defined here will be available only
to a private chat.
""" """
HOSTS = (PrivateChatCommands,) HOSTS = (PrivateChatCommands,)
@ -75,8 +78,9 @@ class CustomPrivateChatCommands(CommandContainer):
class CustomGroupChatCommands(CommandContainer): class CustomGroupChatCommands(CommandContainer):
""" """
This command container bounds only to the GroupChatCommands command host. This command container bounds only to the GroupChatCommands command
Therefore command defined here will be available only to a group chat. host. Therefore command defined here will be available only to a
group chat.
""" """
HOSTS = (GroupChatCommands,) HOSTS = (GroupChatCommands,)

View File

@ -1,4 +1,4 @@
# Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com> # Copyright (C) 2009-2010 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -14,29 +14,29 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
The module defines a set of command hosts, which are bound to a different The module defines a set of command hosts, which are bound to a
command processors, which are the source of commands. different command processors, which are the source of commands.
""" """
from ..framework import CommandHost from ..framework import CommandHost
class ChatCommands(CommandHost): class ChatCommands(CommandHost):
""" """
This command host is bound to the command processor which processes commands This command host is bound to the command processor which processes
from a chat. commands from a chat.
""" """
pass pass
class PrivateChatCommands(CommandHost): class PrivateChatCommands(CommandHost):
""" """
This command host is bound to the command processor which processes commands This command host is bound to the command processor which processes
from a private chat. commands from a private chat.
""" """
pass pass
class GroupChatCommands(CommandHost): class GroupChatCommands(CommandHost):
""" """
This command host is bound to the command processor which processes commands This command host is bound to the command processor which processes
from a group chat. commands from a group chat.
""" """
pass pass

View File

@ -1,4 +1,4 @@
# Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com> # Copyright (C) 2009-2010 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -14,10 +14,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
Provides a glue to tie command system framework and the actual code where it Provides a glue to tie command system framework and the actual code
would be dropped in. Defines a little bit of scaffolding to support interaction where it would be dropped in. Defines a little bit of scaffolding to
between the two and a few utility methods so you don't need to dig up the code support interaction between the two and a few utility methods so you
itself code to write basic commands. don't need to dig up the code itself code to write basic commands.
""" """
from types import StringTypes from types import StringTypes
@ -26,17 +26,18 @@ from traceback import print_exc
from common import gajim from common import gajim
from ..framework import CommandProcessor from ..framework import CommandProcessor
from ..errors import CommandError from ..errors import CommandError, NoCommandError
class ChatCommandProcessor(CommandProcessor): class ChatCommandProcessor(CommandProcessor):
""" """
A basic scaffolding to provide convenient interaction between the command A basic scaffolding to provide convenient interaction between the
system and chat controls. command system and chat controls.
""" """
def process_as_command(self, text): def process_as_command(self, text):
self.command_succeeded = False
flag = super(ChatCommandProcessor, self).process_as_command(text) flag = super(ChatCommandProcessor, self).process_as_command(text)
if flag: if flag and self.command_succeeded:
self.add_history(text) self.add_history(text)
self.clear_input() self.clear_input()
return flag return flag
@ -44,40 +45,49 @@ class ChatCommandProcessor(CommandProcessor):
def execute_command(self, name, arguments): def execute_command(self, name, arguments):
try: try:
super(ChatCommandProcessor, self).execute_command(name, arguments) super(ChatCommandProcessor, self).execute_command(name, arguments)
except NoCommandError, error:
details = dict(name=error.name, message=error.message)
message = "%(name)s: %(message)s\n" % details
message += "Try using the //%(name)s or /say /%(name)s " % details
message += "construct if you intended to send it as a text."
self.echo(message, 'error')
except CommandError, error: except CommandError, error:
self.echo("%s: %s" %(error.name, error.message), 'error') self.echo("%s: %s" % (error.name, error.message), 'error')
except Exception: except Exception:
self.echo("An error occured while trying to execute the command", 'error') self.echo("An error occured while trying to execute the command", 'error')
print_exc() print_exc()
else:
self.command_succeeded = True
def looks_like_command(self, text, body, name, arguments): def looks_like_command(self, text, body, name, arguments):
# Command escape stuff ggoes here. If text was prepended by the command # Command escape stuff ggoes here. If text was prepended by the
# prefix twice, like //not_a_command (if prefix is set to /) then it # command prefix twice, like //not_a_command (if prefix is set
# will be escaped, that is sent just as a regular message with one (only # to /) then it will be escaped, that is sent just as a regular
# one) prefix removed, so message will be /not_a_command. # message with one (only one) prefix removed, so message will be
# /not_a_command.
if body.startswith(self.COMMAND_PREFIX): if body.startswith(self.COMMAND_PREFIX):
self.send(body) self.send(body)
return True return True
def command_preprocessor(self, command, name, arguments, args, kwargs): def command_preprocessor(self, command, name, arguments, args, kwargs):
# If command argument contain h or help option - forward it to the /help # If command argument contain h or help option - forward it to
# command. Dont forget to pass self, as all commands are unbound. And # the /help command. Dont forget to pass self, as all commands
# also don't forget to print output. # are unbound. And also don't forget to print output.
if 'h' in kwargs or 'help' in kwargs: if 'h' in kwargs or 'help' in kwargs:
help = self.get_command('help') help = self.get_command('help')
self.echo(help(self, name)) self.echo(help(self, name))
return True return True
def command_postprocessor(self, command, name, arguments, args, kwargs, value): def command_postprocessor(self, command, name, arguments, args, kwargs, value):
# If command returns a string - print it to a user. A convenient and # If command returns a string - print it to a user. A convenient
# sufficient in most simple cases shortcut to a using echo. # and sufficient in most simple cases shortcut to a using echo.
if value and isinstance(value, StringTypes): if value and isinstance(value, StringTypes):
self.echo(value) self.echo(value)
class CommandTools: class CommandTools:
""" """
Contains a set of basic tools and shortcuts you can use in your commands to Contains a set of basic tools and shortcuts you can use in your
performe some simple operations. commands to performe some simple operations.
""" """
def echo(self, text, kind='info'): def echo(self, text, kind='info'):
@ -107,8 +117,8 @@ class CommandTools:
def add_history(self, text): def add_history(self, text):
""" """
Add given text to the input history, so user can scroll through it using Add given text to the input history, so user can scroll through
ctrl + up/down arrow keys. it using ctrl + up/down arrow keys.
""" """
self.save_sent_message(text) self.save_sent_message(text)

View File

@ -1,4 +1,4 @@
# Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com> # Copyright (C) 2009-2010 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -27,7 +27,7 @@ from common.exceptions import GajimGeneralException
from common.logger import Constants from common.logger import Constants
from ..errors import CommandError from ..errors import CommandError
from ..framework import CommandContainer, command, documentation from ..framework import CommandContainer, command, doc
from ..mapping import generate_usage from ..mapping import generate_usage
from hosts import ChatCommands, PrivateChatCommands, GroupChatCommands from hosts import ChatCommands, PrivateChatCommands, GroupChatCommands
@ -38,25 +38,25 @@ lc = Constants()
class StandardCommonCommands(CommandContainer): class StandardCommonCommands(CommandContainer):
""" """
This command container contains standard commands which are common to all - This command container contains standard commands which are common
chat, private chat, group chat. to all - chat, private chat, group chat.
""" """
HOSTS = (ChatCommands, PrivateChatCommands, GroupChatCommands) HOSTS = (ChatCommands, PrivateChatCommands, GroupChatCommands)
@command @command
@documentation(_("Clear the text window")) @doc(_("Clear the text window"))
def clear(self): def clear(self):
self.conv_textview.clear() self.conv_textview.clear()
@command @command
@documentation(_("Hide the chat buttons")) @doc(_("Hide the chat buttons"))
def compact(self): def compact(self):
new_status = not self.hide_chat_buttons new_status = not self.hide_chat_buttons
self.chat_buttons_set_visible(new_status) self.chat_buttons_set_visible(new_status)
@command(overlap=True) @command(overlap=True)
@documentation(_("Show help on a given command or a list of available commands if -(-a)ll is given")) @doc(_("Show help on a given command or a list of available commands if -(-a)ll is given"))
def help(self, command=None, all=False): def help(self, command=None, all=False):
if command: if command:
command = self.get_command(command) command = self.get_command(command)
@ -83,17 +83,17 @@ class StandardCommonCommands(CommandContainer):
self.echo(help(self, 'help')) self.echo(help(self, 'help'))
@command(raw=True) @command(raw=True)
@documentation(_("Send a message to the contact")) @doc(_("Send a message to the contact"))
def say(self, message): def say(self, message):
self.send(message) self.send(message)
@command(raw=True) @command(raw=True)
@documentation(_("Send action (in the third person) to the current chat")) @doc(_("Send action (in the third person) to the current chat"))
def me(self, action): def me(self, action):
self.send("/me %s" % action) self.send("/me %s" % action)
@command('lastlog', overlap=True) @command('lastlog', overlap=True)
@documentation(_("Show logged messages which mention given text")) @doc(_("Show logged messages which mention given text"))
def grep(self, text, limit=None): def grep(self, text, limit=None):
results = gajim.logger.get_search_results_for_query(self.contact.jid, results = gajim.logger.get_search_results_for_query(self.contact.jid,
text, self.account) text, self.account)
@ -129,7 +129,7 @@ class StandardCommonCommands(CommandContainer):
self.echo(formatted) self.echo(formatted)
@command(raw=True, empty=True) @command(raw=True, empty=True)
@documentation(_(""" @doc(_("""
Set current the status Set current the status
Status can be given as one of the following values: online, away, Status can be given as one of the following values: online, away,
@ -142,7 +142,7 @@ class StandardCommonCommands(CommandContainer):
connection.change_status(status, message) connection.change_status(status, message)
@command(raw=True, empty=True) @command(raw=True, empty=True)
@documentation(_("Set the current status to away")) @doc(_("Set the current status to away"))
def away(self, message): def away(self, message):
if not message: if not message:
message = _("Away") message = _("Away")
@ -150,35 +150,40 @@ class StandardCommonCommands(CommandContainer):
connection.change_status('away', message) connection.change_status('away', message)
@command('back', raw=True, empty=True) @command('back', raw=True, empty=True)
@documentation(_("Set the current status to online")) @doc(_("Set the current status to online"))
def online(self, message): def online(self, message):
if not message: if not message:
message = _("Available") message = _("Available")
for connection in gajim.connections.itervalues(): for connection in gajim.connections.itervalues():
connection.change_status('online', message) connection.change_status('online', message)
class StandardChatCommands(CommandContainer): class StandardCommonChatCommands(CommandContainer):
""" """
This command container contains standard command which are unique to a chat. This command container contans standard commands, which are common
to a chat and a private chat only.
""" """
HOSTS = (ChatCommands,) HOSTS = (ChatCommands, PrivateChatCommands)
@command @command
@documentation(_("Send a ping to the contact")) @doc(_("Toggle the GPG encryption"))
def gpg(self):
self._toggle_gpg()
@command
@doc(_("Send a ping to the contact"))
def ping(self): def ping(self):
if self.account == gajim.ZEROCONF_ACC_NAME: if self.account == gajim.ZEROCONF_ACC_NAME:
raise CommandError(_('Command is not supported for zeroconf accounts')) raise CommandError(_('Command is not supported for zeroconf accounts'))
gajim.connections[self.account].sendPing(self.contact) gajim.connections[self.account].sendPing(self.contact)
@command @command
@documentation(_("Sends DTMF events through an open audio session")) @doc(_("Send DTMF events through an open audio session"))
def dtmf(self, events): def dtmf(self, events):
if not self.audio_sid: if not self.audio_sid:
raise CommandError(_("There is no open audio session with this contact")) raise CommandError(_("There is no open audio session with this contact"))
# Valid values for DTMF tones are *, # or a number # Valid values for DTMF tones are *, # or a number.
events = [event for event in events events = [e for e in events if e in ('*', '#') or e.isdigit()]
if event in ('*', '#') or event.isdigit()]
if events: if events:
session = gajim.connections[self.account].get_jingle_session( session = gajim.connections[self.account].get_jingle_session(
self.contact.get_full_jid(), self.audio_sid) self.contact.get_full_jid(), self.audio_sid)
@ -188,10 +193,10 @@ class StandardChatCommands(CommandContainer):
raise CommandError(_("No valid DTMF event specified")) raise CommandError(_("No valid DTMF event specified"))
@command @command
@documentation(_("Toggle audio session")) @doc(_("Toggle audio session"))
def audio(self): def audio(self):
if self.audio_state == self.JINGLE_STATE_NOT_AVAILABLE: if not self.audio_available:
raise CommandError(_("Video sessions are not available")) raise CommandError(_("Audio sessions are not available"))
else: else:
# A state of an audio session is toggled by inverting a state of the # A state of an audio session is toggled by inverting a state of the
# appropriate button. # appropriate button.
@ -199,9 +204,9 @@ class StandardChatCommands(CommandContainer):
self._audio_button.set_active(not state) self._audio_button.set_active(not state)
@command @command
@documentation(_("Toggle video session")) @doc(_("Toggle video session"))
def video(self): def video(self):
if self.video_state == self.JINGLE_STATE_NOT_AVAILABLE: if not self.video_available:
raise CommandError(_("Video sessions are not available")) raise CommandError(_("Video sessions are not available"))
else: else:
# A state of a video session is toggled by inverting a state of the # A state of a video session is toggled by inverting a state of the
@ -209,24 +214,32 @@ class StandardChatCommands(CommandContainer):
state = self._video_button.get_active() state = self._video_button.get_active()
self._video_button.set_active(not state) self._video_button.set_active(not state)
class StandardChatCommands(CommandContainer):
"""
This command container contains standard commands which are unique
to a chat.
"""
HOSTS = (ChatCommands,)
class StandardPrivateChatCommands(CommandContainer): class StandardPrivateChatCommands(CommandContainer):
""" """
This command container contains standard command which are unique to a This command container contains standard commands which are unique
private chat. to a private chat.
""" """
HOSTS = (PrivateChatCommands,) HOSTS = (PrivateChatCommands,)
class StandardGroupchatCommands(CommandContainer): class StandardGroupChatCommands(CommandContainer):
""" """
This command container contains standard command which are unique to a group This command container contains standard commands which are unique
chat. to a group chat.
""" """
HOSTS = (GroupChatCommands,) HOSTS = (GroupChatCommands,)
@command(raw=True) @command(raw=True)
@documentation(_("Change your nickname in a group chat")) @doc(_("Change your nickname in a group chat"))
def nick(self, new_nick): def nick(self, new_nick):
try: try:
new_nick = helpers.parse_resource(new_nick) new_nick = helpers.parse_resource(new_nick)
@ -236,7 +249,7 @@ class StandardGroupchatCommands(CommandContainer):
self.new_nick = new_nick self.new_nick = new_nick
@command('query', raw=True) @command('query', raw=True)
@documentation(_("Open a private chat window with a specified occupant")) @doc(_("Open a private chat window with a specified occupant"))
def chat(self, nick): def chat(self, nick):
nicks = gajim.contacts.get_nick_list(self.account, self.room_jid) nicks = gajim.contacts.get_nick_list(self.account, self.room_jid)
if nick in nicks: if nick in nicks:
@ -245,7 +258,7 @@ class StandardGroupchatCommands(CommandContainer):
raise CommandError(_("Nickname not found")) raise CommandError(_("Nickname not found"))
@command('msg', raw=True) @command('msg', raw=True)
@documentation(_("Open a private chat window with a specified occupant and send him a message")) @doc(_("Open a private chat window with a specified occupant and send him a message"))
def message(self, nick, a_message): def message(self, nick, a_message):
nicks = gajim.contacts.get_nick_list(self.account, self.room_jid) nicks = gajim.contacts.get_nick_list(self.account, self.room_jid)
if nick in nicks: if nick in nicks:
@ -254,7 +267,7 @@ class StandardGroupchatCommands(CommandContainer):
raise CommandError(_("Nickname not found")) raise CommandError(_("Nickname not found"))
@command(raw=True, empty=True) @command(raw=True, empty=True)
@documentation(_("Display or change a group chat topic")) @doc(_("Display or change a group chat topic"))
def topic(self, new_topic): def topic(self, new_topic):
if new_topic: if new_topic:
self.connection.send_gc_subject(self.room_jid, new_topic) self.connection.send_gc_subject(self.room_jid, new_topic)
@ -262,13 +275,13 @@ class StandardGroupchatCommands(CommandContainer):
return self.subject return self.subject
@command(raw=True, empty=True) @command(raw=True, empty=True)
@documentation(_("Invite a user to a room for a reason")) @doc(_("Invite a user to a room for a reason"))
def invite(self, jid, reason): def invite(self, jid, reason):
self.connection.send_invite(self.room_jid, jid, reason) self.connection.send_invite(self.room_jid, jid, reason)
return _("Invited %s to %s") % (jid, self.room_jid) return _("Invited %s to %s") % (jid, self.room_jid)
@command(raw=True, empty=True) @command(raw=True, empty=True)
@documentation(_("Join a group chat given by a jid, optionally using given nickname")) @doc(_("Join a group chat given by a jid, optionally using given nickname"))
def join(self, jid, nick): def join(self, jid, nick):
if not nick: if not nick:
nick = self.nick nick = self.nick
@ -285,12 +298,12 @@ class StandardGroupchatCommands(CommandContainer):
pass pass
@command('part', 'close', raw=True, empty=True) @command('part', 'close', raw=True, empty=True)
@documentation(_("Leave the groupchat, optionally giving a reason, and close tab or window")) @doc(_("Leave the groupchat, optionally giving a reason, and close tab or window"))
def leave(self, reason): def leave(self, reason):
self.parent_win.remove_tab(self, self.parent_win.CLOSE_COMMAND, reason) self.parent_win.remove_tab(self, self.parent_win.CLOSE_COMMAND, reason)
@command(raw=True, empty=True) @command(raw=True, empty=True)
@documentation(_(""" @doc(_("""
Ban user by a nick or a jid from a groupchat Ban user by a nick or a jid from a groupchat
If given nickname is not found it will be treated as a jid. If given nickname is not found it will be treated as a jid.
@ -302,14 +315,14 @@ class StandardGroupchatCommands(CommandContainer):
self.connection.gc_set_affiliation(self.room_jid, who, 'outcast', reason or str()) self.connection.gc_set_affiliation(self.room_jid, who, 'outcast', reason or str())
@command(raw=True, empty=True) @command(raw=True, empty=True)
@documentation(_("Kick user by a nick from a groupchat")) @doc(_("Kick user by a nick from a groupchat"))
def kick(self, who, reason): def kick(self, who, reason):
if not who in gajim.contacts.get_nick_list(self.account, self.room_jid): if not who in gajim.contacts.get_nick_list(self.account, self.room_jid):
raise CommandError(_("Nickname not found")) raise CommandError(_("Nickname not found"))
self.connection.gc_set_role(self.room_jid, who, 'none', reason or str()) self.connection.gc_set_role(self.room_jid, who, 'none', reason or str())
@command @command
@documentation(_("Display names of all group chat occupants")) @doc(_("Display names of all group chat occupants"))
def names(self, verbose=False): def names(self, verbose=False):
get_contact = lambda nick: gajim.contacts.get_gc_contact(self.account, self.room_jid, nick) get_contact = lambda nick: gajim.contacts.get_gc_contact(self.account, self.room_jid, nick)
nicks = gajim.contacts.get_nick_list(self.account, self.room_jid) nicks = gajim.contacts.get_nick_list(self.account, self.room_jid)
@ -330,11 +343,11 @@ class StandardGroupchatCommands(CommandContainer):
return ', '.join(nicks) return ', '.join(nicks)
@command('ignore', raw=True) @command('ignore', raw=True)
@documentation(_("Forbid an occupant to send you public or private messages")) @doc(_("Forbid an occupant to send you public or private messages"))
def block(self, who): def block(self, who):
self.on_block(None, who) self.on_block(None, who)
@command('unignore', raw=True) @command('unignore', raw=True)
@documentation(_("Allow an occupant to send you public or private messages")) @doc(_("Allow an occupant to send you public or private messages"))
def unblock(self, who): def unblock(self, who):
self.on_unblock(None, who) self.on_unblock(None, who)

View File

@ -1,4 +1,4 @@
# Copyright (C) 2009 Alexander Cherniuk <ts33kr@gmail.com> # Copyright (C) 2009-2010 Alexander Cherniuk <ts33kr@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -14,17 +14,16 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
The module contains routines to parse command arguments and map them to the The module contains routines to parse command arguments and map them to
command handler's positonal and keyword arguments. the command handler's positonal and keyword arguments.
Mapping is done in two stages: 1) parse arguments into positional arguments and Mapping is done in two stages: 1) parse arguments into positional
options; 2) adapt them to the specific command handler according to the command arguments and options; 2) adapt them to the specific command handler
properties. according to the command properties.
""" """
import re import re
from types import BooleanType, UnicodeType from types import BooleanType, UnicodeType
from types import TupleType, ListType
from operator import itemgetter from operator import itemgetter
from errors import DefinitionError, CommandError from errors import DefinitionError, CommandError
@ -34,28 +33,32 @@ from errors import DefinitionError, CommandError
ARG_PATTERN = re.compile(r'(\'|")?(?P<body>(?(1).+?|\S+))(?(1)\1)') ARG_PATTERN = re.compile(r'(\'|")?(?P<body>(?(1).+?|\S+))(?(1)\1)')
OPT_PATTERN = re.compile(r'(?<!\w)--?(?P<key>[\w-]+)(?:(?:=|\s)(\'|")?(?P<value>(?(2)[^-]+?|[^-\s]+))(?(2)\2))?') OPT_PATTERN = re.compile(r'(?<!\w)--?(?P<key>[\w-]+)(?:(?:=|\s)(\'|")?(?P<value>(?(2)[^-]+?|[^-\s]+))(?(2)\2))?')
# Option keys needs to be encoded to a specific encoding as Python does not # Option keys needs to be encoded to a specific encoding as Python does
# allow to expand dictionary with raw unicode strings as keys from a **kwargs. # not allow to expand dictionary with raw unicode strings as keys from a
# **kwargs.
KEY_ENCODING = 'UTF-8' KEY_ENCODING = 'UTF-8'
# Defines how complete representation of command usage (generated based on # Defines how complete representation of command usage (generated based
# command handler argument specification) will be rendered. # on command handler argument specification) will be rendered.
USAGE_PATTERN = 'Usage: %s %s' USAGE_PATTERN = 'Usage: %s %s'
def parse_arguments(arguments): def parse_arguments(arguments):
""" """
Simple yet effective and sufficient in most cases parser which parses Simple yet effective and sufficient in most cases parser which
command arguments and returns them as two lists. parses command arguments and returns them as two lists.
First list represents positional arguments as (argument, position), and First list represents positional arguments as (argument, position),
second representing options as (key, value, position) tuples, where position and second representing options as (key, value, position) tuples,
is a (start, end) span tuple of where it was found in the string. where position is a (start, end) span tuple of where it was found in
the string.
Options may be given in --long or -short format. As --option=value or Options may be given in --long or -short format. As --option=value
--option value or -option value. Keys without values will get None as value. or --option value or -option value. Keys without values will get
None as value.
Arguments and option values that contain spaces may be given as 'one two Arguments and option values that contain spaces may be given as 'one
three' or "one two three"; that is between single or double quotes. two three' or "one two three"; that is between single or double
quotes.
""" """
args, opts = [], [] args, opts = [], []
@ -90,14 +93,16 @@ def parse_arguments(arguments):
position = match.span() position = match.span()
args.append((body, position)) args.append((body, position))
# Primitive but sufficiently effective way of disposing of conflicted # Primitive but sufficiently effective way of disposing of
# sectors. Remove any arguments that intersect with options. # conflicted sectors. Remove any arguments that intersect with
# options.
for arg, position in args[:]: for arg, position in args[:]:
if intersects_opts(position): if intersects_opts(position):
args.remove((arg, position)) args.remove((arg, position))
# Primitive but sufficiently effective way of disposing of conflicted # Primitive but sufficiently effective way of disposing of
# sectors. Remove any options that intersect with arguments. # conflicted sectors. Remove any options that intersect with
# arguments.
for key, value, position in opts[:]: for key, value, position in opts[:]:
if intersects_args(position): if intersects_args(position):
opts.remove((key, value, position)) opts.remove((key, value, position))
@ -106,41 +111,40 @@ def parse_arguments(arguments):
def adapt_arguments(command, arguments, args, opts): def adapt_arguments(command, arguments, args, opts):
""" """
Adapt args and opts got from the parser to a specific handler by means of Adapt args and opts got from the parser to a specific handler by
arguments specified on command definition. That is transform them to *args means of arguments specified on command definition. That is
and **kwargs suitable for passing to a command handler. transform them to *args and **kwargs suitable for passing to a
command handler.
Dashes (-) in the option names will be converted to underscores. So you can Dashes (-) in the option names will be converted to underscores. So
map --one-more-option to a one_more_option=None. you can map --one-more-option to a one_more_option=None.
If the initial value of a keyword argument is a boolean (False in most If the initial value of a keyword argument is a boolean (False in
cases) - then this option will be treated as a switch, that is an option most cases) - then this option will be treated as a switch, that is
which does not take an argument. If a switch is followed by an argument - an option which does not take an argument. If a switch is followed
then this argument will be treated just like a normal positional argument. by an argument - then this argument will be treated just like a
normal positional argument.
If the initial value of a keyword argument is a sequence, that is a tuple or
list - then a value of this option will be considered correct only if it is
present in the sequence.
""" """
spec_args, spec_kwargs, var_args, var_kwargs = command.extract_specification() spec_args, spec_kwargs, var_args, var_kwargs = command.extract_specification()
norm_kwargs = dict(spec_kwargs) norm_kwargs = dict(spec_kwargs)
# Quite complex piece of neck-breaking logic to extract raw arguments if # Quite complex piece of neck-breaking logic to extract raw
# there is more, then one positional argument specified by the command. In # arguments if there is more, then one positional argument specified
# case if it's just one argument which is the collector - this is fairly # by the command. In case if it's just one argument which is the
# easy. But when it's more then one argument - the neck-breaking logic of # collector - this is fairly easy. But when it's more then one
# how to retrieve residual arguments as a raw, all in one piece string, # argument - the neck-breaking logic of how to retrieve residual
# kicks in. # arguments as a raw, all in one piece string, kicks in.
if command.raw: if command.raw:
if arguments: if arguments:
spec_fix = 1 if command.source else 0 spec_fix = 1 if command.source else 0
spec_len = len(spec_args) - spec_fix spec_len = len(spec_args) - spec_fix
arguments_end = len(arguments) - 1 arguments_end = len(arguments) - 1
# If there are any optional arguments given they should be either an # If there are any optional arguments given they should be
# unquoted postional argument or part of the raw argument. So we # either an unquoted postional argument or part of the raw
# find all optional arguments that can possibly be unquoted argument # argument. So we find all optional arguments that can
# and append them as is to the args. # possibly be unquoted argument and append them as is to the
# args.
for key, value, (start, end) in opts[:spec_len]: for key, value, (start, end) in opts[:spec_len]:
if value: if value:
end -= len(value) + 1 end -= len(value) + 1
@ -149,9 +153,9 @@ def adapt_arguments(command, arguments, args, opts):
else: else:
args.append((arguments[start:end], (start, end))) args.append((arguments[start:end], (start, end)))
# We need in-place sort here because after manipulations with # We need in-place sort here because after manipulations
# options order of arguments might be wrong and we just can't have # with options order of arguments might be wrong and we just
# more complex logic to not let that happen. # can't have more complex logic to not let that happen.
args.sort(key=itemgetter(1)) args.sort(key=itemgetter(1))
if spec_len > 1: if spec_len > 1:
@ -160,27 +164,28 @@ def adapt_arguments(command, arguments, args, opts):
except IndexError: except IndexError:
raise CommandError("Missing arguments", command) raise CommandError("Missing arguments", command)
# The essential point of the whole play. After boundaries are # The essential point of the whole play. After
# being determined (supposingly correct) we separate raw part # boundaries are being determined (supposingly correct)
# from the rest of arguments, which should be normally # we separate raw part from the rest of arguments, which
# processed. # should be normally processed.
raw = arguments[end:] raw = arguments[end:]
raw = raw.strip() or None raw = raw.strip() or None
if not raw and not command.empty: if not raw and not command.empty:
raise CommandError("Missing arguments", command) raise CommandError("Missing arguments", command)
# Discard residual arguments and all of the options as raw # Discard residual arguments and all of the options as
# command does not support options and if an option is given it # raw command does not support options and if an option
# is rather a part of a raw argument. # is given it is rather a part of a raw argument.
args = args[:spec_len - 1] args = args[:spec_len - 1]
opts = [] opts = []
args.append((raw, (end, arguments_end))) args.append((raw, (end, arguments_end)))
else: else:
# Substitue all of the arguments with only one, which contain # Substitue all of the arguments with only one, which
# raw and unprocessed arguments as a string. And discard all the # contain raw and unprocessed arguments as a string. And
# options, as raw command does not support them. # discard all the options, as raw command does not
# support them.
args = [(arguments, (0, arguments_end))] args = [(arguments, (0, arguments_end))]
opts = [] opts = []
else: else:
@ -189,16 +194,17 @@ def adapt_arguments(command, arguments, args, opts):
else: else:
raise CommandError("Missing arguments", command) raise CommandError("Missing arguments", command)
# The first stage of transforming options we have got to a format that can # The first stage of transforming options we have got to a format
# be used to associate them with declared keyword arguments. Substituting # that can be used to associate them with declared keyword
# dashes (-) in their names with underscores (_). # arguments. Substituting dashes (-) in their names with
# underscores (_).
for index, (key, value, position) in enumerate(opts): for index, (key, value, position) in enumerate(opts):
if '-' in key: if '-' in key:
opts[index] = (key.replace('-', '_'), value, position) opts[index] = (key.replace('-', '_'), value, position)
# The second stage of transforming options to an associatable state. # The second stage of transforming options to an associatable state.
# Expanding short, one-letter options to a verbose ones, if corresponding # Expanding short, one-letter options to a verbose ones, if
# optin has been given. # corresponding optin has been given.
if command.expand_short: if command.expand_short:
expanded = [] expanded = []
for spec_key, spec_value in norm_kwargs.iteritems(): for spec_key, spec_value in norm_kwargs.iteritems():
@ -210,26 +216,27 @@ def adapt_arguments(command, arguments, args, opts):
opts[index] = (spec_key, value, position) opts[index] = (spec_key, value, position)
break break
# Detect switches and set their values accordingly. If any of them carries a # Detect switches and set their values accordingly. If any of them
# value - append it to args. # carries a value - append it to args.
for index, (key, value, position) in enumerate(opts): for index, (key, value, position) in enumerate(opts):
if isinstance(norm_kwargs.get(key), BooleanType): if isinstance(norm_kwargs.get(key), BooleanType):
opts[index] = (key, True, position) opts[index] = (key, True, position)
if value: if value:
args.append((value, position)) args.append((value, position))
# Sorting arguments and options (just to be sure) in regarding to their # Sorting arguments and options (just to be sure) in regarding to
# positions in the string. # their positions in the string.
args.sort(key=itemgetter(1)) args.sort(key=itemgetter(1))
opts.sort(key=itemgetter(2)) opts.sort(key=itemgetter(2))
# Stripping down position information supplied with arguments and options as # Stripping down position information supplied with arguments and
# it won't be needed again. # options as it won't be needed again.
args = map(lambda (arg, position): arg, args) args = map(lambda (arg, position): arg, args)
opts = map(lambda (key, value, position): (key, value), opts) opts = map(lambda (key, value, position): (key, value), opts)
# If command has extra option enabled - collect all extra arguments and pass # If command has extra option enabled - collect all extra arguments
# them to a last positional argument command defines as a list. # and pass them to a last positional argument command defines as a
# list.
if command.extra: if command.extra:
if not var_args: if not var_args:
spec_fix = 1 if not command.source else 2 spec_fix = 1 if not command.source else 2
@ -240,9 +247,9 @@ def adapt_arguments(command, arguments, args, opts):
else: else:
raise DefinitionError("Can not have both, extra and *args") raise DefinitionError("Can not have both, extra and *args")
# Detect if positional arguments overlap keyword arguments. If so and this # Detect if positional arguments overlap keyword arguments. If so
# is allowed by command options - then map them directly to their options, # and this is allowed by command options - then map them directly to
# so they can get propert further processings. # their options, so they can get propert further processings.
spec_fix = 1 if command.source else 0 spec_fix = 1 if command.source else 0
spec_len = len(spec_args) - spec_fix spec_len = len(spec_args) - spec_fix
if len(args) > spec_len: if len(args) > spec_len:
@ -262,49 +269,32 @@ def adapt_arguments(command, arguments, args, opts):
if not isinstance(value, BooleanType): if not isinstance(value, BooleanType):
raise CommandError("%s: Switch can not take an argument" % key, command) raise CommandError("%s: Switch can not take an argument" % key, command)
# Detect every sequence constraint and ensure that if corresponding options # We need to encode every keyword argument to a simple string, not
# are given - they contain proper values, within the constraint range. # the unicode one, because ** expansion does not support it.
for key, value in opts:
initial = norm_kwargs.get(key)
if isinstance(initial, (TupleType, ListType)):
if value not in initial:
raise CommandError("%s: Invalid argument" % key, command)
# If argument to an option constrained by a sequence was not given - then
# it's value should be set to None.
for spec_key, spec_value in spec_kwargs:
if isinstance(spec_value, (TupleType, ListType)):
for key, value in opts:
if spec_key == key:
break
else:
opts.append((spec_key, None))
# We need to encode every keyword argument to a simple string, not the
# unicode one, because ** expansion does not support it.
for index, (key, value) in enumerate(opts): for index, (key, value) in enumerate(opts):
if isinstance(key, UnicodeType): if isinstance(key, UnicodeType):
opts[index] = (key.encode(KEY_ENCODING), value) opts[index] = (key.encode(KEY_ENCODING), value)
# Inject the source arguments as a string as a first argument, if command # Inject the source arguments as a string as a first argument, if
# has enabled the corresponding option. # command has enabled the corresponding option.
if command.source: if command.source:
args.insert(0, arguments) args.insert(0, arguments)
# Return *args and **kwargs in the form suitable for passing to a command # Return *args and **kwargs in the form suitable for passing to a
# handler and being expanded. # command handler and being expanded.
return tuple(args), dict(opts) return tuple(args), dict(opts)
def generate_usage(command, complete=True): def generate_usage(command, complete=True):
""" """
Extract handler's arguments specification and wrap them in a human-readable Extract handler's arguments specification and wrap them in a
format usage information. If complete is given - then USAGE_PATTERN will be human-readable format usage information. If complete is given - then
used to render the specification completly. USAGE_PATTERN will be used to render the specification completly.
""" """
spec_args, spec_kwargs, var_args, var_kwargs = command.extract_specification() spec_args, spec_kwargs, var_args, var_kwargs = command.extract_specification()
# Remove some special positional arguments from the specifiaction, but store # Remove some special positional arguments from the specifiaction,
# their names so they can be used for usage info generation. # but store their names so they can be used for usage info
# generation.
sp_source = spec_args.pop(0) if command.source else None sp_source = spec_args.pop(0) if command.source else None
sp_extra = spec_args.pop() if command.extra else None sp_extra = spec_args.pop() if command.extra else None
@ -317,8 +307,6 @@ def generate_usage(command, complete=True):
if isinstance(value, BooleanType): if isinstance(value, BooleanType):
value = str() value = str()
elif isinstance(value, (TupleType, ListType)):
value = '={%s}' % ', '.join(value)
else: else:
value = '=%s' % value value = '=%s' % value
@ -350,8 +338,8 @@ def generate_usage(command, complete=True):
if var_kwargs: if var_kwargs:
usage += (' ' if args else str()) + '[[%s]]' % var_kwargs usage += (' ' if args else str()) + '[[%s]]' % var_kwargs
# Native name will be the first one if it is included. Otherwise, names will # Native name will be the first one if it is included. Otherwise,
# be in the order they were specified. # names will be in the order they were specified.
if len(command.names) > 1: if len(command.names) > 1:
names = '%s (%s)' % (command.first_name, ', '.join(command.names[1:])) names = '%s (%s)' % (command.first_name, ', '.join(command.names[1:]))
else: else:

View File

@ -1,9 +1,8 @@
## src/common/GnuPG.py ## src/common/GnuPG.py
## ##
## Copyright (C) 2003-2008 Yann Leboulanger <asterix AT lagaule.org> ## Copyright (C) 2003-2010 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2005 Alex Mauer <hawke AT hawkesnest.net> ## Copyright (C) 2005 Alex Mauer <hawke AT hawkesnest.net>
## Copyright (C) 2005-2006 Nikos Kouremenos <kourem AT gmail.com> ## Copyright (C) 2005-2006 Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2005-2008 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2007 Stephan Erb <steve-e AT h3c.de> ## Copyright (C) 2007 Stephan Erb <steve-e AT h3c.de>
## Copyright (C) 2008 Jean-Marie Traissard <jim AT lapin.org> ## Copyright (C) 2008 Jean-Marie Traissard <jim AT lapin.org>
## Jonathan Schleifer <js-gajim AT webkeks.org> ## Jonathan Schleifer <js-gajim AT webkeks.org>

View File

@ -3,7 +3,7 @@
## ##
## Copyright (C) 2001 Frank J. Tobin <ftobin AT neverending.org> ## Copyright (C) 2001 Frank J. Tobin <ftobin AT neverending.org>
## Copyright (C) 2005 Nikos Kouremenos <kourem AT gmail.com> ## Copyright (C) 2005 Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2006-2007 Yann Leboulanger <asterix AT lagaule.org> ## Copyright (C) 2006-2010 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2008 Jean-Marie Traissard <jim AT lapin.org> ## Copyright (C) 2008 Jean-Marie Traissard <jim AT lapin.org>
## ##
## This file is part of Gajim. ## This file is part of Gajim.

View File

@ -3,7 +3,7 @@
## ##
## Copyright (C) 2006 Jean-Marie Traissard <jim AT lapin.org> ## Copyright (C) 2006 Jean-Marie Traissard <jim AT lapin.org>
## Tomasz Melcer <liori AT exroot.org> ## Tomasz Melcer <liori AT exroot.org>
## Copyright (C) 2006-2007 Yann Leboulanger <asterix AT lagaule.org> ## Copyright (C) 2006-2010 Yann Leboulanger <asterix AT lagaule.org>
## ##
## This file is part of Gajim. ## This file is part of Gajim.
## ##

View File

@ -3,7 +3,7 @@
## ##
## Copyright (C) 2007 Tomasz Melcer <liori AT exroot.org> ## Copyright (C) 2007 Tomasz Melcer <liori AT exroot.org>
## Travis Shirk <travis AT pobox.com> ## Travis Shirk <travis AT pobox.com>
## Copyright (C) 2007-2008 Yann Leboulanger <asterix AT lagaule.org> ## Copyright (C) 2007-2010 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2008 Brendan Taylor <whateley AT gmail.com> ## Copyright (C) 2008 Brendan Taylor <whateley AT gmail.com>
## Jonathan Schleifer <js-gajim AT webkeks.org> ## Jonathan Schleifer <js-gajim AT webkeks.org>
## Copyright (C) 2008-2009 Stephan Erb <steve-e AT h3c.de> ## Copyright (C) 2008-2009 Stephan Erb <steve-e AT h3c.de>

View File

@ -3,7 +3,7 @@
## ##
## Copyright (C) 2005-2006 Travis Shirk <travis AT pobox.com> ## Copyright (C) 2005-2006 Travis Shirk <travis AT pobox.com>
## Nikos Kouremenos <kourem AT gmail.com> ## Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2005-2008 Yann Leboulanger <asterix AT lagaule.org> ## Copyright (C) 2005-2010 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2006 Dimitur Kirov <dkirov AT gmail.com> ## Copyright (C) 2006 Dimitur Kirov <dkirov AT gmail.com>
## Copyright (C) 2007 Tomasz Melcer <liori AT exroot.org> ## Copyright (C) 2007 Tomasz Melcer <liori AT exroot.org>
## Copyright (C) 2008 Jean-Marie Traissard <jim AT lapin.org> ## Copyright (C) 2008 Jean-Marie Traissard <jim AT lapin.org>
@ -129,7 +129,9 @@ def split_db():
print 'spliting database' print 'spliting database'
if os.name == 'nt': if os.name == 'nt':
try: try:
OLD_LOG_DB_FOLDER = os.path.join(fse(os.environ[u'appdata']), u'Gajim') import configpaths
OLD_LOG_DB_FOLDER = os.path.join(configpaths.fse(
os.environ[u'appdata']), u'Gajim')
except KeyError: except KeyError:
OLD_LOG_DB_FOLDER = u'.' OLD_LOG_DB_FOLDER = u'.'
else: else:
@ -184,7 +186,8 @@ def check_and_possibly_move_config():
if os.name == 'nt': if os.name == 'nt':
try: try:
OLD_LOG_DB_FOLDER = os.path.join(fse(os.environ[u'appdata']), u'Gajim') OLD_LOG_DB_FOLDER = os.path.join(configpaths.fse(
os.environ[u'appdata']), u'Gajim')
except KeyError: except KeyError:
OLD_LOG_DB_FOLDER = u'.' OLD_LOG_DB_FOLDER = u'.'
else: else:
@ -340,5 +343,10 @@ def check_and_possibly_create_paths():
sys.exit() sys.exit()
def create_path(directory): def create_path(directory):
head, tail = os.path.split(directory)
if not os.path.exists(head):
create_path(head)
if os.path.exists(directory):
return
print _('creating %s directory') % directory print _('creating %s directory') % directory
os.mkdir(directory, 0700) os.mkdir(directory, 0700)

View File

@ -1,8 +1,8 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*-
## src/common/commands.py ## src/common/commands.py
## ##
## Copyright (C) 2006-2007 Yann Leboulanger <asterix AT lagaule.org> ## Copyright (C) 2006-2010 Yann Leboulanger <asterix AT lagaule.org>
## Tomasz Melcer <liori AT exroot.org> ## Copyright (C) 2006-2007 Tomasz Melcer <liori AT exroot.org>
## Copyright (C) 2007 Jean-Marie Traissard <jim AT lapin.org> ## Copyright (C) 2007 Jean-Marie Traissard <jim AT lapin.org>
## Copyright (C) 2008 Brendan Taylor <whateley AT gmail.com> ## Copyright (C) 2008 Brendan Taylor <whateley AT gmail.com>
## Stephan Erb <steve-e AT h3c.de> ## Stephan Erb <steve-e AT h3c.de>
@ -290,6 +290,41 @@ class ForwardMessagesCommand(AdHocCommand):
return False # finish the session return False # finish the session
class FwdMsgThenDisconnectCommand(AdHocCommand):
commandnode = 'fwd-msd-disconnect'
commandname = _('Forward unread message then disconnect')
@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, delayed=event.time_,
now=True)
response, cmd = self.buildResponse(request, status = 'completed')
cmd.addChild('note', {}, _('The status has been changed.'))
# if going offline, we need to push response so it won't go into
# queue and disappear
self.connection.connection.send(response, now = True)
# send new status
gajim.interface.roster.send_status(self.connection.name, 'offline', '')
# finish the session
return False
class ConnectionCommands: class ConnectionCommands:
""" """
This class depends on that it is a part of Connection() class This class depends on that it is a part of Connection() class
@ -299,7 +334,7 @@ class ConnectionCommands:
# a list of all commands exposed: node -> command class # a list of all commands exposed: node -> command class
self.__commands = {} self.__commands = {}
for cmdobj in (ChangeStatusCommand, ForwardMessagesCommand, for cmdobj in (ChangeStatusCommand, ForwardMessagesCommand,
LeaveGroupchatsCommand): LeaveGroupchatsCommand, FwdMsgThenDisconnectCommand):
self.__commands[cmdobj.commandnode] = cmdobj self.__commands[cmdobj.commandnode] = cmdobj
# a list of sessions; keys are tuples (jid, sessionid, node) # a list of sessions; keys are tuples (jid, sessionid, node)

View File

@ -1,7 +1,7 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*-
## src/common/config.py ## src/common/config.py
## ##
## Copyright (C) 2003-2008 Yann Leboulanger <asterix AT lagaule.org> ## Copyright (C) 2003-2010 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2004-2005 Vincent Hanquez <tab AT snarc.org> ## Copyright (C) 2004-2005 Vincent Hanquez <tab AT snarc.org>
## Copyright (C) 2005 Stéphan Kochen <stephan AT kochen.nl> ## Copyright (C) 2005 Stéphan Kochen <stephan AT kochen.nl>
## Copyright (C) 2005-2006 Dimitur Kirov <dkirov AT gmail.com> ## Copyright (C) 2005-2006 Dimitur Kirov <dkirov AT gmail.com>
@ -277,6 +277,8 @@ class Config:
'audio_output_device': [opt_str, 'autoaudiosink'], 'audio_output_device': [opt_str, 'autoaudiosink'],
'video_input_device': [opt_str, 'autovideosrc ! videoscale ! ffmpegcolorspace'], 'video_input_device': [opt_str, 'autovideosrc ! videoscale ! ffmpegcolorspace'],
'video_output_device': [opt_str, 'autovideosink'], 'video_output_device': [opt_str, 'autovideosink'],
'video_framerate': [opt_str, '', _('Optionally fix jingle output video framerate. Example: 10/1 or 25/2')],
'video_size': [opt_str, '', _('Optionally resize jingle output video. Example: 320x240')],
'audio_input_volume': [opt_int, 50], 'audio_input_volume': [opt_int, 50],
'audio_output_volume': [opt_int, 50], 'audio_output_volume': [opt_int, 50],
'use_stun_server': [opt_bool, True, _('If True, Gajim will try to use a STUN server when using jingle. The one in "stun_server" option, or the one given by the jabber server.')], 'use_stun_server': [opt_bool, True, _('If True, Gajim will try to use a STUN server when using jingle. The one in "stun_server" option, or the one given by the jabber server.')],
@ -289,6 +291,7 @@ class Config:
'name': [ opt_str, '', '', True ], 'name': [ opt_str, '', '', True ],
'hostname': [ opt_str, '', '', True ], 'hostname': [ opt_str, '', '', True ],
'anonymous_auth': [ opt_bool, False ], 'anonymous_auth': [ opt_bool, False ],
'client_cert': [ opt_str, '', '', True ],
'savepass': [ opt_bool, False ], 'savepass': [ opt_bool, False ],
'password': [ opt_str, '' ], 'password': [ opt_str, '' ],
'resource': [ opt_str, 'gajim', '', True ], 'resource': [ opt_str, 'gajim', '', True ],
@ -315,6 +318,7 @@ class Config:
'connection_types': [ opt_str, 'tls ssl plain', _('Ordered list (space separated) of connection type to try. Can contain tls, ssl or plain')], 'connection_types': [ opt_str, 'tls ssl plain', _('Ordered list (space separated) of connection type to try. Can contain tls, ssl or plain')],
'warn_when_plaintext_connection': [ opt_bool, True, _('Show a warning dialog before sending password on an plaintext connection.') ], 'warn_when_plaintext_connection': [ opt_bool, True, _('Show a warning dialog before sending password on an plaintext connection.') ],
'warn_when_insecure_ssl_connection': [ opt_bool, True, _('Show a warning dialog before using standard SSL library.') ], 'warn_when_insecure_ssl_connection': [ opt_bool, True, _('Show a warning dialog before using standard SSL library.') ],
'warn_when_insecure_password': [ opt_bool, True, _('Show a warning dialog before sending PLAIN password over a plain conenction.') ],
'ssl_fingerprint_sha1': [ opt_str, '', '', True ], 'ssl_fingerprint_sha1': [ opt_str, '', '', True ],
'ignore_ssl_errors': [ opt_str, '', _('Space separated list of ssl errors to ignore.') ], 'ignore_ssl_errors': [ opt_str, '', _('Space separated list of ssl errors to ignore.') ],
'use_srv': [ opt_bool, True, '', True ], 'use_srv': [ opt_bool, True, '', True ],
@ -451,8 +455,8 @@ class Config:
'urgency_hint': [opt_bool, False], 'urgency_hint': [opt_bool, False],
}, {}), }, {}),
'plugins': ({ 'plugins': ({
'active': [opt_bool, False, _('State whether plugins should be activated on exit (this is saved on Gajim exit). This option SHOULD NOT be used to (de)activate plug-ins. Use GUI instead.')], 'active': [opt_bool, False, _('State whether plugins should be activated on exit (this is saved on Gajim exit). This option SHOULD NOT be used to (de)activate plug-ins. Use GUI instead.')],
}, {}), },{}),
} }
statusmsg_default = { statusmsg_default = {

View File

@ -3,7 +3,7 @@
## ##
## Copyright (C) 2006 Jean-Marie Traissard <jim AT lapin.org> ## Copyright (C) 2006 Jean-Marie Traissard <jim AT lapin.org>
## Junglecow J <junglecow AT gmail.com> ## Junglecow J <junglecow AT gmail.com>
## Copyright (C) 2006-2007 Yann Leboulanger <asterix AT lagaule.org> ## Copyright (C) 2006-2010 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2007 Brendan Taylor <whateley AT gmail.com> ## Copyright (C) 2007 Brendan Taylor <whateley AT gmail.com>
## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org> ## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
## ##
@ -157,7 +157,7 @@ class ConfigPaths:
self.add('ICONS', None, os.path.join(basedir, windowsify(u'icons'))) self.add('ICONS', None, os.path.join(basedir, windowsify(u'icons')))
self.add('HOME', None, fse(os.path.expanduser('~'))) self.add('HOME', None, fse(os.path.expanduser('~')))
self.add('PLUGINS_BASE', None, os.path.join(basedir, self.add('PLUGINS_BASE', None, os.path.join(basedir,
windowsify(u'plugins'))) windowsify(u'plugins')))
try: try:
self.add('TMP', None, fse(tempfile.gettempdir())) self.add('TMP', None, fse(tempfile.gettempdir()))
except IOError, e: except IOError, e:

Some files were not shown because too many files have changed in this diff Show More