merged trunk into session_centric branch
This commit is contained in:
parent
b8882ba48e
commit
0b48b05218
68 changed files with 13704 additions and 7863 deletions
13
TODO.pep
Normal file
13
TODO.pep
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
• configure access model when changing it in the combobox
|
||||||
|
• PEP in status change
|
||||||
|
|
||||||
|
Tune use cases:
|
||||||
|
• on disconnection of an account set Tune to None
|
||||||
|
|
||||||
|
Tooltips use cases:
|
||||||
|
• Show PEP in GC tooltips
|
||||||
|
|
||||||
|
Mood/Activity use cases
|
||||||
|
• on connection of an account set them to None
|
||||||
|
• on disconnection of an account set them to None
|
||||||
|
• on explicit set publish them
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
echo "[encoding: UTF-8]" > po/POTFILES.in \
|
echo "[encoding: UTF-8]" > po/POTFILES.in \
|
||||||
&& ls -1 -U data/gajim.desktop.in.in data/glade/*.glade \
|
&& ls -1 -U data/gajim.desktop.in.in data/glade/*.glade \
|
||||||
src/*py src/common/*py src/common/zeroconf/*.py >> \
|
src/*py src/common/*py src/common/zeroconf/*.py src/osx/*.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
|
||||||
echo "***Error: pkg-config not found***"
|
echo "***Error: pkg-config not found***"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
AC_INIT([Gajim - A Jabber Instant Messager],
|
AC_INIT([Gajim - A Jabber Instant Messager],
|
||||||
[0.11.4.0-svn],[http://trac.gajim.org/],[gajim])
|
[0.11.4.2-svn],[http://trac.gajim.org/],[gajim])
|
||||||
AC_PREREQ([2.59])
|
AC_PREREQ([2.59])
|
||||||
AM_INIT_AUTOMAKE([1.8])
|
AM_INIT_AUTOMAKE([1.8])
|
||||||
AC_CONFIG_HEADER(config.h)
|
AC_CONFIG_HEADER(config.h)
|
||||||
|
|
|
@ -14,7 +14,13 @@ sounds_DATA = $(srcdir)/sounds/*.wav
|
||||||
otherdir = $(pkgdatadir)/data/other
|
otherdir = $(pkgdatadir)/data/other
|
||||||
other_DATA = other/servers.xml other/cacerts.pem
|
other_DATA = other/servers.xml other/cacerts.pem
|
||||||
|
|
||||||
man_MANS = gajim.1 gajim-remote.1
|
if BUILD_REMOTE_CONTROL
|
||||||
|
OPTIONAL_MAN = gajim-remote.1
|
||||||
|
else
|
||||||
|
OPTIONAL_MAN =
|
||||||
|
endif
|
||||||
|
|
||||||
|
man_MANS = gajim.1 $(OPTIONAL_MAN)
|
||||||
|
|
||||||
|
|
||||||
EXTRA_DIST = $(desktop_in_files) \
|
EXTRA_DIST = $(desktop_in_files) \
|
||||||
|
|
|
@ -17,6 +17,20 @@
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="pep_menuitem">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="label" translatable="yes">_Personal Events</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<child internal-child="image">
|
||||||
|
<widget class="GtkImage" id="menu-item-image7">
|
||||||
|
<property name="stock">gtk-home</property>
|
||||||
|
<property name="icon_size">1</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
|
<widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
|
|
@ -117,7 +117,7 @@ to the Jabber network.</property>
|
||||||
<widget class="GtkLabel" id="label270">
|
<widget class="GtkLabel" id="label270">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="xalign">0</property>
|
<property name="xalign">0</property>
|
||||||
<property name="label" translatable="yes"><b>Please fill in the data for your new account</b></property>
|
<property name="label" translatable="yes"><b>Please fill in the data for your existing account</b></property>
|
||||||
<property name="use_markup">True</property>
|
<property name="use_markup">True</property>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
|
|
File diff suppressed because it is too large
Load diff
158
data/glade/change_activity_dialog.glade
Normal file
158
data/glade/change_activity_dialog.glade
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||||
|
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||||
|
|
||||||
|
<glade-interface>
|
||||||
|
|
||||||
|
<widget class="GtkDialog" id="change_activity_dialog">
|
||||||
|
<property name="border_width">6</property>
|
||||||
|
<property name="title" translatable="yes"></property>
|
||||||
|
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||||
|
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||||
|
<property name="modal">False</property>
|
||||||
|
<property name="default_width">270</property>
|
||||||
|
<property name="resizable">True</property>
|
||||||
|
<property name="destroy_with_parent">False</property>
|
||||||
|
<property name="decorated">True</property>
|
||||||
|
<property name="skip_taskbar_hint">False</property>
|
||||||
|
<property name="skip_pager_hint">False</property>
|
||||||
|
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||||
|
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||||
|
<property name="focus_on_map">True</property>
|
||||||
|
<property name="urgency_hint">False</property>
|
||||||
|
<property name="has_separator">True</property>
|
||||||
|
<signal name="key_press_event" handler="on_change_status_message_dialog_key_press_event" last_modification_time="Wed, 16 Mar 2005 00:53:06 GMT"/>
|
||||||
|
|
||||||
|
<child internal-child="vbox">
|
||||||
|
<widget class="GtkVBox" id="dialog-vbox5">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="homogeneous">False</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
|
||||||
|
<child internal-child="action_area">
|
||||||
|
<widget class="GtkHButtonBox" id="dialog-action_area">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkButton" id="cancel_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_default">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="label">gtk-cancel</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||||
|
<property name="focus_on_click">True</property>
|
||||||
|
<property name="response_id">-6</property>
|
||||||
|
<signal name="clicked" handler="on_cancel_button_clicked" last_modification_time="Sat, 31 Mar 2007 07:58:52 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkButton" id="ok_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_default">True</property>
|
||||||
|
<property name="has_default">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="label">gtk-ok</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||||
|
<property name="focus_on_click">True</property>
|
||||||
|
<property name="response_id">-5</property>
|
||||||
|
<signal name="clicked" handler="on_ok_button_clicked" last_modification_time="Sat, 31 Mar 2007 07:57:55 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="pack_type">GTK_PACK_END</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkFrame" id="frame38">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="label_yalign">0.5</property>
|
||||||
|
<property name="shadow_type">GTK_SHADOW_NONE</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkAlignment" id="alignment107">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="xscale">1</property>
|
||||||
|
<property name="yscale">1</property>
|
||||||
|
<property name="top_padding">0</property>
|
||||||
|
<property name="bottom_padding">0</property>
|
||||||
|
<property name="left_padding">12</property>
|
||||||
|
<property name="right_padding">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkVBox" id="vbox112">
|
||||||
|
<property name="border_width">6</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="homogeneous">False</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkComboBox" id="combobox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="add_tearoffs">False</property>
|
||||||
|
<property name="focus_on_click">True</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkComboBox" id="combobox2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="add_tearoffs">False</property>
|
||||||
|
<property name="focus_on_click">True</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkEntry" id="entry">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="editable">True</property>
|
||||||
|
<property name="visibility">True</property>
|
||||||
|
<property name="max_length">0</property>
|
||||||
|
<property name="text" translatable="yes"></property>
|
||||||
|
<property name="has_frame">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="activates_default">False</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
|
||||||
|
</glade-interface>
|
145
data/glade/change_mood_dialog.glade
Normal file
145
data/glade/change_mood_dialog.glade
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||||
|
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||||
|
|
||||||
|
<glade-interface>
|
||||||
|
|
||||||
|
<widget class="GtkDialog" id="change_mood_dialog">
|
||||||
|
<property name="border_width">6</property>
|
||||||
|
<property name="title" translatable="yes"></property>
|
||||||
|
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||||
|
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||||
|
<property name="modal">False</property>
|
||||||
|
<property name="default_width">270</property>
|
||||||
|
<property name="resizable">True</property>
|
||||||
|
<property name="destroy_with_parent">False</property>
|
||||||
|
<property name="decorated">True</property>
|
||||||
|
<property name="skip_taskbar_hint">False</property>
|
||||||
|
<property name="skip_pager_hint">False</property>
|
||||||
|
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||||
|
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||||
|
<property name="focus_on_map">True</property>
|
||||||
|
<property name="urgency_hint">False</property>
|
||||||
|
<property name="has_separator">True</property>
|
||||||
|
<signal name="key_press_event" handler="on_change_status_message_dialog_key_press_event" last_modification_time="Wed, 16 Mar 2005 00:53:06 GMT"/>
|
||||||
|
|
||||||
|
<child internal-child="vbox">
|
||||||
|
<widget class="GtkVBox" id="dialog-vbox5">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="homogeneous">False</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
|
||||||
|
<child internal-child="action_area">
|
||||||
|
<widget class="GtkHButtonBox" id="dialog-action_area">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkButton" id="cancel_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_default">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="label">gtk-cancel</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||||
|
<property name="focus_on_click">True</property>
|
||||||
|
<property name="response_id">-6</property>
|
||||||
|
<signal name="clicked" handler="on_cancel_button_clicked" last_modification_time="Sat, 31 Mar 2007 07:58:52 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkButton" id="ok_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_default">True</property>
|
||||||
|
<property name="has_default">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="label">gtk-ok</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||||
|
<property name="focus_on_click">True</property>
|
||||||
|
<property name="response_id">-5</property>
|
||||||
|
<signal name="clicked" handler="on_ok_button_clicked" last_modification_time="Sat, 31 Mar 2007 07:57:55 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="pack_type">GTK_PACK_END</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkFrame" id="frame38">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="label_yalign">0.5</property>
|
||||||
|
<property name="shadow_type">GTK_SHADOW_NONE</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkAlignment" id="alignment107">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="xscale">1</property>
|
||||||
|
<property name="yscale">1</property>
|
||||||
|
<property name="top_padding">0</property>
|
||||||
|
<property name="bottom_padding">0</property>
|
||||||
|
<property name="left_padding">12</property>
|
||||||
|
<property name="right_padding">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkVBox" id="vbox112">
|
||||||
|
<property name="border_width">6</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="homogeneous">False</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkComboBox" id="combobox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="add_tearoffs">False</property>
|
||||||
|
<property name="focus_on_click">True</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkEntry" id="entry">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="editable">True</property>
|
||||||
|
<property name="visibility">True</property>
|
||||||
|
<property name="max_length">0</property>
|
||||||
|
<property name="text" translatable="yes"></property>
|
||||||
|
<property name="has_frame">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="activates_default">False</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
|
||||||
|
</glade-interface>
|
|
@ -43,7 +43,7 @@
|
||||||
<widget class="GtkVBox" id="vbox1">
|
<widget class="GtkVBox" id="vbox1">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkVBox" id="vbox2">
|
<widget class="GtkVBox" id="welcome_vbox">
|
||||||
<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>
|
||||||
<child>
|
<child>
|
||||||
|
|
135
data/glade/manage_pep_services_window.glade
Normal file
135
data/glade/manage_pep_services_window.glade
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||||
|
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||||
|
|
||||||
|
<glade-interface>
|
||||||
|
|
||||||
|
<widget class="GtkWindow" id="manage_pep_services_window">
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="title" translatable="yes"></property>
|
||||||
|
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||||
|
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||||
|
<property name="modal">False</property>
|
||||||
|
<property name="default_width">350</property>
|
||||||
|
<property name="default_height">150</property>
|
||||||
|
<property name="resizable">True</property>
|
||||||
|
<property name="destroy_with_parent">False</property>
|
||||||
|
<property name="decorated">True</property>
|
||||||
|
<property name="skip_taskbar_hint">False</property>
|
||||||
|
<property name="skip_pager_hint">False</property>
|
||||||
|
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
|
||||||
|
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||||
|
<property name="focus_on_map">True</property>
|
||||||
|
<property name="urgency_hint">False</property>
|
||||||
|
<signal name="destroy" handler="on_manage_pep_services_window_destroy"/>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkVBox" id="vbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="homogeneous">False</property>
|
||||||
|
<property name="spacing">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkScrolledWindow" id="scrolledwindow1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||||
|
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||||
|
<property name="shadow_type">GTK_SHADOW_NONE</property>
|
||||||
|
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkTreeView" id="services_treeview">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="headers_visible">True</property>
|
||||||
|
<property name="rules_hint">False</property>
|
||||||
|
<property name="reorderable">False</property>
|
||||||
|
<property name="enable_search">True</property>
|
||||||
|
<property name="fixed_height_mode">False</property>
|
||||||
|
<property name="hover_selection">False</property>
|
||||||
|
<property name="hover_expand">False</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkHButtonBox" id="hbuttonbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="layout_style">GTK_BUTTONBOX_DEFAULT_STYLE</property>
|
||||||
|
<property name="spacing">0</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkButton" id="add_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_default">True</property>
|
||||||
|
<property name="has_default">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="label">gtk-add</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||||
|
<property name="focus_on_click">True</property>
|
||||||
|
<property name="response_id">-5</property>
|
||||||
|
<signal name="clicked" handler="on_add_button_clicked" last_modification_time="Sat, 31 Mar 2007 07:57:55 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkButton" id="delete_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_default">True</property>
|
||||||
|
<property name="has_default">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="label">gtk-delete</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||||
|
<property name="focus_on_click">True</property>
|
||||||
|
<property name="response_id">-5</property>
|
||||||
|
<signal name="clicked" handler="on_delete_button_clicked" last_modification_time="Sat, 31 Mar 2007 07:57:55 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkButton" id="cancel_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_default">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="label">gtk-cancel</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||||
|
<property name="focus_on_click">True</property>
|
||||||
|
<property name="response_id">-6</property>
|
||||||
|
<signal name="clicked" handler="on_cancel_button_clicked" last_modification_time="Sat, 31 Mar 2007 07:58:52 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkButton" id="ok_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_default">True</property>
|
||||||
|
<property name="has_default">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="label">gtk-ok</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||||
|
<property name="focus_on_click">True</property>
|
||||||
|
<property name="response_id">-5</property>
|
||||||
|
<signal name="clicked" handler="on_ok_button_clicked" last_modification_time="Sat, 31 Mar 2007 07:57:55 GMT"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="padding">0</property>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
|
||||||
|
</glade-interface>
|
|
@ -108,15 +108,34 @@
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkScrolledWindow" id="message_scrolledwindow">
|
<widget class="GtkHBox" id="hbox1">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="border_width">3</property>
|
|
||||||
<property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
|
|
||||||
<property name="vscrollbar_policy">GTK_POLICY_NEVER</property>
|
|
||||||
<property name="shadow_type">GTK_SHADOW_IN</property>
|
|
||||||
<child>
|
<child>
|
||||||
<placeholder/>
|
<widget class="GtkImage" id="lock_image">
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="no_show_all">True</property>
|
||||||
|
<property name="stock">gtk-dialog-authentication</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkScrolledWindow" id="message_scrolledwindow">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="border_width">3</property>
|
||||||
|
<property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
|
||||||
|
<property name="vscrollbar_policy">GTK_POLICY_NEVER</property>
|
||||||
|
<property name="shadow_type">GTK_SHADOW_IN</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
|
@ -136,38 +155,6 @@
|
||||||
<widget class="GtkHBox" id="hbox3006">
|
<widget class="GtkHBox" id="hbox3006">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="spacing">1</property>
|
<property name="spacing">1</property>
|
||||||
<child>
|
|
||||||
<widget class="GtkEventBox" id="gpg_eventbox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="tooltip" translatable="yes">OpenPGP Encryption</property>
|
|
||||||
<child>
|
|
||||||
<widget class="GtkToggleButton" id="gpg_togglebutton">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="relief">GTK_RELIEF_NONE</property>
|
|
||||||
<property name="focus_on_click">False</property>
|
|
||||||
<property name="response_id">0</property>
|
|
||||||
<child>
|
|
||||||
<widget class="GtkImage" id="image1333">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="stock">gtk-dialog-authentication</property>
|
|
||||||
</widget>
|
|
||||||
</child>
|
|
||||||
</widget>
|
|
||||||
</child>
|
|
||||||
</widget>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<widget class="GtkVSeparator" id="vseparator4">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
</widget>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -399,6 +386,7 @@
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkVBox" id="muc_child_vbox">
|
<widget class="GtkVBox" id="muc_child_vbox">
|
||||||
|
<property name="can_focus">True</property>
|
||||||
<property name="border_width">3</property>
|
<property name="border_width">3</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkAlignment" id="alignment103">
|
<widget class="GtkAlignment" id="alignment103">
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -193,6 +193,14 @@
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuItem" id="pep_services_menuitem">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="label" translatable="yes">_Services</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -222,6 +230,17 @@
|
||||||
<signal name="activate" handler="on_show_transports_menuitem_activate"/>
|
<signal name="activate" handler="on_show_transports_menuitem_activate"/>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkCheckMenuItem" id="show_roster_menuitem">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="label" translatable="yes">Show _roster</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<signal name="toggled" handler="on_show_roster_menuitem_toggled"/>
|
||||||
|
<accelerator key="R" modifiers="GDK_CONTROL_MASK" signal="activate"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkSeparatorMenuItem" id="separator3">
|
<widget class="GtkSeparatorMenuItem" id="separator3">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -344,45 +363,65 @@
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkScrolledWindow" id="scrolledwindow">
|
<widget class="GtkHPaned" id="roster_hpaned">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="border_width">2</property>
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
|
|
||||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkTreeView" id="roster_treeview">
|
<widget class="GtkVBox" id="roster_vbox2">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="headers_visible">False</property>
|
<child>
|
||||||
<property name="reorderable">True</property>
|
<widget class="GtkScrolledWindow" id="scrolledwindow">
|
||||||
<signal name="leave_notify_event" handler="on_roster_treeview_leave_notify_event"/>
|
<property name="visible">True</property>
|
||||||
<signal name="button_press_event" handler="on_roster_treeview_button_press_event"/>
|
<property name="can_focus">True</property>
|
||||||
<signal name="motion_notify_event" handler="on_roster_treeview_motion_notify_event"/>
|
<property name="border_width">2</property>
|
||||||
<signal name="row_collapsed" handler="on_roster_treeview_row_collapsed"/>
|
<property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
|
||||||
<signal name="row_expanded" handler="on_roster_treeview_row_expanded"/>
|
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||||
<signal name="key_press_event" handler="on_roster_treeview_key_press_event"/>
|
<child>
|
||||||
<signal name="row_activated" handler="on_roster_treeview_row_activated"/>
|
<widget class="GtkTreeView" id="roster_treeview">
|
||||||
<signal name="button_release_event" handler="on_roster_treeview_button_release_event"/>
|
<property name="visible">True</property>
|
||||||
<signal name="scroll_event" handler="on_roster_treeview_scroll_event"/>
|
<property name="can_focus">True</property>
|
||||||
<signal name="style_set" handler="on_roster_treeview_style_set"/>
|
<property name="headers_visible">False</property>
|
||||||
|
<property name="reorderable">True</property>
|
||||||
|
<signal name="leave_notify_event" handler="on_roster_treeview_leave_notify_event"/>
|
||||||
|
<signal name="button_press_event" handler="on_roster_treeview_button_press_event"/>
|
||||||
|
<signal name="motion_notify_event" handler="on_roster_treeview_motion_notify_event"/>
|
||||||
|
<signal name="row_collapsed" handler="on_roster_treeview_row_collapsed"/>
|
||||||
|
<signal name="row_expanded" handler="on_roster_treeview_row_expanded"/>
|
||||||
|
<signal name="key_press_event" handler="on_roster_treeview_key_press_event"/>
|
||||||
|
<signal name="row_activated" handler="on_roster_treeview_row_activated"/>
|
||||||
|
<signal name="button_release_event" handler="on_roster_treeview_button_release_event"/>
|
||||||
|
<signal name="scroll_event" handler="on_roster_treeview_scroll_event"/>
|
||||||
|
<signal name="style_set" handler="on_roster_treeview_style_set"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkComboBox" id="status_combobox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<signal name="changed" handler="on_status_combobox_changed"/>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="resize">False</property>
|
||||||
|
<property name="shrink">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
|
||||||
<widget class="GtkComboBox" id="status_combobox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<signal name="changed" handler="on_status_combobox_changed"/>
|
|
||||||
</widget>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="position">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
<property name="xpad">5</property>
|
<property name="xpad">5</property>
|
||||||
<property name="ypad">5</property>
|
<property name="ypad">5</property>
|
||||||
<property name="selectable">True</property>
|
<property name="selectable">True</property>
|
||||||
|
<property name="ellipsize">PANGO_ELLIPSIZE_END</property>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -94,6 +95,7 @@
|
||||||
<property name="xpad">5</property>
|
<property name="xpad">5</property>
|
||||||
<property name="ypad">5</property>
|
<property name="ypad">5</property>
|
||||||
<property name="selectable">True</property>
|
<property name="selectable">True</property>
|
||||||
|
<property name="ellipsize">PANGO_ELLIPSIZE_END</property>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="left_attach">1</property>
|
<property name="left_attach">1</property>
|
||||||
|
@ -218,8 +220,8 @@
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="spacing">6</property>
|
<property name="spacing">6</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkLabel" id="label59">
|
<widget class="GtkLabel" id="user_avatar_label">
|
||||||
<property name="visible">True</property>
|
<property name="no_show_all">True</property>
|
||||||
<property name="label" translatable="yes">User avatar:</property>
|
<property name="label" translatable="yes">User avatar:</property>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
|
@ -227,17 +229,6 @@
|
||||||
<property name="fill">False</property>
|
<property name="fill">False</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
|
||||||
<widget class="GtkLabel" id="no_user_avatar_label">
|
|
||||||
<property name="no_show_all">True</property>
|
|
||||||
<property name="label" translatable="yes">None</property>
|
|
||||||
</widget>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">False</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkEventBox" id="PHOTO_eventbox">
|
<widget class="GtkEventBox" id="PHOTO_eventbox">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -254,7 +245,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">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -265,7 +256,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">2</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -277,11 +268,12 @@
|
||||||
<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">4</property>
|
<property name="position">3</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
@ -384,9 +376,6 @@
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
|
||||||
<property name="tab_expand">False</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkLabel" id="label3">
|
<widget class="GtkLabel" id="label3">
|
||||||
|
@ -397,7 +386,6 @@
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="type">tab</property>
|
<property name="type">tab</property>
|
||||||
<property name="tab_expand">False</property>
|
|
||||||
<property name="tab_fill">False</property>
|
<property name="tab_fill">False</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
@ -1014,7 +1002,6 @@
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
<property name="tab_expand">False</property>
|
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -1027,7 +1014,6 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="type">tab</property>
|
<property name="type">tab</property>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
<property name="tab_expand">False</property>
|
|
||||||
<property name="tab_fill">False</property>
|
<property name="tab_fill">False</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
@ -1459,7 +1445,6 @@
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">2</property>
|
<property name="position">2</property>
|
||||||
<property name="tab_expand">False</property>
|
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -1472,7 +1457,6 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="type">tab</property>
|
<property name="type">tab</property>
|
||||||
<property name="position">2</property>
|
<property name="position">2</property>
|
||||||
<property name="tab_expand">False</property>
|
|
||||||
<property name="tab_fill">False</property>
|
<property name="tab_fill">False</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
@ -1497,7 +1481,6 @@
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">3</property>
|
<property name="position">3</property>
|
||||||
<property name="tab_expand">False</property>
|
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -1510,7 +1493,6 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="type">tab</property>
|
<property name="type">tab</property>
|
||||||
<property name="position">3</property>
|
<property name="position">3</property>
|
||||||
<property name="tab_expand">False</property>
|
|
||||||
<property name="tab_fill">False</property>
|
<property name="tab_fill">False</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
@ -1533,7 +1515,6 @@
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">4</property>
|
<property name="position">4</property>
|
||||||
<property name="tab_expand">False</property>
|
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
@ -1544,7 +1525,6 @@
|
||||||
<packing>
|
<packing>
|
||||||
<property name="type">tab</property>
|
<property name="type">tab</property>
|
||||||
<property name="position">4</property>
|
<property name="position">4</property>
|
||||||
<property name="tab_expand">False</property>
|
|
||||||
<property name="tab_fill">False</property>
|
<property name="tab_fill">False</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
@ -1588,6 +1568,7 @@
|
||||||
</child>
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
<property name="position">2</property>
|
<property name="position">2</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
|
data/gajim.desktop.in
|
||||||
|
src/eggtrayicon.c
|
||||||
|
|
402
po/fr.po
402
po/fr.po
|
@ -3570,7 +3570,7 @@ msgstr "Fichier"
|
||||||
|
|
||||||
#: ../src/filetransfers_window.py:87
|
#: ../src/filetransfers_window.py:87
|
||||||
msgid "Time"
|
msgid "Time"
|
||||||
msgstr "Moment"
|
msgstr "Durée"
|
||||||
|
|
||||||
#: ../src/filetransfers_window.py:99
|
#: ../src/filetransfers_window.py:99
|
||||||
msgid "Progress"
|
msgid "Progress"
|
||||||
|
@ -6537,6 +6537,406 @@ msgstr "Connecté"
|
||||||
msgid "Disconnected"
|
msgid "Disconnected"
|
||||||
msgstr "Déconnecté"
|
msgstr "Déconnecté"
|
||||||
|
|
||||||
|
#pep
|
||||||
|
msgid "afraid"
|
||||||
|
msgstr "appeuré"
|
||||||
|
|
||||||
|
msgid "amazed"
|
||||||
|
msgstr "surpris, amusé"
|
||||||
|
|
||||||
|
msgid "angry"
|
||||||
|
msgstr "en colère"
|
||||||
|
|
||||||
|
msgid "annoyed"
|
||||||
|
msgstr "dérangé"
|
||||||
|
|
||||||
|
msgid "anxious"
|
||||||
|
msgstr "anxieux"
|
||||||
|
|
||||||
|
msgid "aroused"
|
||||||
|
msgstr "excité"
|
||||||
|
|
||||||
|
msgid "ashamed"
|
||||||
|
msgstr "honteux/éhonté"
|
||||||
|
|
||||||
|
msgid "bored"
|
||||||
|
msgstr "ennuyé"
|
||||||
|
|
||||||
|
msgid "brave"
|
||||||
|
msgstr "courageux"
|
||||||
|
|
||||||
|
msgid "calm"
|
||||||
|
msgstr "calme"
|
||||||
|
|
||||||
|
msgid "cold"
|
||||||
|
msgstr "froid"
|
||||||
|
|
||||||
|
msgid "confused"
|
||||||
|
msgstr "confus"
|
||||||
|
|
||||||
|
msgid "contented"
|
||||||
|
msgstr "contenté"
|
||||||
|
|
||||||
|
msgid "cranky"
|
||||||
|
msgstr "excentrique"
|
||||||
|
|
||||||
|
msgid "curious"
|
||||||
|
msgstr "curieux"
|
||||||
|
|
||||||
|
msgid "depressed"
|
||||||
|
msgstr "déprimé"
|
||||||
|
|
||||||
|
msgid "disappointed"
|
||||||
|
msgstr "décu"
|
||||||
|
|
||||||
|
msgid "disgusted"
|
||||||
|
msgstr "dégouté"
|
||||||
|
|
||||||
|
msgid "distracted"
|
||||||
|
msgstr "distrait"
|
||||||
|
|
||||||
|
msgid "embarrassed"
|
||||||
|
msgstr "embarssé"
|
||||||
|
|
||||||
|
msgid "excited"
|
||||||
|
msgstr "excité"
|
||||||
|
|
||||||
|
msgid "flirtatious"
|
||||||
|
msgstr "coquet"
|
||||||
|
|
||||||
|
msgid "frustrated"
|
||||||
|
msgstr "frustré"
|
||||||
|
|
||||||
|
msgid "grumpy"
|
||||||
|
msgstr "grognon"
|
||||||
|
|
||||||
|
msgid "guilty"
|
||||||
|
msgstr "coupable"
|
||||||
|
|
||||||
|
msgid "happy"
|
||||||
|
msgstr "joyeux"
|
||||||
|
|
||||||
|
msgid "hot"
|
||||||
|
msgstr "chaud"
|
||||||
|
|
||||||
|
msgid "humbled"
|
||||||
|
msgstr "humilié"
|
||||||
|
|
||||||
|
msgid "humiliated"
|
||||||
|
msgstr "humilié"
|
||||||
|
|
||||||
|
msgid "hungry"
|
||||||
|
msgstr "affamé"
|
||||||
|
|
||||||
|
msgid "hurt"
|
||||||
|
msgstr "blessé"
|
||||||
|
|
||||||
|
msgid "impressed"
|
||||||
|
msgstr "impressionné"
|
||||||
|
|
||||||
|
msgid "in_awe"
|
||||||
|
msgstr "dans la crainte"
|
||||||
|
|
||||||
|
msgid "in_love"
|
||||||
|
msgstr "amoureux"
|
||||||
|
|
||||||
|
msgid "indignant"
|
||||||
|
msgstr "indigné"
|
||||||
|
|
||||||
|
msgid "interested"
|
||||||
|
msgstr "interessé"
|
||||||
|
|
||||||
|
msgid "intoxicated"
|
||||||
|
msgstr "intoxiqué"
|
||||||
|
|
||||||
|
msgid "invincible"
|
||||||
|
msgstr "invincible"
|
||||||
|
|
||||||
|
msgid "jealous"
|
||||||
|
msgstr "jaloux"
|
||||||
|
|
||||||
|
msgid "lonely"
|
||||||
|
msgstr "seul/esseulé"
|
||||||
|
|
||||||
|
msgid "mean"
|
||||||
|
msgstr "méchant"
|
||||||
|
|
||||||
|
msgid "moody"
|
||||||
|
msgstr "déprimé"
|
||||||
|
|
||||||
|
msgid "nervous"
|
||||||
|
msgstr "nerveux"
|
||||||
|
|
||||||
|
msgid "neutral"
|
||||||
|
msgstr "neutre"
|
||||||
|
|
||||||
|
msgid "offended"
|
||||||
|
msgstr "offensé"
|
||||||
|
|
||||||
|
msgid "playful"
|
||||||
|
msgstr "joueur"
|
||||||
|
|
||||||
|
msgid "proud"
|
||||||
|
msgstr "fier"
|
||||||
|
|
||||||
|
msgid "relieved"
|
||||||
|
msgstr "soulagé"
|
||||||
|
|
||||||
|
msgid "remorseful"
|
||||||
|
msgstr "plein de remord"
|
||||||
|
|
||||||
|
msgid "restless"
|
||||||
|
msgstr "infatiguable"
|
||||||
|
|
||||||
|
msgid "sad"
|
||||||
|
msgstr "triste"
|
||||||
|
|
||||||
|
msgid "sarcastic"
|
||||||
|
msgstr "sarcastique"
|
||||||
|
|
||||||
|
msgid "serious"
|
||||||
|
msgstr "serieux"
|
||||||
|
|
||||||
|
msgid "shocked"
|
||||||
|
msgstr "choqué"
|
||||||
|
|
||||||
|
msgid "shy"
|
||||||
|
msgstr "timide"
|
||||||
|
|
||||||
|
msgid "sick"
|
||||||
|
msgstr "malade"
|
||||||
|
|
||||||
|
msgid "sleepy"
|
||||||
|
msgstr "endormi"
|
||||||
|
|
||||||
|
msgid "stressed"
|
||||||
|
msgstr "stressé"
|
||||||
|
|
||||||
|
msgid "surprised"
|
||||||
|
msgstr "surpris"
|
||||||
|
|
||||||
|
msgid "thirsty"
|
||||||
|
msgstr "assoiffé"
|
||||||
|
|
||||||
|
msgid "worried"
|
||||||
|
msgstr "inquiet"
|
||||||
|
|
||||||
|
msgid "_Personnal Events"
|
||||||
|
msgstr "Évènements _Personnels"
|
||||||
|
|
||||||
|
msgid "Activity"
|
||||||
|
msgstr "Activité"
|
||||||
|
|
||||||
|
msgid "doing_chores"
|
||||||
|
msgstr "fait des corvées"
|
||||||
|
|
||||||
|
msgid "buying_groceries"
|
||||||
|
msgstr "achète des épiceries"
|
||||||
|
|
||||||
|
msgid "cleaning"
|
||||||
|
msgstr "nettoie"
|
||||||
|
|
||||||
|
msgid "cooking"
|
||||||
|
msgstr "cuisine"
|
||||||
|
|
||||||
|
msgid "doing_maintenance"
|
||||||
|
msgstr "fait de la maintenance"
|
||||||
|
|
||||||
|
msgid "doing_the_dishes"
|
||||||
|
msgstr "fait la vaiselle"
|
||||||
|
|
||||||
|
msgid "doing_the_laundry"
|
||||||
|
msgstr "fait la blanchisserie"
|
||||||
|
|
||||||
|
msgid "gardening"
|
||||||
|
msgstr "jardine"
|
||||||
|
|
||||||
|
msgid "running_an_errand"
|
||||||
|
msgstr "fait une course"
|
||||||
|
|
||||||
|
msgid "walking_the_dog"
|
||||||
|
msgstr "promène le chien"
|
||||||
|
|
||||||
|
msgid "drinking"
|
||||||
|
msgstr "boit"
|
||||||
|
|
||||||
|
msgid "having_a_beer"
|
||||||
|
msgstr "prend une bière"
|
||||||
|
|
||||||
|
msgid "having_coffee"
|
||||||
|
msgstr "prend un café"
|
||||||
|
|
||||||
|
msgid "having_tea"
|
||||||
|
msgstr "prend un thé"
|
||||||
|
|
||||||
|
msgid "eating"
|
||||||
|
msgstr "mange"
|
||||||
|
|
||||||
|
msgid "having_a_snack"
|
||||||
|
msgstr "prend un snack"
|
||||||
|
|
||||||
|
msgid "having_breakfast"
|
||||||
|
msgstr "prend le petit-déjeuner"
|
||||||
|
|
||||||
|
msgid "having_dinner"
|
||||||
|
msgstr "soupe"
|
||||||
|
|
||||||
|
msgid "having_lunch"
|
||||||
|
msgstr "dîne"
|
||||||
|
|
||||||
|
msgid "exercising"
|
||||||
|
msgstr "fait de l'exercice"
|
||||||
|
|
||||||
|
msgid "cycling"
|
||||||
|
msgstr "fait du vélo"
|
||||||
|
|
||||||
|
msgid "hiking"
|
||||||
|
msgstr "fait de la randonnée"
|
||||||
|
|
||||||
|
msgid "jogging"
|
||||||
|
msgstr "fait un jogging"
|
||||||
|
|
||||||
|
msgid "playing_sports"
|
||||||
|
msgstr "fait du sport"
|
||||||
|
|
||||||
|
msgid "running"
|
||||||
|
msgstr "court"
|
||||||
|
|
||||||
|
msgid "skiing"
|
||||||
|
msgstr "skie"
|
||||||
|
|
||||||
|
msgid "swimming"
|
||||||
|
msgstr "nage"
|
||||||
|
|
||||||
|
msgid "working_out"
|
||||||
|
msgstr "élabore"
|
||||||
|
|
||||||
|
msgid "grooming"
|
||||||
|
msgstr "se toilette"
|
||||||
|
|
||||||
|
msgid "at_the_spa"
|
||||||
|
msgstr "à la station thermale"
|
||||||
|
|
||||||
|
msgid "brushing_teeth"
|
||||||
|
msgstr "se brosse les dents"
|
||||||
|
|
||||||
|
msgid "getting_a_haircut"
|
||||||
|
msgstr "se fait couper les cheveux"
|
||||||
|
|
||||||
|
msgid "shaving"
|
||||||
|
msgstr "se rase"
|
||||||
|
|
||||||
|
msgid "taking_a_bath"
|
||||||
|
msgstr "prend un bain"
|
||||||
|
|
||||||
|
msgid "taking_a_shower"
|
||||||
|
msgstr "prend une douche"
|
||||||
|
|
||||||
|
msgid "having_appointment"
|
||||||
|
msgstr "à un rendez-vous"
|
||||||
|
|
||||||
|
msgid "inactive"
|
||||||
|
msgstr "inactif"
|
||||||
|
|
||||||
|
msgid "day_off"
|
||||||
|
msgstr "en congé"
|
||||||
|
|
||||||
|
msgid "hanging_out"
|
||||||
|
msgstr "traîne"
|
||||||
|
|
||||||
|
msgid "on_vacation"
|
||||||
|
msgstr "en vacances"
|
||||||
|
|
||||||
|
msgid "scheduled_holiday"
|
||||||
|
msgstr "en vacances organisées"
|
||||||
|
|
||||||
|
msgid "sleeping"
|
||||||
|
msgstr "dort"
|
||||||
|
|
||||||
|
msgid "relaxing"
|
||||||
|
msgstr "se relaxe"
|
||||||
|
|
||||||
|
msgid "gaming"
|
||||||
|
msgstr "joue"
|
||||||
|
|
||||||
|
msgid "going_out"
|
||||||
|
msgstr "sort"
|
||||||
|
|
||||||
|
msgid "partying"
|
||||||
|
msgstr "fait la fête"
|
||||||
|
|
||||||
|
msgid "reading"
|
||||||
|
msgstr "lit"
|
||||||
|
|
||||||
|
msgid "rehearsing"
|
||||||
|
msgstr "se prépare"
|
||||||
|
|
||||||
|
msgid "shopping"
|
||||||
|
msgstr "fait les magasins"
|
||||||
|
|
||||||
|
msgid "socializing"
|
||||||
|
msgstr "se socialise"
|
||||||
|
|
||||||
|
msgid "sunbathing"
|
||||||
|
msgstr "prend un bain de soleil"
|
||||||
|
|
||||||
|
msgid "watching_tv"
|
||||||
|
msgstr "regarde la TV"
|
||||||
|
|
||||||
|
msgid "watching_a_movie"
|
||||||
|
msgstr "regarde un film"
|
||||||
|
|
||||||
|
msgid "talking"
|
||||||
|
msgstr "discute"
|
||||||
|
|
||||||
|
msgid "in_real_life"
|
||||||
|
msgstr "dans la vraie vie"
|
||||||
|
|
||||||
|
msgid "on_the_phone"
|
||||||
|
msgstr "au téléphone"
|
||||||
|
|
||||||
|
msgid "traveling"
|
||||||
|
msgstr "voyage"
|
||||||
|
|
||||||
|
msgid "commuting"
|
||||||
|
msgstr "permute"
|
||||||
|
|
||||||
|
msgid "driving"
|
||||||
|
msgstr "conduit"
|
||||||
|
|
||||||
|
msgid "in_a_car"
|
||||||
|
msgstr "en voiture"
|
||||||
|
|
||||||
|
msgid "on_a_bus"
|
||||||
|
msgstr "en bus"
|
||||||
|
|
||||||
|
msgid "on_a_plane"
|
||||||
|
msgstr "en avion"
|
||||||
|
|
||||||
|
msgid "on_a_train"
|
||||||
|
msgstr "en train"
|
||||||
|
|
||||||
|
msgid "on_a_trip"
|
||||||
|
msgstr "en séjour"
|
||||||
|
|
||||||
|
msgid "walking"
|
||||||
|
msgstr "marche"
|
||||||
|
|
||||||
|
msgid "working"
|
||||||
|
msgstr "travaille"
|
||||||
|
|
||||||
|
msgid "coding"
|
||||||
|
msgstr "programme"
|
||||||
|
|
||||||
|
msgid "in_a_meeting"
|
||||||
|
msgstr "en réunion"
|
||||||
|
|
||||||
|
msgid "studying"
|
||||||
|
msgstr "étudie"
|
||||||
|
|
||||||
|
msgid "writing"
|
||||||
|
msgstr "écrit"
|
||||||
|
|
||||||
#~ msgid "2003-12-13T18:30:02Z"
|
#~ msgid "2003-12-13T18:30:02Z"
|
||||||
#~ msgstr "2003-12-13T18:30:02Z"
|
#~ msgstr "2003-12-13T18:30:02Z"
|
||||||
#~ msgid "<small>Romeo and Juliet</small>"
|
#~ msgid "<small>Romeo and Juliet</small>"
|
||||||
|
|
|
@ -44,26 +44,26 @@ trayicon.c:
|
||||||
$(srcdir)/trayicon.defs > $@
|
$(srcdir)/trayicon.defs > $@
|
||||||
endif
|
endif
|
||||||
gajimsrcdir = $(pkgdatadir)/src
|
gajimsrcdir = $(pkgdatadir)/src
|
||||||
gajimsrc_DATA = $(srcdir)/*.py
|
gajimsrc_PYTHON = $(srcdir)/*.py
|
||||||
|
|
||||||
gajimsrc1dir = $(pkgdatadir)/src/common
|
gajimsrc1dir = $(pkgdatadir)/src/common
|
||||||
gajimsrc1_DATA = \
|
gajimsrc1_PYTHON = \
|
||||||
$(srcdir)/common/*.py
|
$(srcdir)/common/*.py
|
||||||
|
|
||||||
gajimsrc2dir = $(pkgdatadir)/src/common/xmpp
|
gajimsrc2dir = $(pkgdatadir)/src/common/xmpp
|
||||||
gajimsrc2_DATA = \
|
gajimsrc2_PYTHON = \
|
||||||
$(srcdir)/common/xmpp/*.py
|
$(srcdir)/common/xmpp/*.py
|
||||||
|
|
||||||
gajimsrc3dir = $(pkgdatadir)/src/common/zeroconf
|
gajimsrc3dir = $(pkgdatadir)/src/common/zeroconf
|
||||||
gajimsrc3_DATA = \
|
gajimsrc3_PYTHON = \
|
||||||
$(srcdir)/common/zeroconf/*.py
|
$(srcdir)/common/zeroconf/*.py
|
||||||
|
|
||||||
DISTCLEANFILES =
|
DISTCLEANFILES =
|
||||||
|
|
||||||
EXTRA_DIST = $(gajimsrc_DATA) \
|
EXTRA_DIST = $(gajimsrc_PYTHON) \
|
||||||
$(gajimsrc1_DATA) \
|
$(gajimsrc1_PYTHON) \
|
||||||
$(gajimsrc2_DATA) \
|
$(gajimsrc2_PYTHON) \
|
||||||
$(gajimsrc3_DATA) \
|
$(gajimsrc3_PYTHON) \
|
||||||
gtkspellmodule.c \
|
gtkspellmodule.c \
|
||||||
eggtrayicon.c \
|
eggtrayicon.c \
|
||||||
trayiconmodule.c \
|
trayiconmodule.c \
|
||||||
|
|
|
@ -151,7 +151,7 @@ class ChatControlBase(MessageControl):
|
||||||
self._on_banner_eventbox_button_press_event)
|
self._on_banner_eventbox_button_press_event)
|
||||||
self.handlers[id] = widget
|
self.handlers[id] = widget
|
||||||
|
|
||||||
self.urlfinder = re.compile("(https?://|www|ftp)[^ ]+")
|
self.urlfinder = re.compile(r"(www\.(?!\.)|[a-z][a-z0-9+.-]*://)[^\s<>'\"]+[^!,\.\s<>\)'\"\]]")
|
||||||
|
|
||||||
if gajim.HAVE_PYSEXY:
|
if gajim.HAVE_PYSEXY:
|
||||||
import sexy
|
import sexy
|
||||||
|
@ -1018,6 +1018,10 @@ class ChatControl(ChatControlBase):
|
||||||
self.widget_set_visible(self.xml.get_widget('banner_eventbox'),
|
self.widget_set_visible(self.xml.get_widget('banner_eventbox'),
|
||||||
gajim.config.get('hide_chat_banner'))
|
gajim.config.get('hide_chat_banner'))
|
||||||
|
|
||||||
|
# Add lock image to show chat encryption
|
||||||
|
self.lock_image = self.xml.get_widget('lock_image')
|
||||||
|
self.lock_tooltip = gtk.Tooltips()
|
||||||
|
|
||||||
# keep timeout id and window obj for possible big avatar
|
# keep timeout id and window obj for possible big avatar
|
||||||
# it is on enter-notify and leave-notify so no need to be per jid
|
# it is on enter-notify and leave-notify so no need to be per jid
|
||||||
self.show_bigger_avatar_timeout_id = None
|
self.show_bigger_avatar_timeout_id = None
|
||||||
|
@ -1050,15 +1054,25 @@ class ChatControl(ChatControlBase):
|
||||||
self.on_avatar_eventbox_button_press_event)
|
self.on_avatar_eventbox_button_press_event)
|
||||||
self.handlers[id] = widget
|
self.handlers[id] = widget
|
||||||
|
|
||||||
widget = self.xml.get_widget('gpg_togglebutton')
|
|
||||||
id = widget.connect('clicked', self.on_toggle_gpg_togglebutton)
|
|
||||||
self.handlers[id] = widget
|
|
||||||
|
|
||||||
if self.contact.jid in gajim.encrypted_chats[self.account]:
|
|
||||||
self.xml.get_widget('gpg_togglebutton').set_active(True)
|
|
||||||
|
|
||||||
self.set_session(session)
|
self.set_session(session)
|
||||||
|
|
||||||
|
# Enable ecryption if needed
|
||||||
|
e2e_is_active = hasattr(self, 'session') and self.session and self.session.enable_encryption
|
||||||
|
self.gpg_is_active = False
|
||||||
|
gpg_pref = gajim.config.get_per('contacts', contact.jid, 'gpg_enabled')
|
||||||
|
|
||||||
|
if not e2e_is_active and gpg_pref and gajim.config.get_per('accounts', self.account, 'keyid') and\
|
||||||
|
gajim.connections[self.account].USE_GPG:
|
||||||
|
self.gpg_is_active = True
|
||||||
|
gajim.encrypted_chats[self.account].append(contact.jid)
|
||||||
|
msg = _('GPG encryption enabled')
|
||||||
|
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
||||||
|
|
||||||
|
if self.session:
|
||||||
|
self.session.loggable = gajim.config.get('log_encrypted_sessions')
|
||||||
|
self._show_lock_image(self.gpg_is_active, 'GPG', self.gpg_is_active, self.session and \
|
||||||
|
self.session.is_loggable())
|
||||||
|
|
||||||
self.status_tooltip = gtk.Tooltips()
|
self.status_tooltip = gtk.Tooltips()
|
||||||
self.update_ui()
|
self.update_ui()
|
||||||
# restore previous conversation
|
# restore previous conversation
|
||||||
|
@ -1164,8 +1178,6 @@ class ChatControl(ChatControlBase):
|
||||||
gtk.gdk.INTERP_BILINEAR)
|
gtk.gdk.INTERP_BILINEAR)
|
||||||
banner_status_img.set_from_pixbuf(scaled_pix)
|
banner_status_img.set_from_pixbuf(scaled_pix)
|
||||||
|
|
||||||
self._update_gpg()
|
|
||||||
|
|
||||||
def draw_banner_text(self):
|
def draw_banner_text(self):
|
||||||
'''Draw the text in the fat line at the top of the window that
|
'''Draw the text in the fat line at the top of the window that
|
||||||
houses the name, jid.
|
houses the name, jid.
|
||||||
|
@ -1254,34 +1266,52 @@ class ChatControl(ChatControlBase):
|
||||||
# setup the label that holds name and jid
|
# setup the label that holds name and jid
|
||||||
banner_name_label.set_markup(label_text)
|
banner_name_label.set_markup(label_text)
|
||||||
|
|
||||||
def on_toggle_gpg_togglebutton(self, widget):
|
def _toggle_gpg(self):
|
||||||
gajim.config.set_per('contacts', self.contact.jid, 'gpg_enabled',
|
ec = gajim.encrypted_chats[self.account]
|
||||||
widget.get_active())
|
if self.gpg_is_active:
|
||||||
|
# Disable encryption
|
||||||
def _update_gpg(self):
|
ec.remove(self.contact.jid)
|
||||||
tb = self.xml.get_widget('gpg_togglebutton')
|
self.gpg_is_active = False
|
||||||
# we can do gpg
|
msg = _('GPG encryption disabled')
|
||||||
# if self.contact is our own contact info (transports),
|
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
||||||
# don't enable pgp
|
if self.session:
|
||||||
if self.contact.keyID and not gajim.jid_is_transport(self.contact.jid):
|
self.session.loggable = True
|
||||||
tb.set_sensitive(True)
|
|
||||||
tt = _('OpenPGP Encryption')
|
|
||||||
|
|
||||||
# restore gpg pref
|
|
||||||
gpg_pref = gajim.config.get_per('contacts', self.contact.jid,
|
|
||||||
'gpg_enabled')
|
|
||||||
if gpg_pref == None:
|
|
||||||
gajim.config.add_per('contacts', self.contact.jid)
|
|
||||||
gpg_pref = gajim.config.get_per('contacts', self.contact.jid,
|
|
||||||
'gpg_enabled')
|
|
||||||
tb.set_active(gpg_pref)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
tb.set_sensitive(False)
|
# Enable encryption
|
||||||
#we talk about a contact here
|
ec.append(self.contact.jid)
|
||||||
tt = _('%s has not broadcast an OpenPGP key, nor has one been assigned') %\
|
self.gpg_is_active = True
|
||||||
self.contact.get_shown_name()
|
msg = _('GPG encryption enabled')
|
||||||
gtk.Tooltips().set_tip(self.xml.get_widget('gpg_eventbox'), tt)
|
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
||||||
|
|
||||||
|
if self.session:
|
||||||
|
self.session.loggable = gajim.config.get('log_encrypted_sessions');
|
||||||
|
if self.session and not self.session.is_loggable():
|
||||||
|
msg = _('Session WILL NOT be logged')
|
||||||
|
else:
|
||||||
|
msg = _('Session WILL be logged')
|
||||||
|
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
||||||
|
|
||||||
|
gpg_pref = gajim.config.get_per('contacts', self.contact.jid,
|
||||||
|
'gpg_enabled')
|
||||||
|
if gpg_pref is None:
|
||||||
|
gajim.config.add_per('contacts', self.contact.jid)
|
||||||
|
gajim.config.set_per('contacts', self.contact.jid, 'gpg_enabled',
|
||||||
|
self.gpg_is_active)
|
||||||
|
|
||||||
|
self._show_lock_image(self.gpg_is_active, 'GPG', self.gpg_is_active, self.session and \
|
||||||
|
self.session.is_loggable())
|
||||||
|
|
||||||
|
def _show_lock_image(self, visible, enc_type = '', enc_enabled = False, chat_logged = False):
|
||||||
|
'''Set lock icon visibiity and create tooltip'''
|
||||||
|
status_string = enc_enabled and 'is' or 'is NOT'
|
||||||
|
logged_string = chat_logged and 'will' or 'will NOT'
|
||||||
|
tooltip = '%s Encryption %s active. \nYour chat session %s be logged.' %\
|
||||||
|
(enc_type, status_string, logged_string)
|
||||||
|
|
||||||
|
self.lock_tooltip.set_tip(self.lock_image, tooltip)
|
||||||
|
self.widget_set_visible(self.lock_image, not visible)
|
||||||
|
self.lock_image.set_sensitive(enc_enabled)
|
||||||
|
|
||||||
def _process_command(self, message):
|
def _process_command(self, message):
|
||||||
if message[0] != '/':
|
if message[0] != '/':
|
||||||
|
@ -1369,9 +1399,11 @@ class ChatControl(ChatControlBase):
|
||||||
encrypted = bool(self.session) and self.session.enable_encryption
|
encrypted = bool(self.session) and self.session.enable_encryption
|
||||||
|
|
||||||
keyID = ''
|
keyID = ''
|
||||||
if self.xml.get_widget('gpg_togglebutton').get_active():
|
if self.gpg_is_active:
|
||||||
keyID = contact.keyID
|
keyID = contact.keyID
|
||||||
encrypted = True
|
encrypted = True
|
||||||
|
if not keyID:
|
||||||
|
keyID = 'UNKNOWN'
|
||||||
|
|
||||||
chatstates_on = gajim.config.get('outgoing_chat_state_notifications') != \
|
chatstates_on = gajim.config.get('outgoing_chat_state_notifications') != \
|
||||||
'disabled'
|
'disabled'
|
||||||
|
@ -1468,13 +1500,14 @@ class ChatControl(ChatControlBase):
|
||||||
msg = _('Session negotiation cancelled')
|
msg = _('Session negotiation cancelled')
|
||||||
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
||||||
|
|
||||||
# print esession settings to textview
|
|
||||||
def print_esession_details(self):
|
def print_esession_details(self):
|
||||||
if self.session and self.session.enable_encryption:
|
'''print esession settings to textview'''
|
||||||
|
e2e_is_active = self.session and self.session.enable_encryption
|
||||||
|
if e2e_is_active:
|
||||||
msg = _('E2E encryption enabled')
|
msg = _('E2E encryption enabled')
|
||||||
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
||||||
|
|
||||||
if self.session.loggable:
|
if self.session.is_loggable():
|
||||||
msg = _('Session WILL be logged')
|
msg = _('Session WILL be logged')
|
||||||
else:
|
else:
|
||||||
msg = _('Session WILL NOT be logged')
|
msg = _('Session WILL NOT be logged')
|
||||||
|
@ -1483,6 +1516,8 @@ class ChatControl(ChatControlBase):
|
||||||
else:
|
else:
|
||||||
msg = _('E2E encryption disabled')
|
msg = _('E2E encryption disabled')
|
||||||
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
ChatControlBase.print_conversation_line(self, msg, 'status', '', None)
|
||||||
|
self._show_lock_image(e2e_is_active, 'E2E', e2e_is_active, self.session and \
|
||||||
|
self.session.is_loggable())
|
||||||
|
|
||||||
def print_conversation(self, text, frm = '', tim = None,
|
def print_conversation(self, text, frm = '', tim = None,
|
||||||
encrypted = False, subject = None, xhtml = None):
|
encrypted = False, subject = None, xhtml = None):
|
||||||
|
@ -1510,19 +1545,15 @@ class ChatControl(ChatControlBase):
|
||||||
'status', '', tim)
|
'status', '', tim)
|
||||||
else:
|
else:
|
||||||
# GPG encryption
|
# GPG encryption
|
||||||
ec = gajim.encrypted_chats[self.account]
|
if encrypted and not self.gpg_is_active:
|
||||||
if encrypted and jid not in ec:
|
msg = _('The following message was encrypted')
|
||||||
msg = _('OpenPGP Encryption enabled')
|
|
||||||
ChatControlBase.print_conversation_line(self, msg,
|
ChatControlBase.print_conversation_line(self, msg,
|
||||||
'status', '', tim)
|
'status', '', tim)
|
||||||
ec.append(jid)
|
self._toggle_gpg()
|
||||||
elif not encrypted and jid in ec:
|
elif not encrypted and self.gpg_is_active:
|
||||||
msg = _('OpenPGP Encryption disabled')
|
msg = _('The following message was NOT encrypted')
|
||||||
ChatControlBase.print_conversation_line(self, msg,
|
ChatControlBase.print_conversation_line(self, msg,
|
||||||
'status', '', tim)
|
'status', '', tim)
|
||||||
ec.remove(jid)
|
|
||||||
self.xml.get_widget('gpg_togglebutton').set_active(encrypted)
|
|
||||||
|
|
||||||
if not frm:
|
if not frm:
|
||||||
kind = 'incoming'
|
kind = 'incoming'
|
||||||
name = contact.get_shown_name()
|
name = contact.get_shown_name()
|
||||||
|
@ -1650,12 +1681,15 @@ class ChatControl(ChatControlBase):
|
||||||
contact = self.parent_win.get_active_contact()
|
contact = self.parent_win.get_active_contact()
|
||||||
jid = contact.jid
|
jid = contact.jid
|
||||||
|
|
||||||
# check if gpg capabitlies or else make gpg toggle insensitive
|
# check if we support and use gpg
|
||||||
gpg_btn = self.xml.get_widget('gpg_togglebutton')
|
if not gajim.config.get_per('accounts', self.account, 'keyid') or\
|
||||||
isactive = gpg_btn.get_active()
|
not gajim.connections[self.account].USE_GPG or\
|
||||||
is_sensitive = gpg_btn.get_property('sensitive')
|
gajim.jid_is_transport(jid):
|
||||||
toggle_gpg_menuitem.set_active(isactive)
|
toggle_gpg_menuitem.set_sensitive(False)
|
||||||
toggle_gpg_menuitem.set_property('sensitive', is_sensitive)
|
else:
|
||||||
|
e2e_is_active = int(self.session != None and self.session.enable_encryption)
|
||||||
|
toggle_gpg_menuitem.set_sensitive(not e2e_is_active)
|
||||||
|
toggle_gpg_menuitem.set_active(self.gpg_is_active)
|
||||||
|
|
||||||
# TODO: check that the remote client supports e2e
|
# TODO: check that the remote client supports e2e
|
||||||
if not gajim.HAVE_PYCRYPTO:
|
if not gajim.HAVE_PYCRYPTO:
|
||||||
|
@ -1663,6 +1697,7 @@ class ChatControl(ChatControlBase):
|
||||||
else:
|
else:
|
||||||
isactive = int(self.session != None and self.session.enable_encryption)
|
isactive = int(self.session != None and self.session.enable_encryption)
|
||||||
toggle_e2e_menuitem.set_active(isactive)
|
toggle_e2e_menuitem.set_active(isactive)
|
||||||
|
toggle_e2e_menuitem.set_sensitive(not self.gpg_is_active)
|
||||||
|
|
||||||
# If we don't have resource, we can't do file transfer
|
# If we don't have resource, we can't do file transfer
|
||||||
# in transports, contact holds our info we need to disable it too
|
# in transports, contact holds our info we need to disable it too
|
||||||
|
@ -1699,9 +1734,10 @@ class ChatControl(ChatControlBase):
|
||||||
self.handlers[id] = add_to_roster_menuitem
|
self.handlers[id] = add_to_roster_menuitem
|
||||||
id = toggle_gpg_menuitem.connect('activate',
|
id = toggle_gpg_menuitem.connect('activate',
|
||||||
self._on_toggle_gpg_menuitem_activate)
|
self._on_toggle_gpg_menuitem_activate)
|
||||||
|
self.handlers[id] = toggle_gpg_menuitem
|
||||||
id = toggle_e2e_menuitem.connect('activate',
|
id = toggle_e2e_menuitem.connect('activate',
|
||||||
self._on_toggle_e2e_menuitem_activate)
|
self._on_toggle_e2e_menuitem_activate)
|
||||||
self.handlers[id] = toggle_gpg_menuitem
|
self.handlers[id] = toggle_e2e_menuitem
|
||||||
id = information_menuitem.connect('activate',
|
id = information_menuitem.connect('activate',
|
||||||
self._on_contact_information_menuitem_activate)
|
self._on_contact_information_menuitem_activate)
|
||||||
self.handlers[id] = information_menuitem
|
self.handlers[id] = information_menuitem
|
||||||
|
@ -2154,10 +2190,7 @@ class ChatControl(ChatControlBase):
|
||||||
gajim.interface.roster.on_info(widget, self.contact, self.account)
|
gajim.interface.roster.on_info(widget, self.contact, self.account)
|
||||||
|
|
||||||
def _on_toggle_gpg_menuitem_activate(self, widget):
|
def _on_toggle_gpg_menuitem_activate(self, widget):
|
||||||
# update the button
|
self._toggle_gpg()
|
||||||
# this is reverse logic, as we are on 'activate' (before change happens)
|
|
||||||
tb = self.xml.get_widget('gpg_togglebutton')
|
|
||||||
tb.set_active(not tb.get_active())
|
|
||||||
|
|
||||||
def _on_convert_to_gc_menuitem_activate(self, widget):
|
def _on_convert_to_gc_menuitem_activate(self, widget):
|
||||||
'''user want to invite some friends to chat'''
|
'''user want to invite some friends to chat'''
|
||||||
|
|
|
@ -28,24 +28,12 @@
|
||||||
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
##
|
##
|
||||||
|
|
||||||
import os
|
import gajim
|
||||||
from os import tmpfile
|
from os import tmpfile
|
||||||
from common import helpers
|
from common import helpers
|
||||||
|
|
||||||
USE_GPG = True
|
if gajim.HAVE_GPG:
|
||||||
|
import GnuPGInterface
|
||||||
try:
|
|
||||||
import GnuPGInterface # Debian package doesn't distribute 'our' file
|
|
||||||
except ImportError:
|
|
||||||
try:
|
|
||||||
from common import GnuPGInterface # use 'our' file
|
|
||||||
except ImportError:
|
|
||||||
USE_GPG = False # user can't do OpenGPG only if he or she removed the file!
|
|
||||||
|
|
||||||
else:
|
|
||||||
status = os.system('gpg -h >/dev/null 2>&1')
|
|
||||||
if status != 0:
|
|
||||||
USE_GPG = False
|
|
||||||
|
|
||||||
class GnuPG(GnuPGInterface.GnuPG):
|
class GnuPG(GnuPGInterface.GnuPG):
|
||||||
def __init__(self, use_agent = False):
|
def __init__(self, use_agent = False):
|
||||||
|
@ -57,8 +45,6 @@ else:
|
||||||
self.options.armor = 1
|
self.options.armor = 1
|
||||||
self.options.meta_interactive = 0
|
self.options.meta_interactive = 0
|
||||||
self.options.extra_args.append('--no-secmem-warning')
|
self.options.extra_args.append('--no-secmem-warning')
|
||||||
# Nolith's patch - prevent crashs on non fully-trusted keys
|
|
||||||
self.options.extra_args.append('--always-trust')
|
|
||||||
if self.use_agent:
|
if self.use_agent:
|
||||||
self.options.extra_args.append('--use-agent')
|
self.options.extra_args.append('--use-agent')
|
||||||
|
|
||||||
|
@ -88,8 +74,6 @@ else:
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
def encrypt(self, str, recipients):
|
def encrypt(self, str, recipients):
|
||||||
if not USE_GPG:
|
|
||||||
return str, 'GnuPG not usable'
|
|
||||||
self.options.recipients = recipients # a list!
|
self.options.recipients = recipients # a list!
|
||||||
|
|
||||||
proc = self.run(['--encrypt'], create_fhs=['stdin', 'stdout', 'status',
|
proc = self.run(['--encrypt'], create_fhs=['stdin', 'stdout', 'status',
|
||||||
|
@ -125,8 +109,6 @@ else:
|
||||||
return self._stripHeaderFooter(output), error
|
return self._stripHeaderFooter(output), error
|
||||||
|
|
||||||
def decrypt(self, str, keyID):
|
def decrypt(self, str, keyID):
|
||||||
if not USE_GPG:
|
|
||||||
return str
|
|
||||||
proc = self.run(['--decrypt', '-q', '-u %s'%keyID], create_fhs=['stdin', 'stdout'])
|
proc = self.run(['--decrypt', '-q', '-u %s'%keyID], create_fhs=['stdin', 'stdout'])
|
||||||
enc = self._addHeaderFooter(str, 'MESSAGE')
|
enc = self._addHeaderFooter(str, 'MESSAGE')
|
||||||
proc.handles['stdin'].write(enc)
|
proc.handles['stdin'].write(enc)
|
||||||
|
@ -140,8 +122,6 @@ else:
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def sign(self, str, keyID):
|
def sign(self, str, keyID):
|
||||||
if not USE_GPG:
|
|
||||||
return str
|
|
||||||
proc = self.run(['-b', '-u %s'%keyID], create_fhs=['stdin', 'stdout', 'status', 'stderr'])
|
proc = self.run(['-b', '-u %s'%keyID], create_fhs=['stdin', 'stdout', 'status', 'stderr'])
|
||||||
proc.handles['stdin'].write(str)
|
proc.handles['stdin'].write(str)
|
||||||
try:
|
try:
|
||||||
|
@ -170,8 +150,6 @@ else:
|
||||||
return 'BAD_PASSPHRASE'
|
return 'BAD_PASSPHRASE'
|
||||||
|
|
||||||
def verify(self, str, sign):
|
def verify(self, str, sign):
|
||||||
if not USE_GPG:
|
|
||||||
return str
|
|
||||||
if str == None:
|
if str == None:
|
||||||
return ''
|
return ''
|
||||||
f = tmpfile()
|
f = tmpfile()
|
||||||
|
@ -200,8 +178,6 @@ else:
|
||||||
return keyid
|
return keyid
|
||||||
|
|
||||||
def get_keys(self, secret = False):
|
def get_keys(self, secret = False):
|
||||||
if not USE_GPG:
|
|
||||||
return {}
|
|
||||||
if secret:
|
if secret:
|
||||||
opt = '--list-secret-keys'
|
opt = '--list-secret-keys'
|
||||||
else:
|
else:
|
||||||
|
@ -217,8 +193,10 @@ else:
|
||||||
sline = line.split(':')
|
sline = line.split(':')
|
||||||
if (sline[0] == 'sec' and secret) or \
|
if (sline[0] == 'sec' and secret) or \
|
||||||
(sline[0] == 'pub' and not secret):
|
(sline[0] == 'pub' and not secret):
|
||||||
|
# decode escaped chars
|
||||||
|
name = eval('"' + sline[9].replace('"', '\\"') + '"')
|
||||||
# make it unicode instance
|
# make it unicode instance
|
||||||
keys[sline[4][8:]] = helpers.decode_string(sline[9])
|
keys[sline[4][8:]] = helpers.decode_string(name)
|
||||||
return keys
|
return keys
|
||||||
try: proc.wait()
|
try: proc.wait()
|
||||||
except IOError: pass
|
except IOError: pass
|
||||||
|
|
|
@ -45,7 +45,7 @@ opt_int = [ 'integer', 0 ]
|
||||||
opt_str = [ 'string', 0 ]
|
opt_str = [ 'string', 0 ]
|
||||||
opt_bool = [ 'boolean', 0 ]
|
opt_bool = [ 'boolean', 0 ]
|
||||||
opt_color = [ 'color', '^(#[0-9a-fA-F]{6})|()$' ]
|
opt_color = [ 'color', '^(#[0-9a-fA-F]{6})|()$' ]
|
||||||
opt_one_window_types = ['never', 'always', 'peracct', 'pertype']
|
opt_one_window_types = ['never', 'always', 'always_with_roster', 'peracct', 'pertype']
|
||||||
opt_treat_incoming_messages = ['', 'chat', 'normal']
|
opt_treat_incoming_messages = ['', 'chat', 'normal']
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
|
@ -100,7 +100,6 @@ class Config:
|
||||||
'urlmsgcolor': [ opt_color, '#0000ff', '', True ],
|
'urlmsgcolor': [ opt_color, '#0000ff', '', True ],
|
||||||
'collapsed_rows': [ opt_str, '', _('List (space separated) of rows (accounts and groups) that are collapsed.'), True ],
|
'collapsed_rows': [ opt_str, '', _('List (space separated) of rows (accounts and groups) that are collapsed.'), True ],
|
||||||
'roster_theme': [ opt_str, _('default'), '', True ],
|
'roster_theme': [ opt_str, _('default'), '', True ],
|
||||||
'saveposition': [ opt_bool, True ],
|
|
||||||
'mergeaccounts': [ opt_bool, False, '', True ],
|
'mergeaccounts': [ opt_bool, False, '', True ],
|
||||||
'sort_by_show': [ opt_bool, True, '', True ],
|
'sort_by_show': [ opt_bool, True, '', True ],
|
||||||
'enable_zeroconf': [opt_bool, False, _('Enable link-local/zeroconf messaging')],
|
'enable_zeroconf': [opt_bool, False, _('Enable link-local/zeroconf messaging')],
|
||||||
|
@ -214,6 +213,7 @@ class Config:
|
||||||
'show_unread_tab_icon': [opt_bool, False, _('If True, Gajim will display an icon on each tab containing unread messages. Depending on the theme, this icon may be animated.')],
|
'show_unread_tab_icon': [opt_bool, False, _('If True, Gajim will display an icon on each tab containing unread messages. Depending on the theme, this icon may be animated.')],
|
||||||
'show_status_msgs_in_roster': [opt_bool, True, _('If True, Gajim will display the status message, if not empty, for every contact under the contact name in roster window.'), True],
|
'show_status_msgs_in_roster': [opt_bool, True, _('If True, Gajim will display the status message, if not empty, for every contact under the contact name in roster window.'), True],
|
||||||
'show_avatars_in_roster': [opt_bool, True, '', True],
|
'show_avatars_in_roster': [opt_bool, True, '', True],
|
||||||
|
'avatar_position_in_roster': [opt_str, 'right', _('Define the position of the avatar in roster. Can be left or right'), True],
|
||||||
'ask_avatars_on_startup': [opt_bool, True, _('If True, Gajim will ask for avatar each contact that did not have an avatar last time or has one cached that is too old.')],
|
'ask_avatars_on_startup': [opt_bool, True, _('If True, Gajim will ask for avatar each contact that did not have an avatar last time or has one cached that is too old.')],
|
||||||
'print_status_in_chats': [opt_bool, True, _('If False, Gajim will no longer print status line in chats when a contact changes his or her status and/or his or her status message.')],
|
'print_status_in_chats': [opt_bool, True, _('If False, Gajim will no longer print status line in chats when a contact changes his or her status and/or his or her status message.')],
|
||||||
'print_status_in_muc': [opt_str, 'in_and_out', _('can be "none", "all" or "in_and_out". If "none", Gajim will no longer print status line in groupchats when a member changes his or her status and/or his or her status message. If "all" Gajim will print all status messages. If "in_and_out", Gajim will only print FOO enters/leaves group chat.')],
|
'print_status_in_muc': [opt_str, 'in_and_out', _('can be "none", "all" or "in_and_out". If "none", Gajim will no longer print status line in groupchats when a member changes his or her status and/or his or her status message. If "all" Gajim will print all status messages. If "in_and_out", Gajim will only print FOO enters/leaves group chat.')],
|
||||||
|
@ -229,7 +229,7 @@ class Config:
|
||||||
'send_sha_in_gc_presence': [opt_bool, True, _('Jabberd1.4 does not like sha info when one join a password protected group chat. Turn this option to False to stop sending sha info in group chat presences.')],
|
'send_sha_in_gc_presence': [opt_bool, True, _('Jabberd1.4 does not like sha info when one join a password protected group chat. Turn this option to False to stop sending sha info in group chat presences.')],
|
||||||
'one_message_window': [opt_str, 'always',
|
'one_message_window': [opt_str, 'always',
|
||||||
#always, never, peracct, pertype should not be translated
|
#always, never, peracct, pertype should not be translated
|
||||||
_('Controls the window where new messages are placed.\n\'always\' - All messages are sent to a single window.\n\'never\' - All messages get their own window.\n\'peracct\' - Messages for each account are sent to a specific window.\n\'pertype\' - Each message type (e.g., chats vs. groupchats) are sent to a specific window. Note, changing this option requires restarting Gajim before the changes will take effect.')],
|
_('Controls the window where new messages are placed.\n\'always\' - All messages are sent to a single window.\n\'always_with_roster\' - Like \'always\' but the messages are in a single window along with the roster.\n\'never\' - All messages get their own window.\n\'peracct\' - Messages for each account are sent to a specific window.\n\'pertype\' - Each message type (e.g., chats vs. groupchats) are sent to a specific window.')],
|
||||||
'show_avatar_in_chat': [opt_bool, True, _('If False, you will no longer see the avatar in the chat window.')],
|
'show_avatar_in_chat': [opt_bool, True, _('If False, you will no longer see the avatar in the chat window.')],
|
||||||
'escape_key_closes': [opt_bool, True, _('If True, pressing the escape key closes a tab/window.')],
|
'escape_key_closes': [opt_bool, True, _('If True, pressing the escape key closes a tab/window.')],
|
||||||
'compact_view': [opt_bool, False, _('Hides the buttons in chat windows.')],
|
'compact_view': [opt_bool, False, _('Hides the buttons in chat windows.')],
|
||||||
|
@ -250,7 +250,14 @@ class Config:
|
||||||
'use_latex': [opt_bool, False, _('If True, Gajim will convert string between $$ and $$ to an image using dvips and convert before insterting it in chat window.')],
|
'use_latex': [opt_bool, False, _('If True, Gajim will convert string between $$ and $$ to an image using dvips and convert before insterting it in chat window.')],
|
||||||
'change_status_window_timeout': [opt_int, 15, _('Time of inactivity needed before the change status window closes down.')],
|
'change_status_window_timeout': [opt_int, 15, _('Time of inactivity needed before the change status window closes down.')],
|
||||||
'max_conversation_lines': [opt_int, 500, _('Maximum number of lines that are printed in conversations. Oldest lines are cleared.')],
|
'max_conversation_lines': [opt_int, 500, _('Maximum number of lines that are printed in conversations. Oldest lines are cleared.')],
|
||||||
|
'publish_mood': [opt_bool, False],
|
||||||
|
'publish_activity': [opt_bool, False],
|
||||||
|
'publish_tune': [opt_bool, False],
|
||||||
|
'subscribe_mood': [opt_bool, True],
|
||||||
|
'subscribe_activity': [opt_bool, True],
|
||||||
|
'subscribe_tune': [opt_bool, True],
|
||||||
'attach_notifications_to_systray': [opt_bool, False, _('If True, notification windows from notification-daemon will be attached to systray icon.')],
|
'attach_notifications_to_systray': [opt_bool, False, _('If True, notification windows from notification-daemon will be attached to systray icon.')],
|
||||||
|
'use_pep': [opt_bool, False, 'temporary variable to enable pep support'],
|
||||||
}
|
}
|
||||||
|
|
||||||
__options_per_key = {
|
__options_per_key = {
|
||||||
|
@ -275,7 +282,8 @@ class Config:
|
||||||
'keyid': [ opt_str, '', '', True ],
|
'keyid': [ opt_str, '', '', True ],
|
||||||
'gpg_sign_presence': [ opt_bool, True, _('If disabled, don\'t sign presences with GPG key, even if GPG is configured.') ],
|
'gpg_sign_presence': [ opt_bool, True, _('If disabled, don\'t sign presences with GPG key, even if GPG is configured.') ],
|
||||||
'keyname': [ opt_str, '', '', True ],
|
'keyname': [ opt_str, '', '', True ],
|
||||||
'usessl': [ opt_bool, False, '', True ],
|
'connection_types': [ opt_str, 'tls ssl plain', _('Ordered list (space separated) of connection type to try. Can contain tls, ssl or plain')],
|
||||||
|
'warn_when_insecure_connection': [ opt_bool, True, _('Show a warning dialog before sending password on an insecure connection.') ],
|
||||||
'ssl_fingerprint_sha1': [ opt_str, '', '', True ],
|
'ssl_fingerprint_sha1': [ opt_str, '', '', True ],
|
||||||
'use_srv': [ opt_bool, True, '', True ],
|
'use_srv': [ opt_bool, True, '', True ],
|
||||||
'use_custom_host': [ opt_bool, False, '', True ],
|
'use_custom_host': [ opt_bool, False, '', True ],
|
||||||
|
@ -306,6 +314,7 @@ class Config:
|
||||||
'zeroconf_last_name': [ opt_str, '', '', True ],
|
'zeroconf_last_name': [ opt_str, '', '', True ],
|
||||||
'zeroconf_jabber_id': [ opt_str, '', '', True ],
|
'zeroconf_jabber_id': [ opt_str, '', '', True ],
|
||||||
'zeroconf_email': [ opt_str, '', '', True ],
|
'zeroconf_email': [ opt_str, '', '', True ],
|
||||||
|
'use_env_http_proxy' : [opt_bool, False],
|
||||||
}, {}),
|
}, {}),
|
||||||
'statusmsg': ({
|
'statusmsg': ({
|
||||||
'message': [ opt_str, '' ],
|
'message': [ opt_str, '' ],
|
||||||
|
@ -354,7 +363,7 @@ class Config:
|
||||||
'state_muc_directed_msg_color': [ opt_color, 'red2' ],
|
'state_muc_directed_msg_color': [ opt_color, 'red2' ],
|
||||||
}, {}),
|
}, {}),
|
||||||
'contacts': ({
|
'contacts': ({
|
||||||
'gpg_enabled': [ opt_bool, True, _('Is OpenPGP enabled for this contact?')],
|
'gpg_enabled': [ opt_bool, False, _('Is OpenPGP enabled for this contact?')],
|
||||||
'speller_language': [ opt_str, '', _('Language for which we want to check misspelled words')],
|
'speller_language': [ opt_str, '', _('Language for which we want to check misspelled words')],
|
||||||
}, {}),
|
}, {}),
|
||||||
'rooms': ({
|
'rooms': ({
|
||||||
|
@ -400,7 +409,8 @@ class Config:
|
||||||
|
|
||||||
soundevents_default = {
|
soundevents_default = {
|
||||||
'first_message_received': [ True, '../data/sounds/message1.wav' ],
|
'first_message_received': [ True, '../data/sounds/message1.wav' ],
|
||||||
'next_message_received': [ True, '../data/sounds/message2.wav' ],
|
'next_message_received_focused': [ True, '../data/sounds/message2.wav' ],
|
||||||
|
'next_message_received_unfocused': [ True, '../data/sounds/message2.wav' ],
|
||||||
'contact_connected': [ True, '../data/sounds/connected.wav' ],
|
'contact_connected': [ True, '../data/sounds/connected.wav' ],
|
||||||
'contact_disconnected': [ True, '../data/sounds/disconnected.wav' ],
|
'contact_disconnected': [ True, '../data/sounds/disconnected.wav' ],
|
||||||
'message_sent': [ True, '../data/sounds/sent.wav' ],
|
'message_sent': [ True, '../data/sounds/sent.wav' ],
|
||||||
|
|
|
@ -48,7 +48,6 @@ from common import passwords
|
||||||
from common import exceptions
|
from common import exceptions
|
||||||
|
|
||||||
from connection_handlers import *
|
from connection_handlers import *
|
||||||
USE_GPG = GnuPG.USE_GPG
|
|
||||||
|
|
||||||
from common.rst_xhtml_generator import create_xhtml
|
from common.rst_xhtml_generator import create_xhtml
|
||||||
|
|
||||||
|
@ -56,8 +55,6 @@ from string import Template
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger('gajim.c.connection')
|
log = logging.getLogger('gajim.c.connection')
|
||||||
|
|
||||||
import gtkgui_helpers
|
|
||||||
|
|
||||||
ssl_error = {
|
ssl_error = {
|
||||||
2: _("Unable to get issuer certificate"),
|
2: _("Unable to get issuer certificate"),
|
||||||
3: _("Unable to get certificate CRL"),
|
3: _("Unable to get certificate CRL"),
|
||||||
|
@ -75,9 +72,9 @@ ssl_error = {
|
||||||
15: _("Format error in CRL's lastUpdate field"),
|
15: _("Format error in CRL's lastUpdate field"),
|
||||||
16: _("Format error in CRL's nextUpdate field"),
|
16: _("Format error in CRL's nextUpdate field"),
|
||||||
17: _("Out of memory"),
|
17: _("Out of memory"),
|
||||||
18: _("Self signed certificate in certificate chain"),
|
18: _("Self signed certificate"),
|
||||||
19: _("Unable to get local issuer certificate"),
|
19: _("Self signed certificate in certificate chain"),
|
||||||
20: _("Unable to verify the first certificate"),
|
20: _("Unable to get local issuer certificate"),
|
||||||
21: _("Unable to verify the first certificate"),
|
21: _("Unable to verify the first certificate"),
|
||||||
22: _("Certificate chain too long"),
|
22: _("Certificate chain too long"),
|
||||||
23: _("Certificate revoked"),
|
23: _("Certificate revoked"),
|
||||||
|
@ -107,7 +104,9 @@ class Connection(ConnectionHandlers):
|
||||||
self.last_connection = None # last ClientCommon instance
|
self.last_connection = None # last ClientCommon instance
|
||||||
self.is_zeroconf = False
|
self.is_zeroconf = False
|
||||||
self.gpg = None
|
self.gpg = None
|
||||||
if USE_GPG:
|
self.USE_GPG = False
|
||||||
|
if gajim.HAVE_GPG:
|
||||||
|
self.USE_GPG = True
|
||||||
self.gpg = GnuPG.GnuPG(gajim.config.get('use_gpg_agent'))
|
self.gpg = GnuPG.GnuPG(gajim.config.get('use_gpg_agent'))
|
||||||
self.status = ''
|
self.status = ''
|
||||||
self.priority = gajim.get_priority(name, 'offline')
|
self.priority = gajim.get_priority(name, 'offline')
|
||||||
|
@ -142,6 +141,9 @@ class Connection(ConnectionHandlers):
|
||||||
self.blocked_contacts = []
|
self.blocked_contacts = []
|
||||||
self.blocked_groups = []
|
self.blocked_groups = []
|
||||||
self.pep_supported = False
|
self.pep_supported = False
|
||||||
|
self.mood = {}
|
||||||
|
self.tune = {}
|
||||||
|
self.activity = {}
|
||||||
# Do we continue connection when we get roster (send presence,get vcard..)
|
# Do we continue connection when we get roster (send presence,get vcard..)
|
||||||
self.continue_connect_info = None
|
self.continue_connect_info = None
|
||||||
# To know the groupchat jid associated with a sranza ID. Useful to
|
# To know the groupchat jid associated with a sranza ID. Useful to
|
||||||
|
@ -178,7 +180,7 @@ class Connection(ConnectionHandlers):
|
||||||
self.dispatch('STATUS', 'connecting')
|
self.dispatch('STATUS', 'connecting')
|
||||||
self.retrycount += 1
|
self.retrycount += 1
|
||||||
self.on_connect_auth = self._init_roster
|
self.on_connect_auth = self._init_roster
|
||||||
self.connect_and_init(self.old_show, self.status, self.gpg != None)
|
self.connect_and_init(self.old_show, self.status, self.USE_GPG)
|
||||||
else:
|
else:
|
||||||
# reconnect succeeded
|
# reconnect succeeded
|
||||||
self.time_to_reconnect = None
|
self.time_to_reconnect = None
|
||||||
|
@ -186,6 +188,8 @@ class Connection(ConnectionHandlers):
|
||||||
|
|
||||||
# We are doing disconnect at so many places, better use one function in all
|
# We are doing disconnect at so many places, better use one function in all
|
||||||
def disconnect(self, on_purpose=False):
|
def disconnect(self, on_purpose=False):
|
||||||
|
#FIXME: set the Tune to None before disconnection per account
|
||||||
|
#gajim.interface.roster._music_track_changed(None, None)
|
||||||
self.on_purpose = on_purpose
|
self.on_purpose = on_purpose
|
||||||
self.connected = 0
|
self.connected = 0
|
||||||
self.time_to_reconnect = None
|
self.time_to_reconnect = None
|
||||||
|
@ -265,7 +269,8 @@ class Connection(ConnectionHandlers):
|
||||||
if not common.xmpp.isResultNode(result):
|
if not common.xmpp.isResultNode(result):
|
||||||
self.dispatch('ACC_NOT_OK', (result.getError()))
|
self.dispatch('ACC_NOT_OK', (result.getError()))
|
||||||
return
|
return
|
||||||
if USE_GPG:
|
if gajim.HAVE_GPG:
|
||||||
|
self.USE_GPG = True
|
||||||
self.gpg = GnuPG.GnuPG(gajim.config.get(
|
self.gpg = GnuPG.GnuPG(gajim.config.get(
|
||||||
'use_gpg_agent'))
|
'use_gpg_agent'))
|
||||||
self.dispatch('ACC_OK', (self.new_account_info))
|
self.dispatch('ACC_OK', (self.new_account_info))
|
||||||
|
@ -279,7 +284,7 @@ class Connection(ConnectionHandlers):
|
||||||
# typed, so send them
|
# typed, so send them
|
||||||
if is_form:
|
if is_form:
|
||||||
#TODO: Check if form has changed
|
#TODO: Check if form has changed
|
||||||
iq = Iq('set', NS_REGISTER, to=self._hostname)
|
iq = common.xmpp.Iq('set', common.xmpp.NS_REGISTER, to=self._hostname)
|
||||||
iq.setTag('query').addChild(node=self.new_account_form)
|
iq.setTag('query').addChild(node=self.new_account_form)
|
||||||
self.connection.SendAndCallForResponse(iq,
|
self.connection.SendAndCallForResponse(iq,
|
||||||
_on_register_result)
|
_on_register_result)
|
||||||
|
@ -313,7 +318,7 @@ class Connection(ConnectionHandlers):
|
||||||
ssl_fingerprint = \
|
ssl_fingerprint = \
|
||||||
self.connection.Connection.ssl_fingerprint_sha1
|
self.connection.Connection.ssl_fingerprint_sha1
|
||||||
self.dispatch('NEW_ACC_CONNECTED', (conf, is_form, ssl_msg,
|
self.dispatch('NEW_ACC_CONNECTED', (conf, is_form, ssl_msg,
|
||||||
ssl_cert, ssl_fingerprint))
|
errnum, ssl_cert, ssl_fingerprint))
|
||||||
self.connection.UnregisterDisconnectHandler(
|
self.connection.UnregisterDisconnectHandler(
|
||||||
self._on_new_account)
|
self._on_new_account)
|
||||||
self.disconnect(on_purpose=True)
|
self.disconnect(on_purpose=True)
|
||||||
|
@ -423,27 +428,56 @@ class Connection(ConnectionHandlers):
|
||||||
proxy['user'] = gajim.config.get_per('proxies', p, 'user')
|
proxy['user'] = gajim.config.get_per('proxies', p, 'user')
|
||||||
proxy['password'] = gajim.config.get_per('proxies', p, 'pass')
|
proxy['password'] = gajim.config.get_per('proxies', p, 'pass')
|
||||||
proxy['type'] = gajim.config.get_per('proxies', p, 'type')
|
proxy['type'] = gajim.config.get_per('proxies', p, 'type')
|
||||||
|
elif gajim.config.get_per('accounts', self.name, 'use_env_http_proxy'):
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
env_http_proxy = os.environ['HTTP_PROXY']
|
||||||
|
except:
|
||||||
|
env_http_proxy = os.environ['http_proxy']
|
||||||
|
env_http_proxy = env_http_proxy.strip('"')
|
||||||
|
# Dispose of the http:// prefix
|
||||||
|
env_http_proxy = env_http_proxy.split('://')
|
||||||
|
env_http_proxy = env_http_proxy[len(env_http_proxy)-1]
|
||||||
|
env_http_proxy = env_http_proxy.split('@')
|
||||||
|
|
||||||
|
if len(env_http_proxy) == 2:
|
||||||
|
login = env_http_proxy[0].split(':')
|
||||||
|
addr = env_http_proxy[1].split(':')
|
||||||
|
else:
|
||||||
|
login = ['', '']
|
||||||
|
addr = env_http_proxy[0].split(':')
|
||||||
|
|
||||||
|
proxy = {'host': addr[0], 'type' : u'http', 'user':login[0]}
|
||||||
|
|
||||||
|
if len(addr) == 2:
|
||||||
|
proxy['port'] = addr[1]
|
||||||
|
else:
|
||||||
|
proxy['port'] = 3128
|
||||||
|
|
||||||
|
if len(login) == 2:
|
||||||
|
proxy['password'] = login[1]
|
||||||
|
else:
|
||||||
|
proxy['password'] = u''
|
||||||
|
|
||||||
|
except:
|
||||||
|
proxy = None
|
||||||
else:
|
else:
|
||||||
proxy = None
|
proxy = None
|
||||||
|
|
||||||
h = hostname
|
h = hostname
|
||||||
p = 5222
|
p = 5222
|
||||||
# autodetect [for SSL in 5223/443 and for TLS if broadcasted]
|
ssl_p = 5223
|
||||||
secur = None
|
# use_srv = False # wants ssl? disable srv lookup
|
||||||
if usessl:
|
|
||||||
p = 5223
|
|
||||||
secur = 1 # 1 means force SSL no matter what the port will be
|
|
||||||
use_srv = False # wants ssl? disable srv lookup
|
|
||||||
if use_custom:
|
if use_custom:
|
||||||
h = custom_h
|
h = custom_h
|
||||||
p = custom_p
|
p = custom_p
|
||||||
|
ssl_p = custom_p
|
||||||
use_srv = False
|
use_srv = False
|
||||||
|
|
||||||
hosts = []
|
|
||||||
# SRV resolver
|
# SRV resolver
|
||||||
self._proxy = proxy
|
self._proxy = proxy
|
||||||
self._secure = secur
|
self._hosts = [ {'host': h, 'port': p, 'ssl_port': ssl_p, 'prio': 10,
|
||||||
self._hosts = [ {'host': h, 'port': p, 'prio': 10, 'weight': 10} ]
|
'weight': 10} ]
|
||||||
self._hostname = hostname
|
self._hostname = hostname
|
||||||
if use_srv:
|
if use_srv:
|
||||||
# add request for srv query to the resolve, on result '_on_resolve'
|
# add request for srv query to the resolve, on result '_on_resolve'
|
||||||
|
@ -457,6 +491,12 @@ class Connection(ConnectionHandlers):
|
||||||
# SRV query returned at least one valid result, we put it in hosts dict
|
# SRV query returned at least one valid result, we put it in hosts dict
|
||||||
if len(result_array) != 0:
|
if len(result_array) != 0:
|
||||||
self._hosts = [i for i in result_array]
|
self._hosts = [i for i in result_array]
|
||||||
|
# Add ssl port
|
||||||
|
ssl_p = 5223
|
||||||
|
if gajim.config.get_per('accounts', self.name, 'use_custom_host'):
|
||||||
|
ssl_p = gajim.config.get_per('accounts', self.name, 'custom_port')
|
||||||
|
for i in self._hosts:
|
||||||
|
i['ssl_port'] = ssl_p
|
||||||
self.connect_to_next_host()
|
self.connect_to_next_host()
|
||||||
|
|
||||||
def on_proxy_failure(self, reason):
|
def on_proxy_failure(self, reason):
|
||||||
|
@ -468,8 +508,9 @@ class Connection(ConnectionHandlers):
|
||||||
self.dispatch('CONNECTION_LOST',
|
self.dispatch('CONNECTION_LOST',
|
||||||
(_('Connection to proxy failed'), reason))
|
(_('Connection to proxy failed'), reason))
|
||||||
|
|
||||||
def connect_to_next_host(self, retry = False):
|
def connect_to_next_type(self, retry=False):
|
||||||
if len(self._hosts):
|
if len(self._connection_types):
|
||||||
|
self._current_type = self._connection_types.pop(0)
|
||||||
if self.last_connection:
|
if self.last_connection:
|
||||||
self.last_connection.socket.disconnect()
|
self.last_connection.socket.disconnect()
|
||||||
self.last_connection = None
|
self.last_connection = None
|
||||||
|
@ -478,27 +519,49 @@ class Connection(ConnectionHandlers):
|
||||||
con = common.xmpp.NonBlockingClient(self._hostname, caller = self,
|
con = common.xmpp.NonBlockingClient(self._hostname, caller = self,
|
||||||
on_connect = self.on_connect_success,
|
on_connect = self.on_connect_success,
|
||||||
on_proxy_failure = self.on_proxy_failure,
|
on_proxy_failure = self.on_proxy_failure,
|
||||||
on_connect_failure = self.connect_to_next_host)
|
on_connect_failure = self.connect_to_next_type)
|
||||||
else:
|
else:
|
||||||
con = common.xmpp.NonBlockingClient(self._hostname, debug = [], caller = self,
|
con = common.xmpp.NonBlockingClient(self._hostname, debug = [],
|
||||||
on_connect = self.on_connect_success,
|
caller = self, on_connect = self.on_connect_success,
|
||||||
on_proxy_failure = self.on_proxy_failure,
|
on_proxy_failure = self.on_proxy_failure,
|
||||||
on_connect_failure = self.connect_to_next_host)
|
on_connect_failure = self.connect_to_next_type)
|
||||||
self.last_connection = con
|
self.last_connection = con
|
||||||
# increase default timeout for server responses
|
# increase default timeout for server responses
|
||||||
common.xmpp.dispatcher_nb.DEFAULT_TIMEOUT_SECONDS = self.try_connecting_for_foo_secs
|
common.xmpp.dispatcher_nb.DEFAULT_TIMEOUT_SECONDS = self.try_connecting_for_foo_secs
|
||||||
con.set_idlequeue(gajim.idlequeue)
|
con.set_idlequeue(gajim.idlequeue)
|
||||||
host = self.select_next_host(self._hosts)
|
|
||||||
self._current_host = host
|
|
||||||
self._hosts.remove(host)
|
|
||||||
|
|
||||||
# FIXME: this is a hack; need a better way
|
# FIXME: this is a hack; need a better way
|
||||||
if self.on_connect_success == self._on_new_account:
|
if self.on_connect_success == self._on_new_account:
|
||||||
con.RegisterDisconnectHandler(self._on_new_account)
|
con.RegisterDisconnectHandler(self._on_new_account)
|
||||||
|
|
||||||
log.info("Connecting to %s: [%s:%d]", self.name, host['host'], host['port'])
|
if self._current_type == 'ssl':
|
||||||
con.connect((host['host'], host['port']), proxy = self._proxy,
|
port = self._current_host['ssl_port']
|
||||||
secure = self._secure)
|
secur = 1
|
||||||
|
else:
|
||||||
|
port = self._current_host['port']
|
||||||
|
if self._current_type == 'plain':
|
||||||
|
secur = 0
|
||||||
|
else:
|
||||||
|
secur = None
|
||||||
|
log.info('Connecting to %s: [%s:%d]', self.name,
|
||||||
|
self._current_host['host'], port)
|
||||||
|
con.connect((self._current_host['host'], port), proxy=self._proxy,
|
||||||
|
secure = secur)
|
||||||
|
else:
|
||||||
|
self.connect_to_next_host(retry)
|
||||||
|
|
||||||
|
def connect_to_next_host(self, retry = False):
|
||||||
|
if len(self._hosts):
|
||||||
|
# No config option exist when creating a new account
|
||||||
|
if self.name in gajim.config.get_per('accounts'):
|
||||||
|
self._connection_types = gajim.config.get_per('accounts', self.name,
|
||||||
|
'connection_types').split()
|
||||||
|
else:
|
||||||
|
self._connection_types = ['tls', 'ssl', 'plain']
|
||||||
|
host = self.select_next_host(self._hosts)
|
||||||
|
self._current_host = host
|
||||||
|
self._hosts.remove(host)
|
||||||
|
self.connect_to_next_type()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if not retry and self.retrycount == 0:
|
if not retry and self.retrycount == 0:
|
||||||
log.debug("Out of hosts, giving up connecting to %s", self.name)
|
log.debug("Out of hosts, giving up connecting to %s", self.name)
|
||||||
|
@ -527,15 +590,26 @@ class Connection(ConnectionHandlers):
|
||||||
if not self.connected: # We went offline during connecting process
|
if not self.connected: # We went offline during connecting process
|
||||||
# FIXME - not possible, maybe it was when we used threads
|
# FIXME - not possible, maybe it was when we used threads
|
||||||
return
|
return
|
||||||
|
_con_type = con_type
|
||||||
|
# xmpp returns 'tcp', but we set 'plain' in connection_types in config
|
||||||
|
if _con_type == 'tcp':
|
||||||
|
_con_type = 'plain'
|
||||||
|
if _con_type != self._current_type:
|
||||||
|
self.connect_to_next_type()
|
||||||
|
return
|
||||||
|
if _con_type == 'plain' and gajim.config.get_per('accounts', self.name,
|
||||||
|
'warn_when_insecure_connection'):
|
||||||
|
self.dispatch('PLAIN_CONNECTION', (con,))
|
||||||
|
return True
|
||||||
|
return self.connection_accepted(con, con_type)
|
||||||
|
|
||||||
|
def connection_accepted(self, con, con_type):
|
||||||
self.hosts = []
|
self.hosts = []
|
||||||
if not con_type:
|
|
||||||
log.debug('Could not connect to %s:%s' % (self._current_host['host'],
|
|
||||||
self._current_host['port']))
|
|
||||||
self.connected_hostname = self._current_host['host']
|
self.connected_hostname = self._current_host['host']
|
||||||
self.on_connect_failure = None
|
self.on_connect_failure = None
|
||||||
con.RegisterDisconnectHandler(self._disconnectedReconnCB)
|
con.RegisterDisconnectHandler(self._disconnectedReconnCB)
|
||||||
log.debug(_('Connected to server %s:%s with %s') % (self._current_host['host'],
|
log.debug('Connected to server %s:%s with %s' % (
|
||||||
self._current_host['port'], con_type))
|
self._current_host['host'], self._current_host['port'], con_type))
|
||||||
|
|
||||||
name = gajim.config.get_per('accounts', self.name, 'name')
|
name = gajim.config.get_per('accounts', self.name, 'name')
|
||||||
hostname = gajim.config.get_per('accounts', self.name, 'hostname')
|
hostname = gajim.config.get_per('accounts', self.name, 'hostname')
|
||||||
|
@ -548,10 +622,10 @@ class Connection(ConnectionHandlers):
|
||||||
text = _('The authenticity of the %s certificate could be invalid.') %\
|
text = _('The authenticity of the %s certificate could be invalid.') %\
|
||||||
hostname
|
hostname
|
||||||
if errnum in ssl_error:
|
if errnum in ssl_error:
|
||||||
text += _('\nSSL Error: %s') % ssl_error[errnum]
|
text += _('\nSSL Error: <b>%s</b>') % ssl_error[errnum]
|
||||||
else:
|
else:
|
||||||
text += _('\nUnknown SSL error: %d') % errnum
|
text += _('\nUnknown SSL error: %d') % errnum
|
||||||
self.dispatch('SSL_ERROR', (text, con.Connection.ssl_cert_pem,
|
self.dispatch('SSL_ERROR', (text, errnum, con.Connection.ssl_cert_pem,
|
||||||
con.Connection.ssl_fingerprint_sha1))
|
con.Connection.ssl_fingerprint_sha1))
|
||||||
return True
|
return True
|
||||||
if hasattr(con.Connection, 'ssl_fingerprint_sha1'):
|
if hasattr(con.Connection, 'ssl_fingerprint_sha1'):
|
||||||
|
@ -565,11 +639,17 @@ class Connection(ConnectionHandlers):
|
||||||
self._register_handlers(con, con_type)
|
self._register_handlers(con, con_type)
|
||||||
con.auth(name, self.password, self.server_resource, 1, self.__on_auth)
|
con.auth(name, self.password, self.server_resource, 1, self.__on_auth)
|
||||||
|
|
||||||
|
|
||||||
def ssl_certificate_accepted(self):
|
def ssl_certificate_accepted(self):
|
||||||
name = gajim.config.get_per('accounts', self.name, 'name')
|
name = gajim.config.get_per('accounts', self.name, 'name')
|
||||||
self._register_handlers(self.connection, 'ssl')
|
self._register_handlers(self.connection, 'ssl')
|
||||||
self.connection.auth(name, self.password, self.server_resource, 1, self.__on_auth)
|
self.connection.auth(name, self.password, self.server_resource, 1,
|
||||||
|
self.__on_auth)
|
||||||
|
|
||||||
|
def plain_connection_accepted(self):
|
||||||
|
name = gajim.config.get_per('accounts', self.name, 'name')
|
||||||
|
self._register_handlers(self.connection, 'tcp')
|
||||||
|
self.connection.auth(name, self.password, self.server_resource, 1,
|
||||||
|
self.__on_auth)
|
||||||
|
|
||||||
def _register_handlers(self, con, con_type):
|
def _register_handlers(self, con, con_type):
|
||||||
self.peerhost = con.get_peerhost()
|
self.peerhost = con.get_peerhost()
|
||||||
|
@ -699,6 +779,17 @@ class Connection(ConnectionHandlers):
|
||||||
def send_invisible_presence(self, msg, signed, initial = False):
|
def send_invisible_presence(self, msg, signed, initial = False):
|
||||||
if not self.connection:
|
if not self.connection:
|
||||||
return
|
return
|
||||||
|
# If we are already connected, and privacy rules are supported, send
|
||||||
|
# offline presence first as it's required by XEP-0126
|
||||||
|
if self.connected > 1 and self.privacy_rules_supported:
|
||||||
|
self.on_purpose = True
|
||||||
|
p = common.xmpp.Presence(typ = 'unavailable')
|
||||||
|
p = self.add_sha(p, False)
|
||||||
|
if msg:
|
||||||
|
p.setStatus(msg)
|
||||||
|
self.remove_all_transfers()
|
||||||
|
self.connection.send(p)
|
||||||
|
|
||||||
# try to set the privacy rule
|
# try to set the privacy rule
|
||||||
iq = self.build_privacy_rule('invisible', 'deny')
|
iq = self.build_privacy_rule('invisible', 'deny')
|
||||||
self.connection.SendAndCallForResponse(iq, self._continue_invisible,
|
self.connection.SendAndCallForResponse(iq, self._continue_invisible,
|
||||||
|
@ -707,8 +798,7 @@ class Connection(ConnectionHandlers):
|
||||||
def _continue_invisible(self, con, iq_obj, msg, signed, initial):
|
def _continue_invisible(self, con, iq_obj, msg, signed, initial):
|
||||||
ptype = ''
|
ptype = ''
|
||||||
show = ''
|
show = ''
|
||||||
# FIXME: JEP 126 need some modifications (see http://lists.jabber.ru/pipermail/ejabberd/2005-July/001252.html). So I disable it for the moment
|
if iq_obj.getType() == 'error': # server doesn't support privacy lists
|
||||||
if 1 or iq_obj.getType() == 'error': #server doesn't support privacy lists
|
|
||||||
# We use the old way which is not xmpp complient
|
# We use the old way which is not xmpp complient
|
||||||
ptype = 'invisible'
|
ptype = 'invisible'
|
||||||
show = 'invisible'
|
show = 'invisible'
|
||||||
|
@ -760,7 +850,7 @@ class Connection(ConnectionHandlers):
|
||||||
callback is the function to call when user give the passphrase'''
|
callback is the function to call when user give the passphrase'''
|
||||||
signed = ''
|
signed = ''
|
||||||
keyID = gajim.config.get_per('accounts', self.name, 'keyid')
|
keyID = gajim.config.get_per('accounts', self.name, 'keyid')
|
||||||
if keyID and self.gpg:
|
if keyID and self.USE_GPG:
|
||||||
use_gpg_agent = gajim.config.get('use_gpg_agent')
|
use_gpg_agent = gajim.config.get('use_gpg_agent')
|
||||||
if self.gpg.passphrase is None and not use_gpg_agent:
|
if self.gpg.passphrase is None and not use_gpg_agent:
|
||||||
# We didn't set a passphrase
|
# We didn't set a passphrase
|
||||||
|
@ -768,7 +858,7 @@ class Connection(ConnectionHandlers):
|
||||||
if self.gpg.passphrase is not None or use_gpg_agent:
|
if self.gpg.passphrase is not None or use_gpg_agent:
|
||||||
signed = self.gpg.sign(msg, keyID)
|
signed = self.gpg.sign(msg, keyID)
|
||||||
if signed == 'BAD_PASSPHRASE':
|
if signed == 'BAD_PASSPHRASE':
|
||||||
self.gpg = None
|
self.USE_GPG = False
|
||||||
signed = ''
|
signed = ''
|
||||||
self.dispatch('BAD_PASSPHRASE', ())
|
self.dispatch('BAD_PASSPHRASE', ())
|
||||||
return signed
|
return signed
|
||||||
|
@ -845,7 +935,8 @@ class Connection(ConnectionHandlers):
|
||||||
safe_substitute({
|
safe_substitute({
|
||||||
'hostname': socket.gethostname()
|
'hostname': socket.gethostname()
|
||||||
})
|
})
|
||||||
if USE_GPG:
|
if gajim.HAVE_GPG:
|
||||||
|
self.USE_GPG = True
|
||||||
self.gpg = GnuPG.GnuPG(gajim.config.get('use_gpg_agent'))
|
self.gpg = GnuPG.GnuPG(gajim.config.get('use_gpg_agent'))
|
||||||
self.connect_and_init(show, msg, sign_msg)
|
self.connect_and_init(show, msg, sign_msg)
|
||||||
|
|
||||||
|
@ -922,9 +1013,15 @@ class Connection(ConnectionHandlers):
|
||||||
fjid += '/' + resource
|
fjid += '/' + resource
|
||||||
msgtxt = msg
|
msgtxt = msg
|
||||||
msgenc = ''
|
msgenc = ''
|
||||||
if keyID and self.gpg:
|
|
||||||
#encrypt
|
if keyID and self.USE_GPG:
|
||||||
msgenc, error = self.gpg.encrypt(msg, [keyID])
|
if keyID == 'UNKNOWN':
|
||||||
|
error = _('Neither the remote presence is signed, nor a key was assigned.')
|
||||||
|
elif keyID[8:] == 'MISMATCH':
|
||||||
|
error = _('The contact\'s key (%s) does not match the key assigned in Gajim.' % keyID[:8])
|
||||||
|
else:
|
||||||
|
#encrypt
|
||||||
|
msgenc, error = self.gpg.encrypt(msg, [keyID])
|
||||||
if msgenc and not error:
|
if msgenc and not error:
|
||||||
msgtxt = '[This message is encrypted]'
|
msgtxt = '[This message is encrypted]'
|
||||||
lang = os.getenv('LANG')
|
lang = os.getenv('LANG')
|
||||||
|
@ -1109,7 +1206,7 @@ class Connection(ConnectionHandlers):
|
||||||
def send_new_account_infos(self, form, is_form):
|
def send_new_account_infos(self, form, is_form):
|
||||||
if is_form:
|
if is_form:
|
||||||
# Get username and password and put them in new_account_info
|
# Get username and password and put them in new_account_info
|
||||||
for field in self._data_form.iter_fields():
|
for field in form.iter_fields():
|
||||||
if field.var == 'username':
|
if field.var == 'username':
|
||||||
self.new_account_info['name'] = field.value
|
self.new_account_info['name'] = field.value
|
||||||
if field.var == 'password':
|
if field.var == 'password':
|
||||||
|
|
|
@ -35,15 +35,20 @@ from calendar import timegm
|
||||||
import socks5
|
import socks5
|
||||||
import common.xmpp
|
import common.xmpp
|
||||||
|
|
||||||
from common import GnuPG
|
|
||||||
from common import helpers
|
from common import helpers
|
||||||
from common import gajim
|
from common import gajim
|
||||||
from common import atom
|
from common import atom
|
||||||
|
from common import pep
|
||||||
from common import exceptions
|
from common import exceptions
|
||||||
from common.commands import ConnectionCommands
|
from common.commands import ConnectionCommands
|
||||||
from common.pubsub import ConnectionPubSub
|
from common.pubsub import ConnectionPubSub
|
||||||
from common.caps import ConnectionCaps
|
from common.caps import ConnectionCaps
|
||||||
|
|
||||||
|
from common import dbus_support
|
||||||
|
if dbus_support.supported:
|
||||||
|
import dbus
|
||||||
|
from music_track_listener import MusicTrackListener
|
||||||
|
|
||||||
from common.stanza_session import EncryptedStanzaSession
|
from common.stanza_session import EncryptedStanzaSession
|
||||||
|
|
||||||
STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
|
STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
|
||||||
|
@ -54,6 +59,7 @@ VCARD_ARRIVED = 'vcard_arrived'
|
||||||
AGENT_REMOVED = 'agent_removed'
|
AGENT_REMOVED = 'agent_removed'
|
||||||
METACONTACTS_ARRIVED = 'metacontacts_arrived'
|
METACONTACTS_ARRIVED = 'metacontacts_arrived'
|
||||||
PRIVACY_ARRIVED = 'privacy_arrived'
|
PRIVACY_ARRIVED = 'privacy_arrived'
|
||||||
|
PEP_ACCESS_MODEL = 'pep_access_model'
|
||||||
HAS_IDLE = True
|
HAS_IDLE = True
|
||||||
try:
|
try:
|
||||||
import idle
|
import idle
|
||||||
|
@ -182,7 +188,7 @@ class ConnectionBytestream:
|
||||||
ft_add_hosts_to_send = map(lambda e:e.strip(),
|
ft_add_hosts_to_send = map(lambda e:e.strip(),
|
||||||
ft_add_hosts_to_send.split(','))
|
ft_add_hosts_to_send.split(','))
|
||||||
for ft_host in ft_add_hosts_to_send:
|
for ft_host in ft_add_hosts_to_send:
|
||||||
ft_add_hosts.append(ft_host)
|
ft_add_hosts.append(ft_host)
|
||||||
listener = gajim.socks5queue.start_listener(port,
|
listener = gajim.socks5queue.start_listener(port,
|
||||||
sha_str, self._result_socks5_sid, file_props['sid'])
|
sha_str, self._result_socks5_sid, file_props['sid'])
|
||||||
if listener == None:
|
if listener == None:
|
||||||
|
@ -750,6 +756,13 @@ class ConnectionDisco:
|
||||||
q.addChild('feature', attrs = {'var': common.xmpp.NS_MUC})
|
q.addChild('feature', attrs = {'var': common.xmpp.NS_MUC})
|
||||||
q.addChild('feature', attrs = {'var': common.xmpp.NS_COMMANDS})
|
q.addChild('feature', attrs = {'var': common.xmpp.NS_COMMANDS})
|
||||||
q.addChild('feature', attrs = {'var': common.xmpp.NS_DISCO_INFO})
|
q.addChild('feature', attrs = {'var': common.xmpp.NS_DISCO_INFO})
|
||||||
|
if gajim.config.get('use_pep'):
|
||||||
|
q.addChild('feature', attrs = {'var': common.xmpp.NS_ACTIVITY})
|
||||||
|
q.addChild('feature', attrs = {'var': common.xmpp.NS_ACTIVITY + '+notify'})
|
||||||
|
q.addChild('feature', attrs = {'var': common.xmpp.NS_TUNE})
|
||||||
|
q.addChild('feature', attrs = {'var': common.xmpp.NS_TUNE + '+notify'})
|
||||||
|
q.addChild('feature', attrs = {'var': common.xmpp.NS_MOOD})
|
||||||
|
q.addChild('feature', attrs = {'var': common.xmpp.NS_MOOD + '+notify'})
|
||||||
q.addChild('feature', attrs = {'var': common.xmpp.NS_ESESSION_INIT})
|
q.addChild('feature', attrs = {'var': common.xmpp.NS_ESESSION_INIT})
|
||||||
|
|
||||||
if (node is None or extension == 'cstates') and gajim.config.get('outgoing_chat_state_notifactions') != 'disabled':
|
if (node is None or extension == 'cstates') and gajim.config.get('outgoing_chat_state_notifactions') != 'disabled':
|
||||||
|
@ -821,6 +834,12 @@ class ConnectionDisco:
|
||||||
if identity['category'] == 'pubsub' and identity['type'] == \
|
if identity['category'] == 'pubsub' and identity['type'] == \
|
||||||
'pep':
|
'pep':
|
||||||
self.pep_supported = True
|
self.pep_supported = True
|
||||||
|
if dbus_support.supported:
|
||||||
|
listener = MusicTrackListener.get()
|
||||||
|
track = listener.get_playing_track()
|
||||||
|
if gajim.config.get('publish_tune'):
|
||||||
|
gajim.interface.roster._music_track_changed(listener,
|
||||||
|
track, self.name)
|
||||||
break
|
break
|
||||||
if features.__contains__(common.xmpp.NS_BYTESTREAM):
|
if features.__contains__(common.xmpp.NS_BYTESTREAM):
|
||||||
gajim.proxy65_manager.resolve(jid, self.connection, self.name)
|
gajim.proxy65_manager.resolve(jid, self.connection, self.name)
|
||||||
|
@ -1099,6 +1118,16 @@ class ConnectionVcard:
|
||||||
self.get_privacy_list('block')
|
self.get_privacy_list('block')
|
||||||
# Ask metacontacts before roster
|
# Ask metacontacts before roster
|
||||||
self.get_metacontacts()
|
self.get_metacontacts()
|
||||||
|
elif self.awaiting_answers[id][0] == PEP_ACCESS_MODEL:
|
||||||
|
conf = iq_obj.getTag('pubsub').getTag('configure')
|
||||||
|
node = conf.getAttr('node')
|
||||||
|
form_tag = conf.getTag('x', namespace=common.xmpp.NS_DATA)
|
||||||
|
if form_tag:
|
||||||
|
form = common.dataforms.ExtendForm(node=form_tag)
|
||||||
|
for field in form.iter_fields():
|
||||||
|
if field.var == 'pubsub#access_model':
|
||||||
|
self.dispatch('PEP_ACCESS_MODEL', (node, field.value))
|
||||||
|
break
|
||||||
|
|
||||||
del self.awaiting_answers[id]
|
del self.awaiting_answers[id]
|
||||||
|
|
||||||
|
@ -1251,7 +1280,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
||||||
reply.setType('error')
|
reply.setType('error')
|
||||||
|
|
||||||
reply.addChild(feature)
|
reply.addChild(feature)
|
||||||
reply.addChild(node=xmpp.ErrorNode('service-unavailable', typ='cancel'))
|
reply.addChild(node=common.xmpp.ErrorNode('service-unavailable', typ='cancel'))
|
||||||
|
|
||||||
con.send(reply)
|
con.send(reply)
|
||||||
|
|
||||||
|
@ -1419,7 +1448,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
||||||
iq_obj = iq_obj.buildReply('result')
|
iq_obj = iq_obj.buildReply('result')
|
||||||
qp = iq_obj.getTag('query')
|
qp = iq_obj.getTag('query')
|
||||||
qp.setTagData('utc', strftime('%Y%m%dT%T', gmtime()))
|
qp.setTagData('utc', strftime('%Y%m%dT%T', gmtime()))
|
||||||
qp.setTagData('tz', tzname[daylight])
|
qp.setTagData('tz', helpers.decode_string(tzname[daylight]))
|
||||||
qp.setTagData('display', helpers.decode_string(strftime('%c',
|
qp.setTagData('display', helpers.decode_string(strftime('%c',
|
||||||
localtime())))
|
localtime())))
|
||||||
self.connection.send(iq_obj)
|
self.connection.send(iq_obj)
|
||||||
|
@ -1599,7 +1628,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
||||||
if not user_nick:
|
if not user_nick:
|
||||||
user_nick = ''
|
user_nick = ''
|
||||||
|
|
||||||
if encTag and GnuPG.USE_GPG:
|
if encTag and self.USE_GPG:
|
||||||
#decrypt
|
#decrypt
|
||||||
encmsg = encTag.getData()
|
encmsg = encTag.getData()
|
||||||
|
|
||||||
|
@ -1770,8 +1799,22 @@ returns the session that we last sent a message to.'''
|
||||||
''' Called when we receive <message/> with pubsub event. '''
|
''' Called when we receive <message/> with pubsub event. '''
|
||||||
# TODO: Logging? (actually services where logging would be useful, should
|
# TODO: Logging? (actually services where logging would be useful, should
|
||||||
# TODO: allow to access archives remotely...)
|
# TODO: allow to access archives remotely...)
|
||||||
|
jid = helpers.get_full_jid_from_iq(msg)
|
||||||
event = msg.getTag('event')
|
event = msg.getTag('event')
|
||||||
|
|
||||||
|
# XEP-0107: User Mood
|
||||||
|
items = event.getTag('items', {'node': common.xmpp.NS_MOOD})
|
||||||
|
if items: pep.user_mood(items, self.name, jid)
|
||||||
|
# XEP-0118: User Tune
|
||||||
|
items = event.getTag('items', {'node': common.xmpp.NS_TUNE})
|
||||||
|
if items: pep.user_tune(items, self.name, jid)
|
||||||
|
# XEP-0080: User Geolocation
|
||||||
|
items = event.getTag('items', {'node': common.xmpp.NS_GEOLOC})
|
||||||
|
if items: pep.user_geoloc(items, self.name, jid)
|
||||||
|
# XEP-0108: User Activity
|
||||||
|
items = event.getTag('items', {'node': common.xmpp.NS_ACTIVITY})
|
||||||
|
if items: pep.user_activity(items, self.name, jid)
|
||||||
|
|
||||||
items = event.getTag('items')
|
items = event.getTag('items')
|
||||||
if items is None: return
|
if items is None: return
|
||||||
|
|
||||||
|
@ -1857,7 +1900,7 @@ returns the session that we last sent a message to.'''
|
||||||
except:
|
except:
|
||||||
prio = 0
|
prio = 0
|
||||||
keyID = ''
|
keyID = ''
|
||||||
if sigTag and self.gpg:
|
if sigTag and self.USE_GPG:
|
||||||
# verify
|
# verify
|
||||||
sigmsg = sigTag.getData()
|
sigmsg = sigTag.getData()
|
||||||
keyID = self.gpg.verify(status, sigmsg)
|
keyID = self.gpg.verify(status, sigmsg)
|
||||||
|
@ -2109,6 +2152,21 @@ returns the session that we last sent a message to.'''
|
||||||
raw_roster = roster.getRaw()
|
raw_roster = roster.getRaw()
|
||||||
roster = {}
|
roster = {}
|
||||||
our_jid = helpers.parse_jid(gajim.get_jid_from_account(self.name))
|
our_jid = helpers.parse_jid(gajim.get_jid_from_account(self.name))
|
||||||
|
if self.connected > 1 and self.continue_connect_info:
|
||||||
|
msg = self.continue_connect_info[1]
|
||||||
|
sign_msg = self.continue_connect_info[2]
|
||||||
|
signed = ''
|
||||||
|
send_first_presence = True
|
||||||
|
if sign_msg:
|
||||||
|
signed = self.get_signed_presence(msg, self._send_first_presence)
|
||||||
|
if signed is None:
|
||||||
|
self.dispatch('GPG_PASSWORD_REQUIRED',
|
||||||
|
(self._send_first_presence,))
|
||||||
|
# _send_first_presence will be called when user enter passphrase
|
||||||
|
send_first_presence = False
|
||||||
|
if send_first_presence:
|
||||||
|
self._send_first_presence(signed)
|
||||||
|
|
||||||
for jid in raw_roster:
|
for jid in raw_roster:
|
||||||
try:
|
try:
|
||||||
j = helpers.parse_jid(jid)
|
j = helpers.parse_jid(jid)
|
||||||
|
@ -2131,20 +2189,6 @@ returns the session that we last sent a message to.'''
|
||||||
|
|
||||||
self.dispatch('ROSTER', roster)
|
self.dispatch('ROSTER', roster)
|
||||||
|
|
||||||
# continue connection
|
|
||||||
if self.connected > 1 and self.continue_connect_info:
|
|
||||||
msg = self.continue_connect_info[1]
|
|
||||||
sign_msg = self.continue_connect_info[2]
|
|
||||||
signed = ''
|
|
||||||
if sign_msg:
|
|
||||||
signed = self.get_signed_presence(msg, self._send_first_presence)
|
|
||||||
if signed is None:
|
|
||||||
self.dispatch('GPG_PASSWORD_REQUIRED',
|
|
||||||
(self._send_first_presence,))
|
|
||||||
# _send_first_presence will be called when user enter passphrase
|
|
||||||
return
|
|
||||||
self._send_first_presence(signed)
|
|
||||||
|
|
||||||
def _send_first_presence(self, signed = ''):
|
def _send_first_presence(self, signed = ''):
|
||||||
show = self.continue_connect_info[0]
|
show = self.continue_connect_info[0]
|
||||||
msg = self.continue_connect_info[1]
|
msg = self.continue_connect_info[1]
|
||||||
|
@ -2155,6 +2199,7 @@ returns the session that we last sent a message to.'''
|
||||||
self.dispatch('ERROR', (_('OpenPGP passphrase was not given'),
|
self.dispatch('ERROR', (_('OpenPGP passphrase was not given'),
|
||||||
#%s is the account name here
|
#%s is the account name here
|
||||||
_('You will be connected to %s without OpenPGP.') % self.name))
|
_('You will be connected to %s without OpenPGP.') % self.name))
|
||||||
|
self.USE_GPG = False
|
||||||
signed = ''
|
signed = ''
|
||||||
self.connected = STATUS_LIST.index(show)
|
self.connected = STATUS_LIST.index(show)
|
||||||
sshow = helpers.get_xmpp_show(show)
|
sshow = helpers.get_xmpp_show(show)
|
||||||
|
|
|
@ -27,7 +27,8 @@ class Contact:
|
||||||
'''Information concerning each contact'''
|
'''Information concerning each contact'''
|
||||||
def __init__(self, jid='', name='', groups=[], show='', status='', sub='',
|
def __init__(self, jid='', name='', groups=[], show='', status='', sub='',
|
||||||
ask='', resource='', priority=0, keyID='', our_chatstate=None,
|
ask='', resource='', priority=0, keyID='', our_chatstate=None,
|
||||||
chatstate=None, last_status_time=None, msg_id = None, composing_xep = None):
|
chatstate=None, last_status_time=None, msg_id = None, composing_xep = None,
|
||||||
|
mood={}, tune={}, activity={}):
|
||||||
self.jid = jid
|
self.jid = jid
|
||||||
self.name = name
|
self.name = name
|
||||||
self.contact_name = '' # nick choosen by contact
|
self.contact_name = '' # nick choosen by contact
|
||||||
|
@ -63,6 +64,10 @@ class Contact:
|
||||||
self.chatstate = chatstate
|
self.chatstate = chatstate
|
||||||
self.last_status_time = last_status_time
|
self.last_status_time = last_status_time
|
||||||
|
|
||||||
|
self.mood = mood.copy()
|
||||||
|
self.tune = tune.copy()
|
||||||
|
self.activity = activity.copy()
|
||||||
|
|
||||||
def get_full_jid(self):
|
def get_full_jid(self):
|
||||||
if self.resource:
|
if self.resource:
|
||||||
return self.jid + '/' + self.resource
|
return self.jid + '/' + self.resource
|
||||||
|
@ -162,15 +167,16 @@ class Contacts:
|
||||||
|
|
||||||
def create_contact(self, jid='', name='', groups=[], show='', status='',
|
def create_contact(self, jid='', name='', groups=[], show='', status='',
|
||||||
sub='', ask='', resource='', priority=0, keyID='', our_chatstate=None,
|
sub='', ask='', resource='', priority=0, keyID='', our_chatstate=None,
|
||||||
chatstate=None, last_status_time=None, composing_xep=None):
|
chatstate=None, last_status_time=None, composing_xep=None,
|
||||||
|
mood={}, tune={}, activity={}):
|
||||||
return Contact(jid, name, groups, show, status, sub, ask, resource,
|
return Contact(jid, name, groups, show, status, sub, ask, resource,
|
||||||
priority, keyID, our_chatstate, chatstate, last_status_time,
|
priority, keyID, our_chatstate, chatstate, last_status_time,
|
||||||
composing_xep)
|
None, composing_xep, mood, tune, activity)
|
||||||
|
|
||||||
def copy_contact(self, contact):
|
def copy_contact(self, contact):
|
||||||
return self.create_contact(jid = contact.jid, name = contact.name,
|
return self.create_contact(jid = contact.jid, name = contact.name,
|
||||||
groups = contact.groups, show = contact.show, status = contact.status,
|
groups = contact.groups, show = contact.show, status =
|
||||||
sub = contact.sub, ask = contact.ask, resource = contact.resource,
|
contact.status, sub = contact.sub, ask = contact.ask, resource = contact.resource,
|
||||||
priority = contact.priority, keyID = contact.keyID,
|
priority = contact.priority, keyID = contact.keyID,
|
||||||
our_chatstate = contact.our_chatstate, chatstate = contact.chatstate,
|
our_chatstate = contact.our_chatstate, chatstate = contact.chatstate,
|
||||||
last_status_time = contact.last_status_time)
|
last_status_time = contact.last_status_time)
|
||||||
|
@ -469,6 +475,15 @@ class Contacts:
|
||||||
return 1
|
return 1
|
||||||
if show2 > show1:
|
if show2 > show1:
|
||||||
return -1
|
return -1
|
||||||
|
server1 = common.gajim.get_server_from_jid(jid1)
|
||||||
|
server2 = common.gajim.get_server_from_jid(jid2)
|
||||||
|
myserver1 = common.gajim.config.get_per('accounts', account1, 'hostname')
|
||||||
|
myserver2 = common.gajim.config.get_per('accounts', account2, 'hostname')
|
||||||
|
if server1 == myserver1:
|
||||||
|
if server2 != myserver2:
|
||||||
|
return 1
|
||||||
|
elif server2 == myserver2:
|
||||||
|
return -1
|
||||||
if jid1 > jid2:
|
if jid1 > jid2:
|
||||||
return 1
|
return 1
|
||||||
if jid2 > jid1:
|
if jid2 > jid1:
|
||||||
|
|
|
@ -2,7 +2,7 @@ docdir = '../'
|
||||||
|
|
||||||
datadir = '../'
|
datadir = '../'
|
||||||
|
|
||||||
version = '0.11.4.0-svn'
|
version = '0.11.4.2-svn'
|
||||||
|
|
||||||
import sys, os.path
|
import sys, os.path
|
||||||
for base in ('.', 'common'):
|
for base in ('.', 'common'):
|
||||||
|
|
|
@ -138,9 +138,6 @@ SHOW_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
|
||||||
|
|
||||||
# zeroconf account name
|
# zeroconf account name
|
||||||
ZEROCONF_ACC_NAME = 'Local'
|
ZEROCONF_ACC_NAME = 'Local'
|
||||||
priority_dict = {}
|
|
||||||
for status in ('online', 'chat', 'away', 'xa', 'dnd', 'invisible'):
|
|
||||||
priority_dict[status] = config.get('autopriority' + status)
|
|
||||||
|
|
||||||
HAVE_PYCRYPTO = True
|
HAVE_PYCRYPTO = True
|
||||||
try:
|
try:
|
||||||
|
@ -154,6 +151,17 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAVE_PYSEXY = False
|
HAVE_PYSEXY = False
|
||||||
|
|
||||||
|
HAVE_GPG = True
|
||||||
|
try:
|
||||||
|
import GnuPGInterface
|
||||||
|
except ImportError:
|
||||||
|
HAVE_GPG = False
|
||||||
|
else:
|
||||||
|
import os
|
||||||
|
status = os.system('gpg -h >/dev/null 2>&1')
|
||||||
|
if status != 0:
|
||||||
|
HAVE_GPG = False
|
||||||
|
|
||||||
def get_nick_from_jid(jid):
|
def get_nick_from_jid(jid):
|
||||||
pos = jid.find('@')
|
pos = jid.find('@')
|
||||||
return jid[:pos]
|
return jid[:pos]
|
||||||
|
@ -260,13 +268,14 @@ def account_is_disconnected(account):
|
||||||
def get_number_of_securely_connected_accounts():
|
def get_number_of_securely_connected_accounts():
|
||||||
'''returns the number of the accounts that are SSL/TLS connected'''
|
'''returns the number of the accounts that are SSL/TLS connected'''
|
||||||
num_of_secured = 0
|
num_of_secured = 0
|
||||||
for account in connections:
|
for account in connections.keys():
|
||||||
if account_is_securely_connected(account):
|
if account_is_securely_connected(account):
|
||||||
num_of_secured += 1
|
num_of_secured += 1
|
||||||
return num_of_secured
|
return num_of_secured
|
||||||
|
|
||||||
def account_is_securely_connected(account):
|
def account_is_securely_connected(account):
|
||||||
if account in con_types and con_types[account] in ('tls', 'ssl'):
|
if account_is_connected(account) and \
|
||||||
|
account in con_types and con_types[account] in ('tls', 'ssl'):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -429,8 +429,8 @@ def launch_browser_mailer(kind, uri):
|
||||||
command = 'kfmclient exec'
|
command = 'kfmclient exec'
|
||||||
elif gajim.config.get('openwith') == 'exo-open':
|
elif gajim.config.get('openwith') == 'exo-open':
|
||||||
command = 'exo-open'
|
command = 'exo-open'
|
||||||
elif ((sys.platform == 'darwin') and
|
elif ((sys.platform == 'darwin') and\
|
||||||
(gajim.config.get('openwith') == 'open')):
|
(gajim.config.get('openwith') == 'open')):
|
||||||
command = 'open'
|
command = 'open'
|
||||||
elif gajim.config.get('openwith') == 'custom':
|
elif gajim.config.get('openwith') == 'custom':
|
||||||
if kind == 'url':
|
if kind == 'url':
|
||||||
|
@ -459,8 +459,8 @@ def launch_file_manager(path_to_open):
|
||||||
command = 'kfmclient exec'
|
command = 'kfmclient exec'
|
||||||
elif gajim.config.get('openwith') == 'exo-open':
|
elif gajim.config.get('openwith') == 'exo-open':
|
||||||
command = 'exo-open'
|
command = 'exo-open'
|
||||||
elif ((sys.platform == 'darwin') and
|
elif ((sys.platform == 'darwin') and\
|
||||||
(gajim.config.get('openwith') == 'open')):
|
(gajim.config.get('openwith') == 'open')):
|
||||||
command = 'open'
|
command = 'open'
|
||||||
elif gajim.config.get('openwith') == 'custom':
|
elif gajim.config.get('openwith') == 'custom':
|
||||||
command = gajim.config.get('custom_file_manager')
|
command = gajim.config.get('custom_file_manager')
|
||||||
|
@ -784,7 +784,8 @@ def get_os_info():
|
||||||
'sourcemage') or not\
|
'sourcemage') or not\
|
||||||
os.path.basename(path_to_file).startswith('slackware'):
|
os.path.basename(path_to_file).startswith('slackware'):
|
||||||
text = distro_name + ' ' + text
|
text = distro_name + ' ' + text
|
||||||
elif path_to_file.endswith('aurox-release'):
|
elif path_to_file.endswith('aurox-release') or \
|
||||||
|
path_to_file.endswith('arch-release'):
|
||||||
# file doesn't have version
|
# file doesn't have version
|
||||||
text = distro_name
|
text = distro_name
|
||||||
elif path_to_file.endswith('lfs-release'): # file just has version
|
elif path_to_file.endswith('lfs-release'): # file just has version
|
||||||
|
@ -792,7 +793,7 @@ def get_os_info():
|
||||||
return text
|
return text
|
||||||
|
|
||||||
# our last chance, ask uname and strip it
|
# our last chance, ask uname and strip it
|
||||||
uname_output = get_output_of_command('uname -a | cut -d" " -f1,3')
|
uname_output = get_output_of_command('uname -sr')
|
||||||
if uname_output is not None:
|
if uname_output is not None:
|
||||||
return uname_output[0] # only first line
|
return uname_output[0] # only first line
|
||||||
return 'N/A'
|
return 'N/A'
|
||||||
|
@ -1092,3 +1093,38 @@ def get_transport_path(transport):
|
||||||
elif os.path.isdir(os.path.join(gajim.MY_ICONSETS_PATH, 'transports',
|
elif os.path.isdir(os.path.join(gajim.MY_ICONSETS_PATH, 'transports',
|
||||||
transport)):
|
transport)):
|
||||||
return os.path.join(gajim.MY_ICONSETS_PATH, 'transports', transport)
|
return os.path.join(gajim.MY_ICONSETS_PATH, 'transports', transport)
|
||||||
|
# No transport folder found, use default jabber one
|
||||||
|
return get_iconset_path(gajim.config.get('iconset'))
|
||||||
|
|
||||||
|
def prepare_and_validate_gpg_keyID(account, jid, keyID):
|
||||||
|
'''Returns an eight char long keyID that can be used with for GPG encryption with this contact.
|
||||||
|
If the given keyID is None, return UNKNOWN; if the key does not match the assigned key
|
||||||
|
XXXXXXXXMISMATCH is returned. If the key is trusted and not yet assigned, assign it'''
|
||||||
|
if gajim.connections[account].USE_GPG:
|
||||||
|
if keyID and len(keyID) == 16:
|
||||||
|
keyID = keyID[8:]
|
||||||
|
|
||||||
|
attached_keys = gajim.config.get_per('accounts', account,
|
||||||
|
'attached_gpg_keys').split()
|
||||||
|
|
||||||
|
if jid in attached_keys and keyID:
|
||||||
|
attachedkeyID = attached_keys[attached_keys.index(jid) + 1]
|
||||||
|
if attachedkeyID != keyID:
|
||||||
|
# Mismatch! Another gpg key was expected
|
||||||
|
keyID += 'MISMATCH'
|
||||||
|
elif jid in attached_keys:
|
||||||
|
# An unsigned presence, just use the assigned key
|
||||||
|
keyID = attached_keys[attached_keys.index(jid) + 1]
|
||||||
|
elif keyID:
|
||||||
|
public_keys = gajim.connections[account].ask_gpg_keys()
|
||||||
|
# Assign the corresponding key, if we have it in our keyring
|
||||||
|
if public_keys.has_key(keyID):
|
||||||
|
for u in gajim.contacts.get_contacts(account, jid):
|
||||||
|
u.keyID = keyID
|
||||||
|
keys_str = gajim.config.get_per('accounts', account, 'attached_gpg_keys')
|
||||||
|
keys_str += jid + ' ' + keyID + ' '
|
||||||
|
gajim.config.set_per('accounts', account, 'attached_gpg_keys', keys_str)
|
||||||
|
elif keyID is None:
|
||||||
|
keyID = 'UNKNOWN'
|
||||||
|
return keyID
|
||||||
|
|
||||||
|
|
|
@ -174,8 +174,10 @@ class OptionsParser:
|
||||||
self.update_config_to_01115()
|
self.update_config_to_01115()
|
||||||
if old < [0, 11, 2, 1] and new >= [0, 11, 2, 1]:
|
if old < [0, 11, 2, 1] and new >= [0, 11, 2, 1]:
|
||||||
self.update_config_to_01121()
|
self.update_config_to_01121()
|
||||||
if old < [0, 11, 2, 2] and new >= [0, 11, 2, 2]:
|
if old < [0, 11, 4, 1] and new >= [0, 11, 4, 1]:
|
||||||
self.update_config_to_01122()
|
self.update_config_to_01141()
|
||||||
|
if old < [0, 11, 4, 2] and new >= [0, 11, 4, 2]:
|
||||||
|
self.update_config_to_01142()
|
||||||
|
|
||||||
gajim.logger.init_vars()
|
gajim.logger.init_vars()
|
||||||
gajim.config.set('version', new_version)
|
gajim.config.set('version', new_version)
|
||||||
|
@ -503,7 +505,7 @@ class OptionsParser:
|
||||||
|
|
||||||
gajim.config.set('version', '0.11.2.1')
|
gajim.config.set('version', '0.11.2.1')
|
||||||
|
|
||||||
def update_config_to_01122(self):
|
def update_config_to_01141(self):
|
||||||
back = os.getcwd()
|
back = os.getcwd()
|
||||||
os.chdir(logger.LOG_DB_FOLDER)
|
os.chdir(logger.LOG_DB_FOLDER)
|
||||||
con = sqlite.connect(logger.LOG_DB_FILE)
|
con = sqlite.connect(logger.LOG_DB_FILE)
|
||||||
|
@ -524,5 +526,20 @@ class OptionsParser:
|
||||||
except sqlite.OperationalError, e:
|
except sqlite.OperationalError, e:
|
||||||
pass
|
pass
|
||||||
con.close()
|
con.close()
|
||||||
gajim.config.set('version', '0.11.2.2')
|
gajim.config.set('version', '0.11.4.1')
|
||||||
|
|
||||||
|
def update_config_to_01142(self):
|
||||||
|
'''next_message_received sound event is splittedin 2 events'''
|
||||||
|
gajim.config.add_per('soundevents', 'next_message_received_focused')
|
||||||
|
gajim.config.add_per('soundevents', 'next_message_received_unfocused')
|
||||||
|
if gajim.config.get_per('soundevents', 'next_message_received'):
|
||||||
|
enabled = gajim.config.get_per('soundevents', 'next_message_received',
|
||||||
|
'enabled')
|
||||||
|
path = gajim.config.get_per('soundevents', 'next_message_received',
|
||||||
|
'path')
|
||||||
|
gajim.config.del_per('soundevents', 'next_message_received')
|
||||||
|
gajim.config.set_per('soundevents', 'next_message_received_focused',
|
||||||
|
'enabled', enabled)
|
||||||
|
gajim.config.set_per('soundevents', 'next_message_received_focused',
|
||||||
|
'path', path)
|
||||||
|
gajim.config.set('version', '0.11.1.2')
|
||||||
|
|
220
src/common/pep.py
Normal file
220
src/common/pep.py
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
from common import gajim, xmpp
|
||||||
|
|
||||||
|
def user_mood(items, name, jid):
|
||||||
|
has_child = False
|
||||||
|
mood = None
|
||||||
|
text = None
|
||||||
|
for item in items.getTags('item'):
|
||||||
|
child = item.getTag('mood')
|
||||||
|
if child is not None:
|
||||||
|
has_child = True
|
||||||
|
for ch in child.getChildren():
|
||||||
|
if ch.getName() != 'text':
|
||||||
|
mood = ch.getName()
|
||||||
|
else:
|
||||||
|
text = ch.getData()
|
||||||
|
if jid == gajim.get_jid_from_account(name):
|
||||||
|
acc = gajim.connections[name]
|
||||||
|
if has_child:
|
||||||
|
if acc.mood.has_key('mood'):
|
||||||
|
del acc.mood['mood']
|
||||||
|
if acc.mood.has_key('text'):
|
||||||
|
del acc.mood['text']
|
||||||
|
if mood != None:
|
||||||
|
acc.mood['mood'] = mood
|
||||||
|
if text != None:
|
||||||
|
acc.mood['text'] = text
|
||||||
|
|
||||||
|
(user, resource) = gajim.get_room_and_nick_from_fjid(jid)
|
||||||
|
contact = gajim.contacts.get_contact(name, user, resource=resource)
|
||||||
|
if not contact:
|
||||||
|
return
|
||||||
|
if has_child:
|
||||||
|
if contact.mood.has_key('mood'):
|
||||||
|
del contact.mood['mood']
|
||||||
|
if contact.mood.has_key('text'):
|
||||||
|
del contact.mood['text']
|
||||||
|
if mood != None:
|
||||||
|
contact.mood['mood'] = mood
|
||||||
|
if text != None:
|
||||||
|
contact.mood['text'] = text
|
||||||
|
|
||||||
|
def user_tune(items, name, jid):
|
||||||
|
has_child = False
|
||||||
|
artist = None
|
||||||
|
title = None
|
||||||
|
source = None
|
||||||
|
track = None
|
||||||
|
length = None
|
||||||
|
|
||||||
|
for item in items.getTags('item'):
|
||||||
|
child = item.getTag('tune')
|
||||||
|
if child is not None:
|
||||||
|
has_child = True
|
||||||
|
for ch in child.getChildren():
|
||||||
|
if ch.getName() == 'artist':
|
||||||
|
artist = ch.getData()
|
||||||
|
elif ch.getName() == 'title':
|
||||||
|
title = ch.getData()
|
||||||
|
elif ch.getName() == 'source':
|
||||||
|
source = ch.getData()
|
||||||
|
elif ch.getName() == 'track':
|
||||||
|
track = ch.getData()
|
||||||
|
elif ch.getName() == 'length':
|
||||||
|
length = ch.getData()
|
||||||
|
|
||||||
|
if jid == gajim.get_jid_from_account(name):
|
||||||
|
acc = gajim.connections[name]
|
||||||
|
if has_child:
|
||||||
|
if acc.tune.has_key('artist'):
|
||||||
|
del acc.tune['artist']
|
||||||
|
if acc.tune.has_key('title'):
|
||||||
|
del acc.tune['title']
|
||||||
|
if acc.tune.has_key('source'):
|
||||||
|
del acc.tune['source']
|
||||||
|
if acc.tune.has_key('track'):
|
||||||
|
del acc.tune['track']
|
||||||
|
if acc.tune.has_key('length'):
|
||||||
|
del acc.tune['length']
|
||||||
|
if artist != None:
|
||||||
|
acc.tune['artist'] = artist
|
||||||
|
if title != None:
|
||||||
|
acc.tune['title'] = title
|
||||||
|
if source != None:
|
||||||
|
acc.tune['source'] = source
|
||||||
|
if track != None:
|
||||||
|
acc.tune['track'] = track
|
||||||
|
if length != None:
|
||||||
|
acc.tune['length'] = length
|
||||||
|
|
||||||
|
(user, resource) = gajim.get_room_and_nick_from_fjid(jid)
|
||||||
|
contact = gajim.contacts.get_contact(name, user, resource=resource)
|
||||||
|
if not contact:
|
||||||
|
return
|
||||||
|
if has_child:
|
||||||
|
if contact.tune.has_key('artist'):
|
||||||
|
del contact.tune['artist']
|
||||||
|
if contact.tune.has_key('title'):
|
||||||
|
del contact.tune['title']
|
||||||
|
if contact.tune.has_key('source'):
|
||||||
|
del contact.tune['source']
|
||||||
|
if contact.tune.has_key('track'):
|
||||||
|
del contact.tune['track']
|
||||||
|
if contact.tune.has_key('length'):
|
||||||
|
del contact.tune['length']
|
||||||
|
if artist != None:
|
||||||
|
contact.tune['artist'] = artist
|
||||||
|
if title != None:
|
||||||
|
contact.tune['title'] = title
|
||||||
|
if source != None:
|
||||||
|
contact.tune['source'] = source
|
||||||
|
if track != None:
|
||||||
|
contact.tune['track'] = track
|
||||||
|
if length != None:
|
||||||
|
contact.tune['length'] = length
|
||||||
|
|
||||||
|
def user_geoloc(items, name, jid):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def user_activity(items, name, jid):
|
||||||
|
has_child = False
|
||||||
|
activity = None
|
||||||
|
subactivity = None
|
||||||
|
text = None
|
||||||
|
|
||||||
|
for item in items.getTags('item'):
|
||||||
|
child = item.getTag('activity')
|
||||||
|
if child is not None:
|
||||||
|
has_child = True
|
||||||
|
for ch in child.getChildren():
|
||||||
|
if ch.getName() != 'text':
|
||||||
|
activity = ch.getName()
|
||||||
|
for chi in ch.getChildren():
|
||||||
|
subactivity = chi.getName()
|
||||||
|
else:
|
||||||
|
text = ch.getData()
|
||||||
|
|
||||||
|
if jid == gajim.get_jid_from_account(name):
|
||||||
|
acc = gajim.connections[name]
|
||||||
|
if has_child:
|
||||||
|
if acc.activity.has_key('activity'):
|
||||||
|
del acc.activity['activity']
|
||||||
|
if acc.activity.has_key('subactivity'):
|
||||||
|
del acc.activity['subactivity']
|
||||||
|
if acc.activity.has_key('text'):
|
||||||
|
del acc.activity['text']
|
||||||
|
if activity != None:
|
||||||
|
acc.activity['activity'] = activity
|
||||||
|
if subactivity != None:
|
||||||
|
acc.activity['subactivity'] = subactivity
|
||||||
|
if text != None:
|
||||||
|
acc.activity['text'] = text
|
||||||
|
|
||||||
|
(user, resource) = gajim.get_room_and_nick_from_fjid(jid)
|
||||||
|
contact = gajim.contacts.get_contact(name, user, resource=resource)
|
||||||
|
if not contact:
|
||||||
|
return
|
||||||
|
if has_child:
|
||||||
|
if contact.activity.has_key('activity'):
|
||||||
|
del contact.activity['activity']
|
||||||
|
if contact.activity.has_key('subactivity'):
|
||||||
|
del contact.activity['subactivity']
|
||||||
|
if contact.activity.has_key('text'):
|
||||||
|
del contact.activity['text']
|
||||||
|
if activity != None:
|
||||||
|
contact.activity['activity'] = activity
|
||||||
|
if subactivity != None:
|
||||||
|
contact.activity['subactivity'] = subactivity
|
||||||
|
if text != None:
|
||||||
|
contact.activity['text'] = text
|
||||||
|
|
||||||
|
def user_send_mood(account, mood, message = ''):
|
||||||
|
if gajim.config.get('publish_mood') == False:
|
||||||
|
return
|
||||||
|
item = xmpp.Node('mood', {'xmlns': xmpp.NS_MOOD})
|
||||||
|
if mood != '':
|
||||||
|
item.addChild(mood)
|
||||||
|
if message != '':
|
||||||
|
i = item.addChild('text')
|
||||||
|
i.addData(message)
|
||||||
|
|
||||||
|
gajim.connections[account].send_pb_publish('', xmpp.NS_MOOD, item, '0')
|
||||||
|
|
||||||
|
def user_send_activity(account, activity, subactivity = '', message = ''):
|
||||||
|
if gajim.config.get('publish_activity') == False:
|
||||||
|
return
|
||||||
|
item = xmpp.Node('activity', {'xmlns': xmpp.NS_ACTIVITY})
|
||||||
|
if activity != '':
|
||||||
|
i = item.addChild(activity)
|
||||||
|
if subactivity != '':
|
||||||
|
i.addChild(subactivity)
|
||||||
|
if message != '':
|
||||||
|
i = item.addChild('text')
|
||||||
|
i.addData(message)
|
||||||
|
|
||||||
|
gajim.connections[account].send_pb_publish('', xmpp.NS_ACTIVITY, item, '0')
|
||||||
|
|
||||||
|
def user_send_tune(account, artist = '', title = '', source = '', track = 0,length = 0, items = None):
|
||||||
|
if (gajim.config.get('publish_tune') == False) or \
|
||||||
|
(gajim.connections[account].pep_supported == False):
|
||||||
|
return
|
||||||
|
item = xmpp.Node('tune', {'xmlns': xmpp.NS_TUNE})
|
||||||
|
if artist != '':
|
||||||
|
i = item.addChild('artist')
|
||||||
|
i.addData(artist)
|
||||||
|
if title != '':
|
||||||
|
i = item.addChild('title')
|
||||||
|
i.addData(title)
|
||||||
|
if source != '':
|
||||||
|
i = item.addChild('source')
|
||||||
|
i.addData(source)
|
||||||
|
if track != 0:
|
||||||
|
i = item.addChild('track')
|
||||||
|
i.addData(track)
|
||||||
|
if length != 0:
|
||||||
|
i = item.addChild('length')
|
||||||
|
i.addData(length)
|
||||||
|
if items is not None:
|
||||||
|
item.addChild(payload=items)
|
||||||
|
|
||||||
|
gajim.connections[account].send_pb_publish('', xmpp.NS_TUNE, item, '0')
|
|
@ -1,5 +1,6 @@
|
||||||
import xmpp
|
import xmpp
|
||||||
import gajim
|
import gajim
|
||||||
|
import connection_handlers
|
||||||
|
|
||||||
class ConnectionPubSub:
|
class ConnectionPubSub:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -43,9 +44,61 @@ class ConnectionPubSub:
|
||||||
|
|
||||||
self.connection.send(query)
|
self.connection.send(query)
|
||||||
|
|
||||||
|
def send_pb_delete(self, jid, node):
|
||||||
|
'''Deletes node.'''
|
||||||
|
query = xmpp.Iq('set', to=jid)
|
||||||
|
d = query.addChild('pubsub', namespace=xmpp.NS_PUBSUB)
|
||||||
|
d = d.addChild('delete', {'node': node})
|
||||||
|
|
||||||
|
self.connection.send(query)
|
||||||
|
|
||||||
|
def send_pb_create(self, jid, node, configure = False, configure_form = None):
|
||||||
|
'''Creates new node.'''
|
||||||
|
query = xmpp.Iq('set', to=jid)
|
||||||
|
c = query.addChild('pubsub', namespace=xmpp.NS_PUBSUB)
|
||||||
|
c = c.addChild('create', {'node': node})
|
||||||
|
if configure:
|
||||||
|
conf = c.addChild('configure')
|
||||||
|
if configure_form is not None:
|
||||||
|
conf.addChild(node=configure_form)
|
||||||
|
|
||||||
|
self.connection.send(query)
|
||||||
|
|
||||||
|
def send_pb_configure(self, jid, node, cb, *cbargs, **cbkwargs):
|
||||||
|
query = xmpp.Iq('set', to=jid)
|
||||||
|
c = query.addChild('pubsub', namespace=xmpp.NS_PUBSUB)
|
||||||
|
c = c.addChild('configure', {'node': node})
|
||||||
|
|
||||||
|
id = self.connection.send(query)
|
||||||
|
|
||||||
|
def on_configure(self, connection, query):
|
||||||
|
try:
|
||||||
|
filledform = cb(stanza['pubsub']['configure']['x'], *cbargs, **cbkwargs)
|
||||||
|
#TODO: Build a form
|
||||||
|
#TODO: Send it
|
||||||
|
|
||||||
|
except CancelConfigure:
|
||||||
|
cancel = xmpp.Iq('set', to=jid)
|
||||||
|
ca = query.addChild('pubsub', namespace=xmpp.NS_PUBSUB)
|
||||||
|
ca = ca.addChild('configure', {'node': node})
|
||||||
|
#ca = ca.addChild('x', namespace=xmpp.NS_DATA, {'type': 'cancel'})
|
||||||
|
|
||||||
|
self.connection.send(cancel)
|
||||||
|
|
||||||
|
self.__callbacks[id] = (on_configure, (), {})
|
||||||
|
|
||||||
def _PubSubCB(self, conn, stanza):
|
def _PubSubCB(self, conn, stanza):
|
||||||
try:
|
try:
|
||||||
cb, args, kwargs = self.__callbacks.pop(stanza.getID())
|
cb, args, kwargs = self.__callbacks.pop(stanza.getID())
|
||||||
cb(conn, stanza, *args, **kwargs)
|
cb(conn, stanza, *args, **kwargs)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def request_pb_configuration(self, jid, node):
|
||||||
|
query = xmpp.Iq('get', to=jid)
|
||||||
|
e = query.addChild('pubsub', namespace=xmpp.NS_PUBSUB_OWNER)
|
||||||
|
e = e.addChild('configure', {'node': node})
|
||||||
|
id = self.connection.getAnID()
|
||||||
|
query.setID(id)
|
||||||
|
self.awaiting_answers[id] = (connection_handlers.PEP_ACCESS_MODEL,)
|
||||||
|
self.connection.send(query)
|
||||||
|
|
|
@ -932,7 +932,7 @@ class Socks5Receiver(Socks5, IdleObject):
|
||||||
elif self.state == 3: # send 'connect' request
|
elif self.state == 3: # send 'connect' request
|
||||||
self.send_raw(self._get_request_buff(self._get_sha1_auth()))
|
self.send_raw(self._get_request_buff(self._get_sha1_auth()))
|
||||||
elif self.file_props['type'] != 'r':
|
elif self.file_props['type'] != 'r':
|
||||||
if self.file_props['paused'] == True:
|
if self.file_props['paused']:
|
||||||
self.idlequeue.plug_idle(self, False, False)
|
self.idlequeue.plug_idle(self, False, False)
|
||||||
return
|
return
|
||||||
result = self.write_next()
|
result = self.write_next()
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from common import gajim
|
from common import gajim
|
||||||
|
|
||||||
from common import xmpp
|
from common import xmpp
|
||||||
from common import helpers
|
|
||||||
from common import exceptions
|
from common import exceptions
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
@ -571,9 +570,9 @@ class EncryptedStanzaSession(StanzaSession):
|
||||||
self.d = crypto.powmod(g, self.y, p)
|
self.d = crypto.powmod(g, self.y, p)
|
||||||
|
|
||||||
to_add = { 'my_nonce': self.n_s,
|
to_add = { 'my_nonce': self.n_s,
|
||||||
'dhkeys': crypto.encode_mpi(self.d),
|
'dhkeys': crypto.encode_mpi(self.d),
|
||||||
'counter': crypto.encode_mpi(self.c_o),
|
'counter': crypto.encode_mpi(self.c_o),
|
||||||
'nonce': self.n_o }
|
'nonce': self.n_o }
|
||||||
|
|
||||||
for name in to_add:
|
for name in to_add:
|
||||||
b64ed = base64.b64encode(to_add[name])
|
b64ed = base64.b64encode(to_add[name])
|
||||||
|
|
|
@ -27,11 +27,14 @@ NS_AGENTS ='jabber:iq:agents'
|
||||||
NS_AMP ='http://jabber.org/protocol/amp'
|
NS_AMP ='http://jabber.org/protocol/amp'
|
||||||
NS_AMP_ERRORS =NS_AMP+'#errors'
|
NS_AMP_ERRORS =NS_AMP+'#errors'
|
||||||
NS_AUTH ='jabber:iq:auth'
|
NS_AUTH ='jabber:iq:auth'
|
||||||
|
NS_AVATAR ='http://www.xmpp.org/extensions/xep-0084.html#ns-metadata'
|
||||||
NS_BIND ='urn:ietf:params:xml:ns:xmpp-bind'
|
NS_BIND ='urn:ietf:params:xml:ns:xmpp-bind'
|
||||||
NS_BROWSE ='jabber:iq:browse'
|
NS_BROWSE ='jabber:iq:browse'
|
||||||
NS_BYTESTREAM ='http://jabber.org/protocol/bytestreams' # XEP-0065
|
NS_BROWSING ='http://jabber.org/protocol/browsing' # XEP-0195
|
||||||
NS_CAPS ='http://jabber.org/protocol/caps' # XEP-0115
|
NS_BYTESTREAM ='http://jabber.org/protocol/bytestreams' # JEP-0065
|
||||||
NS_CHATSTATES ='http://jabber.org/protocol/chatstates' # XEP-0085
|
NS_CAPS ='http://jabber.org/protocol/caps' # JEP-0115
|
||||||
|
NS_CHATSTATES ='http://jabber.org/protocol/chatstates' # JEP-0085
|
||||||
|
NS_CHATTING ='http://jabber.org/protocol/chatting' # XEP-0194
|
||||||
NS_CLIENT ='jabber:client'
|
NS_CLIENT ='jabber:client'
|
||||||
NS_COMMANDS ='http://jabber.org/protocol/commands'
|
NS_COMMANDS ='http://jabber.org/protocol/commands'
|
||||||
NS_COMPONENT_ACCEPT='jabber:component:accept'
|
NS_COMPONENT_ACCEPT='jabber:component:accept'
|
||||||
|
@ -48,8 +51,9 @@ NS_ENCRYPTED ='jabber:x:encrypted' # XEP-00
|
||||||
NS_ESESSION_INIT='http://www.xmpp.org/extensions/xep-0116.html#ns-init' # XEP-0116
|
NS_ESESSION_INIT='http://www.xmpp.org/extensions/xep-0116.html#ns-init' # XEP-0116
|
||||||
NS_EVENT ='jabber:x:event' # XEP-0022
|
NS_EVENT ='jabber:x:event' # XEP-0022
|
||||||
NS_FEATURE ='http://jabber.org/protocol/feature-neg'
|
NS_FEATURE ='http://jabber.org/protocol/feature-neg'
|
||||||
NS_FILE ='http://jabber.org/protocol/si/profile/file-transfer' # XEP-0096
|
NS_FILE ='http://jabber.org/protocol/si/profile/file-transfer' # JEP-0096
|
||||||
NS_GEOLOC ='http://jabber.org/protocol/geoloc' # XEP-0080
|
NS_GAMING ='http://jabber.org/protocol/gaming' # XEP-0196
|
||||||
|
NS_GEOLOC ='http://jabber.org/protocol/geoloc' # JEP-0080
|
||||||
NS_GROUPCHAT ='gc-1.0'
|
NS_GROUPCHAT ='gc-1.0'
|
||||||
NS_HTTP_AUTH ='http://jabber.org/protocol/http-auth' # XEP-0070
|
NS_HTTP_AUTH ='http://jabber.org/protocol/http-auth' # XEP-0070
|
||||||
NS_HTTP_BIND ='http://jabber.org/protocol/httpbind' # XEP-0124
|
NS_HTTP_BIND ='http://jabber.org/protocol/httpbind' # XEP-0124
|
||||||
|
@ -72,6 +76,7 @@ NS_PRIVACY ='jabber:iq:privacy'
|
||||||
NS_PRIVATE ='jabber:iq:private'
|
NS_PRIVATE ='jabber:iq:private'
|
||||||
NS_PROFILE ='http://jabber.org/protocol/profile' # XEP-0154
|
NS_PROFILE ='http://jabber.org/protocol/profile' # XEP-0154
|
||||||
NS_PUBSUB ='http://jabber.org/protocol/pubsub' # XEP-0060
|
NS_PUBSUB ='http://jabber.org/protocol/pubsub' # XEP-0060
|
||||||
|
NS_PUBSUB_OWNER ='http://jabber.org/protocol/pubsub#owner' # JEP-0060
|
||||||
NS_REGISTER ='jabber:iq:register'
|
NS_REGISTER ='jabber:iq:register'
|
||||||
NS_ROSTER ='jabber:iq:roster'
|
NS_ROSTER ='jabber:iq:roster'
|
||||||
NS_ROSTERX ='http://jabber.org/protocol/rosterx' # XEP-0144
|
NS_ROSTERX ='http://jabber.org/protocol/rosterx' # XEP-0144
|
||||||
|
@ -90,12 +95,14 @@ NS_STREAMS ='http://etherx.jabber.org/streams'
|
||||||
NS_TIME ='jabber:iq:time' # XEP-0900
|
NS_TIME ='jabber:iq:time' # XEP-0900
|
||||||
NS_TIME_REVISED ='urn:xmpp:time' # XEP-0202
|
NS_TIME_REVISED ='urn:xmpp:time' # XEP-0202
|
||||||
NS_TLS ='urn:ietf:params:xml:ns:xmpp-tls'
|
NS_TLS ='urn:ietf:params:xml:ns:xmpp-tls'
|
||||||
|
NS_TUNE ='http://jabber.org/protocol/tune' # XEP-0118
|
||||||
NS_VACATION ='http://jabber.org/protocol/vacation'
|
NS_VACATION ='http://jabber.org/protocol/vacation'
|
||||||
NS_VCARD ='vcard-temp'
|
NS_VCARD ='vcard-temp'
|
||||||
NS_GMAILNOTIFY ='google:mail:notify'
|
NS_GMAILNOTIFY ='google:mail:notify'
|
||||||
NS_GTALKSETTING ='google:setting'
|
NS_GTALKSETTING ='google:setting'
|
||||||
NS_VCARD_UPDATE =NS_VCARD+':x:update'
|
NS_VCARD_UPDATE =NS_VCARD+':x:update'
|
||||||
NS_VERSION ='jabber:iq:version'
|
NS_VERSION ='jabber:iq:version'
|
||||||
|
NS_VIEWING ='http://jabber.org/protocol/viewing' # XEP--197
|
||||||
NS_PING ='urn:xmpp:ping' # XEP-0199
|
NS_PING ='urn:xmpp:ping' # XEP-0199
|
||||||
NS_WAITINGLIST ='http://jabber.org/protocol/waitinglist' # XEP-0130
|
NS_WAITINGLIST ='http://jabber.org/protocol/waitinglist' # XEP-0130
|
||||||
NS_XHTML_IM ='http://jabber.org/protocol/xhtml-im' # XEP-0071
|
NS_XHTML_IM ='http://jabber.org/protocol/xhtml-im' # XEP-0071
|
||||||
|
|
|
@ -87,7 +87,11 @@ class Roster(PlugIn):
|
||||||
def PresenceHandler(self,dis,pres):
|
def PresenceHandler(self,dis,pres):
|
||||||
""" Presence tracker. Used internally for setting items' resources state in
|
""" Presence tracker. Used internally for setting items' resources state in
|
||||||
internal roster representation. """
|
internal roster representation. """
|
||||||
jid=JID(pres.getFrom())
|
jid=pres.getFrom()
|
||||||
|
if not jid:
|
||||||
|
# If no from attribue, it's from server
|
||||||
|
jid=self._owner.Server
|
||||||
|
jid=JID(jid)
|
||||||
if not self._data.has_key(jid.getStripped()): self._data[jid.getStripped()]={'name':None,'ask':None,'subscription':'none','groups':['Not in roster'],'resources':{}}
|
if not self._data.has_key(jid.getStripped()): self._data[jid.getStripped()]={'name':None,'ask':None,'subscription':'none','groups':['Not in roster'],'resources':{}}
|
||||||
if type(self._data[jid.getStripped()]['resources'])!=type(dict()):
|
if type(self._data[jid.getStripped()]['resources'])!=type(dict()):
|
||||||
self._data[jid.getStripped()]['resources']={}
|
self._data[jid.getStripped()]['resources']={}
|
||||||
|
|
|
@ -761,15 +761,18 @@ class NonBlockingTLS(PlugIn):
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if 'BEGIN CERTIFICATE' in line:
|
if 'BEGIN CERTIFICATE' in line:
|
||||||
begin = i
|
begin = i
|
||||||
continue
|
|
||||||
elif 'END CERTIFICATE' in line and begin > -1:
|
elif 'END CERTIFICATE' in line and begin > -1:
|
||||||
cert = ''.join(lines[begin:i+2])
|
cert = ''.join(lines[begin:i+2])
|
||||||
try:
|
try:
|
||||||
X509cert = OpenSSL.crypto.load_certificate(
|
X509cert = OpenSSL.crypto.load_certificate(
|
||||||
OpenSSL.crypto.FILETYPE_PEM, cert)
|
OpenSSL.crypto.FILETYPE_PEM, cert)
|
||||||
store.add_cert(X509cert)
|
store.add_cert(X509cert)
|
||||||
|
except OpenSSL.crypto.Error, exception_obj:
|
||||||
|
log.warning('Unable to load a certificate from file %s: %s' %\
|
||||||
|
(gajim.MY_CACERTS, exception_obj.args[0][0][2]))
|
||||||
except:
|
except:
|
||||||
log.warning('Unable to load a certificate from file %s' % \
|
log.warning(
|
||||||
|
'Unknown error while loading certificate from file %s' % \
|
||||||
gajim.MY_CACERTS)
|
gajim.MY_CACERTS)
|
||||||
begin = -1
|
begin = -1
|
||||||
i += 1
|
i += 1
|
||||||
|
@ -787,7 +790,8 @@ class NonBlockingTLS(PlugIn):
|
||||||
try:
|
try:
|
||||||
self.starttls='in progress'
|
self.starttls='in progress'
|
||||||
tcpsock._sslObj.do_handshake()
|
tcpsock._sslObj.do_handshake()
|
||||||
except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError), e:
|
# Errors are handeled in _do_receive function
|
||||||
|
except:
|
||||||
pass
|
pass
|
||||||
tcpsock._sslObj.setblocking(False)
|
tcpsock._sslObj.setblocking(False)
|
||||||
log.debug("Synchronous handshake completed")
|
log.debug("Synchronous handshake completed")
|
||||||
|
@ -1027,7 +1031,7 @@ class NBSOCKS5PROXYsocket(NonBlockingTcp):
|
||||||
# use the IPv4 address request even if remote resolving was specified.
|
# use the IPv4 address request even if remote resolving was specified.
|
||||||
try:
|
try:
|
||||||
self.ipaddr = socket.inet_aton(self.server[0])
|
self.ipaddr = socket.inet_aton(self.server[0])
|
||||||
req = req + "\x01" + ipaddr
|
req = req + "\x01" + self.ipaddr
|
||||||
except socket.error:
|
except socket.error:
|
||||||
# Well it's not an IP number, so it's probably a DNS name.
|
# Well it's not an IP number, so it's probably a DNS name.
|
||||||
# if self.__proxy[3]==True:
|
# if self.__proxy[3]==True:
|
||||||
|
|
|
@ -32,7 +32,6 @@ from calendar import timegm
|
||||||
from common import socks5
|
from common import socks5
|
||||||
import common.xmpp
|
import common.xmpp
|
||||||
|
|
||||||
from common import GnuPG
|
|
||||||
from common import helpers
|
from common import helpers
|
||||||
from common import gajim
|
from common import gajim
|
||||||
from common.zeroconf import zeroconf
|
from common.zeroconf import zeroconf
|
||||||
|
@ -726,13 +725,15 @@ class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream):
|
||||||
if not user_nick:
|
if not user_nick:
|
||||||
user_nick = ''
|
user_nick = ''
|
||||||
|
|
||||||
if encTag and GnuPG.USE_GPG:
|
if encTag and self.USE_GPG:
|
||||||
#decrypt
|
#decrypt
|
||||||
encmsg = encTag.getData()
|
encmsg = encTag.getData()
|
||||||
|
|
||||||
keyID = gajim.config.get_per('accounts', self.name, 'keyid')
|
keyID = gajim.config.get_per('accounts', self.name, 'keyid')
|
||||||
if keyID:
|
if keyID:
|
||||||
decmsg = self.gpg.decrypt(encmsg, keyID)
|
decmsg = self.gpg.decrypt(encmsg, keyID)
|
||||||
|
# \x00 chars are not allowed in C (so in GTK)
|
||||||
|
decmsg = decmsg.replace('\x00', '')
|
||||||
if decmsg:
|
if decmsg:
|
||||||
msgtxt = decmsg
|
msgtxt = decmsg
|
||||||
encrypted = True
|
encrypted = True
|
||||||
|
|
|
@ -49,8 +49,6 @@ from common.zeroconf import client_zeroconf
|
||||||
from common.zeroconf import zeroconf
|
from common.zeroconf import zeroconf
|
||||||
from connection_handlers_zeroconf import *
|
from connection_handlers_zeroconf import *
|
||||||
|
|
||||||
USE_GPG = GnuPG.USE_GPG
|
|
||||||
|
|
||||||
class ConnectionZeroconf(ConnectionHandlersZeroconf):
|
class ConnectionZeroconf(ConnectionHandlersZeroconf):
|
||||||
'''Connection class'''
|
'''Connection class'''
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
|
@ -62,7 +60,9 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
|
||||||
self.connected = 0 # offline
|
self.connected = 0 # offline
|
||||||
self.connection = None
|
self.connection = None
|
||||||
self.gpg = None
|
self.gpg = None
|
||||||
if USE_GPG:
|
self.USE_GPG = False
|
||||||
|
if gajim.HAVE_GPG:
|
||||||
|
self.USE_GPG = True
|
||||||
self.gpg = GnuPG.GnuPG(gajim.config.get('use_gpg_agent'))
|
self.gpg = GnuPG.GnuPG(gajim.config.get('use_gpg_agent'))
|
||||||
self.is_zeroconf = True
|
self.is_zeroconf = True
|
||||||
self.privacy_rules_supported = False
|
self.privacy_rules_supported = False
|
||||||
|
@ -86,9 +86,13 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
|
||||||
self.no_log_for = False
|
self.no_log_for = False
|
||||||
|
|
||||||
self.pep_supported = False
|
self.pep_supported = False
|
||||||
|
self.mood = {}
|
||||||
|
self.tune = {}
|
||||||
|
self.activity = {}
|
||||||
# Do we continue connection when we get roster (send presence,get vcard...)
|
# Do we continue connection when we get roster (send presence,get vcard...)
|
||||||
self.continue_connect_info = None
|
self.continue_connect_info = None
|
||||||
if USE_GPG:
|
if gajim.HAVE_GPG:
|
||||||
|
self.USE_GPG = True
|
||||||
self.gpg = GnuPG.GnuPG(gajim.config.get('use_gpg_agent'))
|
self.gpg = GnuPG.GnuPG(gajim.config.get('use_gpg_agent'))
|
||||||
|
|
||||||
self.get_config_values_or_default()
|
self.get_config_values_or_default()
|
||||||
|
@ -160,17 +164,19 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
|
||||||
def get_signed_msg(self, msg):
|
def get_signed_msg(self, msg):
|
||||||
signed = ''
|
signed = ''
|
||||||
keyID = gajim.config.get_per('accounts', self.name, 'keyid')
|
keyID = gajim.config.get_per('accounts', self.name, 'keyid')
|
||||||
if keyID and USE_GPG:
|
if keyID and self.USE_GPG:
|
||||||
use_gpg_agent = gajim.config.get('use_gpg_agent')
|
use_gpg_agent = gajim.config.get('use_gpg_agent')
|
||||||
if self.connected < 2 and self.gpg.passphrase is None and \
|
if self.connected < 2 and self.gpg.passphrase is None and \
|
||||||
not use_gpg_agent:
|
not use_gpg_agent:
|
||||||
# We didn't set a passphrase
|
# We didn't set a passphrase
|
||||||
self.dispatch('ERROR', (_('OpenPGP passphrase was not given'),
|
self.dispatch('ERROR', (_('OpenPGP passphrase was not given'),
|
||||||
#%s is the account name here
|
#%s is the account name here
|
||||||
_('You will be connected to %s without OpenPGP.') % self.name))
|
_('You will be connected to %s without OpenPGP.') % self.name))
|
||||||
|
self.USE_GPG = False
|
||||||
elif self.gpg.passphrase is not None or use_gpg_agent:
|
elif self.gpg.passphrase is not None or use_gpg_agent:
|
||||||
signed = self.gpg.sign(msg, keyID)
|
signed = self.gpg.sign(msg, keyID)
|
||||||
if signed == 'BAD_PASSPHRASE':
|
if signed == 'BAD_PASSPHRASE':
|
||||||
|
self.USE_GPG = False
|
||||||
signed = ''
|
signed = ''
|
||||||
if self.connected < 2:
|
if self.connected < 2:
|
||||||
self.dispatch('BAD_PASSPHRASE', ())
|
self.dispatch('BAD_PASSPHRASE', ())
|
||||||
|
@ -370,9 +376,14 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
|
||||||
|
|
||||||
msgtxt = msg
|
msgtxt = msg
|
||||||
msgenc = ''
|
msgenc = ''
|
||||||
if keyID and USE_GPG:
|
if keyID and self.USE_GPG:
|
||||||
# encrypt
|
if keyID == 'UNKNOWN':
|
||||||
msgenc, error = self.gpg.encrypt(msg, [keyID])
|
error = _('Neither the remote presence is signed, nor a key was assigned.')
|
||||||
|
elif keyID[8:] == 'MISMATCH':
|
||||||
|
error = _('The contact\'s key (%s) does not match the key assigned in Gajim.' % keyID[:8])
|
||||||
|
else:
|
||||||
|
# encrypt
|
||||||
|
msgenc, error = self.gpg.encrypt(msg, [keyID])
|
||||||
if msgenc and not error:
|
if msgenc and not error:
|
||||||
msgtxt = '[This message is encrypted]'
|
msgtxt = '[This message is encrypted]'
|
||||||
lang = os.getenv('LANG')
|
lang = os.getenv('LANG')
|
||||||
|
@ -507,7 +518,7 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
|
||||||
gajim.log.debug('This should not happen (send_agent_status)')
|
gajim.log.debug('This should not happen (send_agent_status)')
|
||||||
|
|
||||||
def gpg_passphrase(self, passphrase):
|
def gpg_passphrase(self, passphrase):
|
||||||
if USE_GPG:
|
if self.gpg:
|
||||||
use_gpg_agent = gajim.config.get('use_gpg_agent')
|
use_gpg_agent = gajim.config.get('use_gpg_agent')
|
||||||
if use_gpg_agent:
|
if use_gpg_agent:
|
||||||
self.gpg.passphrase = None
|
self.gpg.passphrase = None
|
||||||
|
@ -515,13 +526,13 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
|
||||||
self.gpg.passphrase = passphrase
|
self.gpg.passphrase = passphrase
|
||||||
|
|
||||||
def ask_gpg_keys(self):
|
def ask_gpg_keys(self):
|
||||||
if USE_GPG:
|
if self.gpg:
|
||||||
keys = self.gpg.get_keys()
|
keys = self.gpg.get_keys()
|
||||||
return keys
|
return keys
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def ask_gpg_secrete_keys(self):
|
def ask_gpg_secrete_keys(self):
|
||||||
if USE_GPG:
|
if self.gpg:
|
||||||
keys = self.gpg.get_secret_keys()
|
keys = self.gpg.get_secret_keys()
|
||||||
return keys
|
return keys
|
||||||
return None
|
return None
|
||||||
|
|
655
src/config.py
655
src/config.py
|
@ -6,6 +6,7 @@
|
||||||
## Copyright (C) 2003-2005 Vincent Hanquez <tab@snarc.org>
|
## Copyright (C) 2003-2005 Vincent Hanquez <tab@snarc.org>
|
||||||
## Copyright (C) 2006 Stefan Bethge <stefan@lanpartei.de>
|
## Copyright (C) 2006 Stefan Bethge <stefan@lanpartei.de>
|
||||||
## Copyright (C) 2007 Stephan Erb <steve-e@h3c.de>
|
## Copyright (C) 2007 Stephan Erb <steve-e@h3c.de>
|
||||||
|
## Copyright (C) 2007 Travis Shirk <travis@pobox.com>
|
||||||
##
|
##
|
||||||
## This file is part of Gajim.
|
## This file is part of Gajim.
|
||||||
##
|
##
|
||||||
|
@ -49,6 +50,7 @@ from common import passwords
|
||||||
from common import zeroconf
|
from common import zeroconf
|
||||||
from common import dbus_support
|
from common import dbus_support
|
||||||
from common import dataforms
|
from common import dataforms
|
||||||
|
from common import pep
|
||||||
|
|
||||||
from common.exceptions import GajimGeneralException
|
from common.exceptions import GajimGeneralException
|
||||||
|
|
||||||
|
@ -69,8 +71,6 @@ class PreferencesWindow:
|
||||||
self.window = self.xml.get_widget('preferences_window')
|
self.window = self.xml.get_widget('preferences_window')
|
||||||
self.window.set_transient_for(gajim.interface.roster.window)
|
self.window.set_transient_for(gajim.interface.roster.window)
|
||||||
self.notebook = self.xml.get_widget('preferences_notebook')
|
self.notebook = self.xml.get_widget('preferences_notebook')
|
||||||
self.treat_incoming_messages_combobox =\
|
|
||||||
self.xml.get_widget('treat_incoming_messages_combobox')
|
|
||||||
self.one_window_type_combobox =\
|
self.one_window_type_combobox =\
|
||||||
self.xml.get_widget('one_window_type_combobox')
|
self.xml.get_widget('one_window_type_combobox')
|
||||||
self.iconset_combobox = self.xml.get_widget('iconset_combobox')
|
self.iconset_combobox = self.xml.get_widget('iconset_combobox')
|
||||||
|
@ -90,8 +90,6 @@ class PreferencesWindow:
|
||||||
'auto_xa_time_spinbutton')
|
'auto_xa_time_spinbutton')
|
||||||
self.auto_xa_message_entry = self.xml.get_widget('auto_xa_message_entry')
|
self.auto_xa_message_entry = self.xml.get_widget('auto_xa_message_entry')
|
||||||
|
|
||||||
w = self.xml.get_widget('anc_hbox')
|
|
||||||
|
|
||||||
### General tab ###
|
### General tab ###
|
||||||
# Display avatars in roster
|
# Display avatars in roster
|
||||||
st = gajim.config.get('show_avatars_in_roster')
|
st = gajim.config.get('show_avatars_in_roster')
|
||||||
|
@ -132,14 +130,6 @@ class PreferencesWindow:
|
||||||
if not gajim.config.get('emoticons_theme'):
|
if not gajim.config.get('emoticons_theme'):
|
||||||
emoticons_combobox.set_active(len(l)-1)
|
emoticons_combobox.set_active(len(l)-1)
|
||||||
|
|
||||||
# Set default for treat incoming messages
|
|
||||||
choices = common.config.opt_treat_incoming_messages
|
|
||||||
type = gajim.config.get('treat_incoming_messages')
|
|
||||||
if type in choices:
|
|
||||||
self.treat_incoming_messages_combobox.set_active(choices.index(type))
|
|
||||||
else:
|
|
||||||
self.treat_incoming_messages_combobox.set_active(0)
|
|
||||||
|
|
||||||
# Set default for single window type
|
# Set default for single window type
|
||||||
choices = common.config.opt_one_window_types
|
choices = common.config.opt_one_window_types
|
||||||
type = gajim.config.get('one_message_window')
|
type = gajim.config.get('one_message_window')
|
||||||
|
@ -163,6 +153,7 @@ class PreferencesWindow:
|
||||||
else:
|
else:
|
||||||
self.xml.get_widget('speller_checkbutton').set_sensitive(False)
|
self.xml.get_widget('speller_checkbutton').set_sensitive(False)
|
||||||
|
|
||||||
|
### Style tab ###
|
||||||
# Themes
|
# Themes
|
||||||
theme_combobox = self.xml.get_widget('theme_combobox')
|
theme_combobox = self.xml.get_widget('theme_combobox')
|
||||||
cell = gtk.CellRendererText()
|
cell = gtk.CellRendererText()
|
||||||
|
@ -211,7 +202,37 @@ class PreferencesWindow:
|
||||||
st = gajim.config.get('use_transports_iconsets')
|
st = gajim.config.get('use_transports_iconsets')
|
||||||
self.xml.get_widget('transports_iconsets_checkbutton').set_active(st)
|
self.xml.get_widget('transports_iconsets_checkbutton').set_active(st)
|
||||||
|
|
||||||
### Privacy tab ###
|
# Color for incoming messages
|
||||||
|
colSt = gajim.config.get('inmsgcolor')
|
||||||
|
self.xml.get_widget('incoming_msg_colorbutton').set_color(
|
||||||
|
gtk.gdk.color_parse(colSt))
|
||||||
|
|
||||||
|
# Color for outgoing messages
|
||||||
|
colSt = gajim.config.get('outmsgcolor')
|
||||||
|
self.xml.get_widget('outgoing_msg_colorbutton').set_color(
|
||||||
|
gtk.gdk.color_parse(colSt))
|
||||||
|
|
||||||
|
# Color for status messages
|
||||||
|
colSt = gajim.config.get('statusmsgcolor')
|
||||||
|
self.xml.get_widget('status_msg_colorbutton').set_color(
|
||||||
|
gtk.gdk.color_parse(colSt))
|
||||||
|
|
||||||
|
# Color for hyperlinks
|
||||||
|
colSt = gajim.config.get('urlmsgcolor')
|
||||||
|
self.xml.get_widget('url_msg_colorbutton').set_color(
|
||||||
|
gtk.gdk.color_parse(colSt))
|
||||||
|
|
||||||
|
# Font for messages
|
||||||
|
font = gajim.config.get('conversation_font')
|
||||||
|
# try to set default font for the current desktop env
|
||||||
|
fontbutton = self.xml.get_widget('conversation_fontbutton')
|
||||||
|
if font == '':
|
||||||
|
fontbutton.set_sensitive(False)
|
||||||
|
self.xml.get_widget('default_chat_font').set_active(True)
|
||||||
|
else:
|
||||||
|
fontbutton.set_font_name(font)
|
||||||
|
|
||||||
|
### Personal Events tab ###
|
||||||
# outgoing send chat state notifications
|
# outgoing send chat state notifications
|
||||||
st = gajim.config.get('outgoing_chat_state_notifications')
|
st = gajim.config.get('outgoing_chat_state_notifications')
|
||||||
combo = self.xml.get_widget('outgoing_chat_states_combobox')
|
combo = self.xml.get_widget('outgoing_chat_states_combobox')
|
||||||
|
@ -232,11 +253,29 @@ class PreferencesWindow:
|
||||||
else: # disabled
|
else: # disabled
|
||||||
combo.set_active(2)
|
combo.set_active(2)
|
||||||
|
|
||||||
# Ignore messages from unknown contacts
|
# PEP
|
||||||
self.xml.get_widget('ignore_events_from_unknown_contacts_checkbutton').\
|
st = gajim.config.get('publish_mood')
|
||||||
set_active(gajim.config.get('ignore_unknown_contacts'))
|
self.xml.get_widget('publish_mood_checkbutton').set_active(st)
|
||||||
|
|
||||||
### Events tab ###
|
st = gajim.config.get('publish_activity')
|
||||||
|
self.xml.get_widget('publish_activity_checkbutton').set_active(st)
|
||||||
|
|
||||||
|
st = gajim.config.get('publish_tune')
|
||||||
|
self.xml.get_widget('publish_tune_checkbutton').set_active(st)
|
||||||
|
|
||||||
|
st = gajim.config.get('subscribe_mood')
|
||||||
|
self.xml.get_widget('subscribe_mood_checkbutton').set_active(st)
|
||||||
|
|
||||||
|
st = gajim.config.get('subscribe_activity')
|
||||||
|
self.xml.get_widget('subscribe_activity_checkbutton').set_active(st)
|
||||||
|
|
||||||
|
st = gajim.config.get('subscribe_tune')
|
||||||
|
self.xml.get_widget('subscribe_tune_checkbutton').set_active(st)
|
||||||
|
|
||||||
|
if not gajim.config.get('use_pep'):
|
||||||
|
self.xml.get_widget('frame_pep').set_sensitive(False)
|
||||||
|
|
||||||
|
### Notifications tab ###
|
||||||
# On new event
|
# On new event
|
||||||
on_event_combobox = self.xml.get_widget('on_event_combobox')
|
on_event_combobox = self.xml.get_widget('on_event_combobox')
|
||||||
if gajim.config.get('autopopup'):
|
if gajim.config.get('autopopup'):
|
||||||
|
@ -306,6 +345,24 @@ class PreferencesWindow:
|
||||||
|
|
||||||
self.fill_sound_treeview()
|
self.fill_sound_treeview()
|
||||||
|
|
||||||
|
# Notify user of new gmail e-mail messages,
|
||||||
|
# make checkbox sensitive if user has a gtalk account
|
||||||
|
frame_gmail = self.xml.get_widget('frame_gmail')
|
||||||
|
notify_gmail_checkbutton = self.xml.get_widget('notify_gmail_checkbutton')
|
||||||
|
notify_gmail_extra_checkbutton = self.xml.get_widget(
|
||||||
|
'notify_gmail_extra_checkbutton')
|
||||||
|
|
||||||
|
for account in gajim.config.get_per('accounts'):
|
||||||
|
jid = gajim.get_jid_from_account(account)
|
||||||
|
if gajim.get_server_from_jid(jid) in gajim.gmail_domains:
|
||||||
|
frame_gmail.set_sensitive(True)
|
||||||
|
st = gajim.config.get('notify_on_new_gmail_email')
|
||||||
|
notify_gmail_checkbutton.set_active(st)
|
||||||
|
st = gajim.config.get('notify_on_new_gmail_email_extra')
|
||||||
|
notify_gmail_extra_checkbutton.set_active(st)
|
||||||
|
break
|
||||||
|
|
||||||
|
#### Status tab ###
|
||||||
# Autoaway
|
# Autoaway
|
||||||
st = gajim.config.get('autoaway')
|
st = gajim.config.get('autoaway')
|
||||||
self.auto_away_checkbutton.set_active(st)
|
self.auto_away_checkbutton.set_active(st)
|
||||||
|
@ -356,7 +413,7 @@ class PreferencesWindow:
|
||||||
renderer = gtk.CellRendererText()
|
renderer = gtk.CellRendererText()
|
||||||
col.pack_start(renderer, False)
|
col.pack_start(renderer, False)
|
||||||
col.set_attributes(renderer, text = 1)
|
col.set_attributes(renderer, text = 1)
|
||||||
col = gtk.TreeViewColumn('Message')
|
col = gtk.TreeViewColumn('Default Message')
|
||||||
self.default_msg_tree.append_column(col)
|
self.default_msg_tree.append_column(col)
|
||||||
renderer = gtk.CellRendererText()
|
renderer = gtk.CellRendererText()
|
||||||
col.pack_start(renderer, True)
|
col.pack_start(renderer, True)
|
||||||
|
@ -387,6 +444,7 @@ class PreferencesWindow:
|
||||||
buf = self.xml.get_widget('msg_textview').get_buffer()
|
buf = self.xml.get_widget('msg_textview').get_buffer()
|
||||||
buf.connect('changed', self.on_msg_textview_changed)
|
buf.connect('changed', self.on_msg_textview_changed)
|
||||||
|
|
||||||
|
### Advanced tab ###
|
||||||
# open links with
|
# open links with
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
applications_frame = self.xml.get_widget('applications_frame')
|
applications_frame = self.xml.get_widget('applications_frame')
|
||||||
|
@ -417,8 +475,8 @@ class PreferencesWindow:
|
||||||
self.applications_combobox.set_active(2)
|
self.applications_combobox.set_active(2)
|
||||||
elif gajim.config.get('openwith') == 'exo-open':
|
elif gajim.config.get('openwith') == 'exo-open':
|
||||||
self.applications_combobox.set_active(3)
|
self.applications_combobox.set_active(3)
|
||||||
elif ((sys.platform == 'darwin') and
|
elif ((sys.platform == 'darwin') and\
|
||||||
(gajim.config.get('openwith') == 'open')):
|
(gajim.config.get('openwith') == 'open')):
|
||||||
self.applications_combobox.set_active(1)
|
self.applications_combobox.set_active(1)
|
||||||
elif gajim.config.get('openwith') == 'custom':
|
elif gajim.config.get('openwith') == 'custom':
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
|
@ -438,74 +496,21 @@ class PreferencesWindow:
|
||||||
st = gajim.config.get('log_contact_status_changes')
|
st = gajim.config.get('log_contact_status_changes')
|
||||||
self.xml.get_widget('log_show_changes_checkbutton').set_active(st)
|
self.xml.get_widget('log_show_changes_checkbutton').set_active(st)
|
||||||
|
|
||||||
|
# log encrypted chat sessions
|
||||||
|
st = gajim.config.get('log_encrypted_sessions')
|
||||||
|
self.xml.get_widget('log_encrypted_chats_checkbutton').set_active(st)
|
||||||
|
|
||||||
# send os info
|
# send os info
|
||||||
st = gajim.config.get('send_os_info')
|
st = gajim.config.get('send_os_info')
|
||||||
self.xml.get_widget('send_os_info_checkbutton').set_active(st)
|
self.xml.get_widget('send_os_info_checkbutton').set_active(st)
|
||||||
|
|
||||||
# send os info
|
# check if gajm is default
|
||||||
st = gajim.config.get('check_if_gajim_is_default')
|
st = gajim.config.get('check_if_gajim_is_default')
|
||||||
self.xml.get_widget('check_default_client_checkbutton').set_active(st)
|
self.xml.get_widget('check_default_client_checkbutton').set_active(st)
|
||||||
|
|
||||||
# set status msg from currently playing music track
|
# Ignore messages from unknown contacts
|
||||||
widget = self.xml.get_widget(
|
self.xml.get_widget('ignore_events_from_unknown_contacts_checkbutton').\
|
||||||
'set_status_msg_from_current_music_track_checkbutton')
|
set_active(gajim.config.get('ignore_unknown_contacts'))
|
||||||
if os.name == 'nt':
|
|
||||||
widget.set_no_show_all(True)
|
|
||||||
widget.hide()
|
|
||||||
elif dbus_support.supported:
|
|
||||||
st = gajim.config.get('set_status_msg_from_current_music_track')
|
|
||||||
widget.set_active(st)
|
|
||||||
else:
|
|
||||||
widget.set_sensitive(False)
|
|
||||||
|
|
||||||
# Notify user of new gmail e-mail messages,
|
|
||||||
# only show checkbox if user has a gtalk account
|
|
||||||
frame_gmail = self.xml.get_widget('frame_gmail')
|
|
||||||
notify_gmail_checkbutton = self.xml.get_widget('notify_gmail_checkbutton')
|
|
||||||
notify_gmail_extra_checkbutton = self.xml.get_widget(
|
|
||||||
'notify_gmail_extra_checkbutton')
|
|
||||||
|
|
||||||
for account in gajim.config.get_per('accounts'):
|
|
||||||
jid = gajim.get_jid_from_account(account)
|
|
||||||
if gajim.get_server_from_jid(jid) in gajim.gmail_domains:
|
|
||||||
frame_gmail.show_all()
|
|
||||||
st = gajim.config.get('notify_on_new_gmail_email')
|
|
||||||
notify_gmail_checkbutton.set_active(st)
|
|
||||||
st = gajim.config.get('notify_on_new_gmail_email_extra')
|
|
||||||
notify_gmail_extra_checkbutton.set_active(st)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
frame_gmail.hide()
|
|
||||||
|
|
||||||
# Color for incoming messages
|
|
||||||
colSt = gajim.config.get('inmsgcolor')
|
|
||||||
self.xml.get_widget('incoming_msg_colorbutton').set_color(
|
|
||||||
gtk.gdk.color_parse(colSt))
|
|
||||||
|
|
||||||
# Color for outgoing messages
|
|
||||||
colSt = gajim.config.get('outmsgcolor')
|
|
||||||
self.xml.get_widget('outgoing_msg_colorbutton').set_color(
|
|
||||||
gtk.gdk.color_parse(colSt))
|
|
||||||
|
|
||||||
# Color for status messages
|
|
||||||
colSt = gajim.config.get('statusmsgcolor')
|
|
||||||
self.xml.get_widget('status_msg_colorbutton').set_color(
|
|
||||||
gtk.gdk.color_parse(colSt))
|
|
||||||
|
|
||||||
# Color for hyperlinks
|
|
||||||
colSt = gajim.config.get('urlmsgcolor')
|
|
||||||
self.xml.get_widget('url_msg_colorbutton').set_color(
|
|
||||||
gtk.gdk.color_parse(colSt))
|
|
||||||
|
|
||||||
# Font for messages
|
|
||||||
font = gajim.config.get('conversation_font')
|
|
||||||
# try to set default font for the current desktop env
|
|
||||||
fontbutton = self.xml.get_widget('conversation_fontbutton')
|
|
||||||
if font == '':
|
|
||||||
fontbutton.set_sensitive(False)
|
|
||||||
self.xml.get_widget('default_chat_font').set_active(True)
|
|
||||||
else:
|
|
||||||
fontbutton.set_font_name(font)
|
|
||||||
|
|
||||||
self.xml.signal_autoconnect(self)
|
self.xml.signal_autoconnect(self)
|
||||||
|
|
||||||
|
@ -521,6 +526,7 @@ class PreferencesWindow:
|
||||||
self.theme_preferences = None
|
self.theme_preferences = None
|
||||||
|
|
||||||
self.notebook.set_current_page(0)
|
self.notebook.set_current_page(0)
|
||||||
|
|
||||||
self.window.show_all()
|
self.window.show_all()
|
||||||
gtkgui_helpers.possibly_move_window_in_current_desktop(self.window)
|
gtkgui_helpers.possibly_move_window_in_current_desktop(self.window)
|
||||||
|
|
||||||
|
@ -536,6 +542,42 @@ class PreferencesWindow:
|
||||||
w.set_sensitive(widget.get_active())
|
w.set_sensitive(widget.get_active())
|
||||||
gajim.interface.save_config()
|
gajim.interface.save_config()
|
||||||
|
|
||||||
|
def on_publish_mood_checkbutton_toggled(self, widget):
|
||||||
|
if widget.get_active() == False:
|
||||||
|
for account in gajim.connections:
|
||||||
|
if gajim.connections[account].pep_supported:
|
||||||
|
pep.user_send_mood(account, '')
|
||||||
|
self.on_checkbutton_toggled(widget, 'publish_mood')
|
||||||
|
|
||||||
|
def on_publish_activity_checkbutton_toggled(self, widget):
|
||||||
|
if widget.get_active() == False:
|
||||||
|
for account in gajim.connections:
|
||||||
|
if gajim.connections[account].pep_supported:
|
||||||
|
pep.user_send_activity(account, '')
|
||||||
|
self.on_checkbutton_toggled(widget, 'publish_activity')
|
||||||
|
|
||||||
|
def on_publish_tune_checkbutton_toggled(self, widget):
|
||||||
|
if widget.get_active() == False:
|
||||||
|
for account in gajim.connections:
|
||||||
|
if gajim.connections[account].pep_supported:
|
||||||
|
pep.user_send_tune(account, '')
|
||||||
|
self.on_checkbutton_toggled(widget, 'publish_tune')
|
||||||
|
gajim.interface.roster.enable_syncing_status_msg_from_current_music_track(
|
||||||
|
widget.get_active())
|
||||||
|
|
||||||
|
def on_subscribe_mood_checkbutton_toggled(self, widget):
|
||||||
|
self.on_checkbutton_toggled(widget, 'subscribe_mood')
|
||||||
|
|
||||||
|
def on_subscribe_activity_checkbutton_toggled(self, widget):
|
||||||
|
self.on_checkbutton_toggled(widget, 'subscribe_activity')
|
||||||
|
|
||||||
|
def on_subscribe_tune_checkbutton_toggled(self, widget):
|
||||||
|
self.on_checkbutton_toggled(widget, 'subscribe_tune')
|
||||||
|
|
||||||
|
def on_sort_by_show_checkbutton_toggled(self, widget):
|
||||||
|
self.on_checkbutton_toggled(widget, 'sort_by_show')
|
||||||
|
gajim.interface.roster.draw_roster()
|
||||||
|
|
||||||
def on_show_avatars_in_roster_checkbutton_toggled(self, widget):
|
def on_show_avatars_in_roster_checkbutton_toggled(self, widget):
|
||||||
self.on_checkbutton_toggled(widget, 'show_avatars_in_roster')
|
self.on_checkbutton_toggled(widget, 'show_avatars_in_roster')
|
||||||
gajim.interface.roster.draw_roster()
|
gajim.interface.roster.draw_roster()
|
||||||
|
@ -576,11 +618,6 @@ class PreferencesWindow:
|
||||||
for win in gajim.interface.msg_win_mgr.windows():
|
for win in gajim.interface.msg_win_mgr.windows():
|
||||||
win.toggle_emoticons()
|
win.toggle_emoticons()
|
||||||
|
|
||||||
def on_treat_incoming_messages_combobox_changed(self, widget):
|
|
||||||
active = widget.get_active()
|
|
||||||
config_type = common.config.opt_treat_incoming_messages[active]
|
|
||||||
gajim.config.set('treat_incoming_messages', config_type)
|
|
||||||
|
|
||||||
def on_one_window_type_combo_changed(self, widget):
|
def on_one_window_type_combo_changed(self, widget):
|
||||||
active = widget.get_active()
|
active = widget.get_active()
|
||||||
config_type = common.config.opt_one_window_types[active]
|
config_type = common.config.opt_one_window_types[active]
|
||||||
|
@ -955,6 +992,9 @@ class PreferencesWindow:
|
||||||
def on_log_show_changes_checkbutton_toggled(self, widget):
|
def on_log_show_changes_checkbutton_toggled(self, widget):
|
||||||
self.on_checkbutton_toggled(widget, 'log_contact_status_changes')
|
self.on_checkbutton_toggled(widget, 'log_contact_status_changes')
|
||||||
|
|
||||||
|
def on_log_encrypted_chats_checkbutton_toggled(self, widget):
|
||||||
|
self.on_checkbutton_toggled(widget, 'log_encrypted_sessions')
|
||||||
|
|
||||||
def on_send_os_info_checkbutton_toggled(self, widget):
|
def on_send_os_info_checkbutton_toggled(self, widget):
|
||||||
self.on_checkbutton_toggled(widget, 'send_os_info')
|
self.on_checkbutton_toggled(widget, 'send_os_info')
|
||||||
|
|
||||||
|
@ -1030,26 +1070,23 @@ class PreferencesWindow:
|
||||||
def fill_sound_treeview(self):
|
def fill_sound_treeview(self):
|
||||||
model = self.sound_tree.get_model()
|
model = self.sound_tree.get_model()
|
||||||
model.clear()
|
model.clear()
|
||||||
|
model.set_sort_column_id(1, gtk.SORT_ASCENDING)
|
||||||
|
|
||||||
# NOTE: sounds_ui_names MUST have all items of
|
# NOTE: sounds_ui_names MUST have all items of
|
||||||
# sounds = gajim.config.get_per('soundevents') as keys
|
# sounds = gajim.config.get_per('soundevents') as keys
|
||||||
sounds_dict = {
|
sounds_dict = {
|
||||||
'first_message_received': _('First Message Received'),
|
'first_message_received': _('First Message Received'),
|
||||||
'next_message_received': _('Next Message Received'),
|
'next_message_received_focused': _('Next Message Received Focused'),
|
||||||
|
'next_message_received_unfocused':
|
||||||
|
_('Next Message Received Unfocused'),
|
||||||
'contact_connected': _('Contact Connected'),
|
'contact_connected': _('Contact Connected'),
|
||||||
'contact_disconnected': _('Contact Disconnected'),
|
'contact_disconnected': _('Contact Disconnected'),
|
||||||
'message_sent': _('Message Sent'),
|
'message_sent': _('Message Sent'),
|
||||||
'muc_message_highlight': _('Group Chat Message Highlight'),
|
'muc_message_highlight': _('Group Chat Message Highlight'),
|
||||||
'muc_message_received': _('Group Chat Message Received')
|
'muc_message_received': _('Group Chat Message Received'),
|
||||||
|
'gmail_received': _('GMail Email Received')
|
||||||
}
|
}
|
||||||
|
|
||||||
# In case of a GMail account we provide a sound notification option
|
|
||||||
for account in gajim.config.get_per('accounts'):
|
|
||||||
jid = gajim.get_jid_from_account(account)
|
|
||||||
if gajim.get_server_from_jid(jid) in gajim.gmail_domains:
|
|
||||||
sounds_dict['gmail_received'] = _('GMail Email Received')
|
|
||||||
break
|
|
||||||
|
|
||||||
for sound_event_config_name, sound_ui_name in sounds_dict.items():
|
for sound_event_config_name, sound_ui_name in sounds_dict.items():
|
||||||
enabled = gajim.config.get_per('soundevents',
|
enabled = gajim.config.get_per('soundevents',
|
||||||
sound_event_config_name, 'enabled')
|
sound_event_config_name, 'enabled')
|
||||||
|
@ -1290,6 +1327,7 @@ class AccountsWindow:
|
||||||
del gajim.interface.instances['accounts']
|
del gajim.interface.instances['accounts']
|
||||||
|
|
||||||
def on_close_button_clicked(self, widget):
|
def on_close_button_clicked(self, widget):
|
||||||
|
self.check_resend_relog()
|
||||||
self.window.destroy()
|
self.window.destroy()
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -1299,8 +1337,6 @@ class AccountsWindow:
|
||||||
self.accounts_treeview = self.xml.get_widget('accounts_treeview')
|
self.accounts_treeview = self.xml.get_widget('accounts_treeview')
|
||||||
self.remove_button = self.xml.get_widget('remove_button')
|
self.remove_button = self.xml.get_widget('remove_button')
|
||||||
self.rename_button = self.xml.get_widget('rename_button')
|
self.rename_button = self.xml.get_widget('rename_button')
|
||||||
#FIXME: I don't understand why this import is necessary
|
|
||||||
import os
|
|
||||||
path_to_kbd_input_img = os.path.join(gajim.DATA_DIR, 'pixmaps',
|
path_to_kbd_input_img = os.path.join(gajim.DATA_DIR, 'pixmaps',
|
||||||
'kbd_input.png')
|
'kbd_input.png')
|
||||||
img = self.xml.get_widget('rename_image')
|
img = self.xml.get_widget('rename_image')
|
||||||
|
@ -1327,7 +1363,10 @@ class AccountsWindow:
|
||||||
|
|
||||||
# Merge accounts
|
# Merge accounts
|
||||||
st = gajim.config.get('mergeaccounts')
|
st = gajim.config.get('mergeaccounts')
|
||||||
self.xml.get_widget('merge_checkbutton').set_active(st)
|
checkbutton = self.xml.get_widget('merge_checkbutton')
|
||||||
|
checkbutton.set_active(st)
|
||||||
|
# prevent roster redraws by connecting the signal after button state is set
|
||||||
|
checkbutton.connect('toggled', self.on_merge_checkbutton_toggled)
|
||||||
|
|
||||||
self.avahi_available = True
|
self.avahi_available = True
|
||||||
try:
|
try:
|
||||||
|
@ -1337,6 +1376,7 @@ class AccountsWindow:
|
||||||
|
|
||||||
def on_accounts_window_key_press_event(self, widget, event):
|
def on_accounts_window_key_press_event(self, widget, event):
|
||||||
if event.keyval == gtk.keysyms.Escape:
|
if event.keyval == gtk.keysyms.Escape:
|
||||||
|
self.check_resend_relog()
|
||||||
self.window.destroy()
|
self.window.destroy()
|
||||||
|
|
||||||
def select_account(self, account):
|
def select_account(self, account):
|
||||||
|
@ -1354,7 +1394,6 @@ class AccountsWindow:
|
||||||
self.remove_button.set_sensitive(False)
|
self.remove_button.set_sensitive(False)
|
||||||
self.rename_button.set_sensitive(False)
|
self.rename_button.set_sensitive(False)
|
||||||
self.current_account = None
|
self.current_account = None
|
||||||
self.init_account()
|
|
||||||
model = self.accounts_treeview.get_model()
|
model = self.accounts_treeview.get_model()
|
||||||
model.clear()
|
model.clear()
|
||||||
for account in gajim.config.get_per('accounts'):
|
for account in gajim.config.get_per('accounts'):
|
||||||
|
@ -1366,37 +1405,7 @@ class AccountsWindow:
|
||||||
status = gajim.connections[self.current_account].status
|
status = gajim.connections[self.current_account].status
|
||||||
gajim.connections[self.current_account].change_status(show, status)
|
gajim.connections[self.current_account].change_status(show, status)
|
||||||
|
|
||||||
def on_accounts_treeview_cursor_changed(self, widget):
|
def check_resend_relog(self):
|
||||||
'''Activate modify buttons when a row is selected, update accounts info'''
|
|
||||||
sel = self.accounts_treeview.get_selection()
|
|
||||||
(model, iter) = sel.get_selected()
|
|
||||||
if iter:
|
|
||||||
account = model[iter][0].decode('utf-8')
|
|
||||||
else:
|
|
||||||
account = None
|
|
||||||
if self.current_account and self.current_account == account:
|
|
||||||
# We're comming back to our current account, no need to update widgets
|
|
||||||
return
|
|
||||||
# Save config for previous account if needed cause focus_out event is
|
|
||||||
# called after the changed event
|
|
||||||
if self.current_account:
|
|
||||||
focused_widget = self.window.get_focus()
|
|
||||||
focused_widget_name = focused_widget.get_name()
|
|
||||||
if focused_widget_name in ('jid_entry1', 'resource_entry1',
|
|
||||||
'custom_port_entry'):
|
|
||||||
if focused_widget_name == 'jid_entry1':
|
|
||||||
func = self.on_jid_entry1_focus_out_event
|
|
||||||
elif focused_widget_name == 'resource_entry1':
|
|
||||||
func = self.on_resource_entry1_focus_out_event
|
|
||||||
elif focused_widget_name == 'custom_port_entry':
|
|
||||||
func = self.on_custom_port_entry_focus_out_event
|
|
||||||
if func(focused_widget, None):
|
|
||||||
# Error detected in entry, don't change account, re-put cursor on
|
|
||||||
# previous row
|
|
||||||
self.select_account(self.current_account)
|
|
||||||
return True
|
|
||||||
self.window.set_focus(widget)
|
|
||||||
|
|
||||||
if self.need_relogin and self.current_account == gajim.ZEROCONF_ACC_NAME:
|
if self.need_relogin and self.current_account == gajim.ZEROCONF_ACC_NAME:
|
||||||
if gajim.connections.has_key(gajim.ZEROCONF_ACC_NAME):
|
if gajim.connections.has_key(gajim.ZEROCONF_ACC_NAME):
|
||||||
gajim.connections[gajim.ZEROCONF_ACC_NAME].update_details()
|
gajim.connections[gajim.ZEROCONF_ACC_NAME].update_details()
|
||||||
|
@ -1435,6 +1444,40 @@ class AccountsWindow:
|
||||||
|
|
||||||
self.need_relogin = False
|
self.need_relogin = False
|
||||||
self.resend_presence = False
|
self.resend_presence = False
|
||||||
|
|
||||||
|
def on_accounts_treeview_cursor_changed(self, widget):
|
||||||
|
'''Activate modify buttons when a row is selected, update accounts info'''
|
||||||
|
sel = self.accounts_treeview.get_selection()
|
||||||
|
(model, iter) = sel.get_selected()
|
||||||
|
if iter:
|
||||||
|
account = model[iter][0].decode('utf-8')
|
||||||
|
else:
|
||||||
|
account = None
|
||||||
|
if self.current_account and self.current_account == account:
|
||||||
|
# We're comming back to our current account, no need to update widgets
|
||||||
|
return
|
||||||
|
# Save config for previous account if needed cause focus_out event is
|
||||||
|
# called after the changed event
|
||||||
|
if self.current_account:
|
||||||
|
focused_widget = self.window.get_focus()
|
||||||
|
focused_widget_name = focused_widget.get_name()
|
||||||
|
if focused_widget_name in ('jid_entry1', 'resource_entry1',
|
||||||
|
'custom_port_entry'):
|
||||||
|
if focused_widget_name == 'jid_entry1':
|
||||||
|
func = self.on_jid_entry1_focus_out_event
|
||||||
|
elif focused_widget_name == 'resource_entry1':
|
||||||
|
func = self.on_resource_entry1_focus_out_event
|
||||||
|
elif focused_widget_name == 'custom_port_entry':
|
||||||
|
func = self.on_custom_port_entry_focus_out_event
|
||||||
|
if func(focused_widget, None):
|
||||||
|
# Error detected in entry, don't change account, re-put cursor on
|
||||||
|
# previous row
|
||||||
|
self.select_account(self.current_account)
|
||||||
|
return True
|
||||||
|
self.window.set_focus(widget)
|
||||||
|
|
||||||
|
self.check_resend_relog()
|
||||||
|
|
||||||
self.remove_button.set_sensitive(True)
|
self.remove_button.set_sensitive(True)
|
||||||
self.rename_button.set_sensitive(True)
|
self.rename_button.set_sensitive(True)
|
||||||
if iter:
|
if iter:
|
||||||
|
@ -1585,8 +1628,16 @@ class AccountsWindow:
|
||||||
'priority'))
|
'priority'))
|
||||||
|
|
||||||
# Connection tab
|
# Connection tab
|
||||||
usessl = gajim.config.get_per('accounts', account, 'usessl')
|
use_env_http_proxy = gajim.config.get_per('accounts', account,
|
||||||
self.xml.get_widget('use_ssl_checkbutton1').set_active(usessl)
|
'use_env_http_proxy')
|
||||||
|
self.xml.get_widget('use_env_http_proxy_checkbutton1').set_active(
|
||||||
|
use_env_http_proxy)
|
||||||
|
self.xml.get_widget('proxy_hbox1').set_sensitive(not use_env_http_proxy)
|
||||||
|
|
||||||
|
warn_when_insecure = gajim.config.get_per('accounts', account,
|
||||||
|
'warn_when_insecure_connection')
|
||||||
|
self.xml.get_widget('warn_when_insecure_connection_checkbutton1').\
|
||||||
|
set_active(warn_when_insecure)
|
||||||
|
|
||||||
self.xml.get_widget('send_keepalive_checkbutton1').set_active(
|
self.xml.get_widget('send_keepalive_checkbutton1').set_active(
|
||||||
gajim.config.get_per('accounts', account, 'keep_alives_enabled'))
|
gajim.config.get_per('accounts', account, 'keep_alives_enabled'))
|
||||||
|
@ -1899,7 +1950,8 @@ class AccountsWindow:
|
||||||
'no_log_for').split()
|
'no_log_for').split()
|
||||||
if self.current_account in list_no_log_for:
|
if self.current_account in list_no_log_for:
|
||||||
list_no_log_for.remove(self.current_account)
|
list_no_log_for.remove(self.current_account)
|
||||||
if not self.xml.get_widget('log_history_checkbutton').get_active():
|
|
||||||
|
if not widget.get_active():
|
||||||
list_no_log_for.append(self.current_account)
|
list_no_log_for.append(self.current_account)
|
||||||
gajim.config.set_per('accounts', self.current_account, 'no_log_for',
|
gajim.config.set_per('accounts', self.current_account, 'no_log_for',
|
||||||
' '.join(list_no_log_for))
|
' '.join(list_no_log_for))
|
||||||
|
@ -1917,6 +1969,14 @@ class AccountsWindow:
|
||||||
self.on_checkbutton_toggled(widget, 'use_ft_proxies',
|
self.on_checkbutton_toggled(widget, 'use_ft_proxies',
|
||||||
account=self.current_account)
|
account=self.current_account)
|
||||||
|
|
||||||
|
def on_use_env_http_proxy_checkbutton1_toggled(self, widget):
|
||||||
|
if self.ignore_events:
|
||||||
|
return
|
||||||
|
self.on_checkbutton_toggled(widget, 'use_env_http_proxy',
|
||||||
|
account=self.current_account)
|
||||||
|
hbox = self.xml.get_widget('proxy_hbox1')
|
||||||
|
hbox.set_sensitive(not widget.get_active())
|
||||||
|
|
||||||
def on_proxies_combobox1_changed(self, widget):
|
def on_proxies_combobox1_changed(self, widget):
|
||||||
active = widget.get_active()
|
active = widget.get_active()
|
||||||
proxy = widget.get_model()[active][0].decode('utf-8')
|
proxy = widget.get_model()[active][0].decode('utf-8')
|
||||||
|
@ -1934,20 +1994,11 @@ class AccountsWindow:
|
||||||
else:
|
else:
|
||||||
gajim.interface.instances['manage_proxies'] = ManageProxiesWindow()
|
gajim.interface.instances['manage_proxies'] = ManageProxiesWindow()
|
||||||
|
|
||||||
def on_use_ssl_checkbutton1_toggled(self, widget):
|
def on_warn_when_insecure_connection_checkbutton1_toggled(self, widget):
|
||||||
if self.ignore_events:
|
if self.ignore_events:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.option_changed('usessl', widget.get_active()):
|
self.on_checkbutton_toggled(widget, 'warn_when_insecure_connection',
|
||||||
self.need_relogin = True
|
|
||||||
|
|
||||||
isactive = widget.get_active()
|
|
||||||
if isactive:
|
|
||||||
self.xml.get_widget('custom_port_entry1').set_text('5223')
|
|
||||||
else:
|
|
||||||
self.xml.get_widget('custom_port_entry1').set_text('5222')
|
|
||||||
|
|
||||||
self.on_checkbutton_toggled(widget, 'usessl',
|
|
||||||
account=self.current_account)
|
account=self.current_account)
|
||||||
|
|
||||||
def on_send_keepalive_checkbutton1_toggled(self, widget):
|
def on_send_keepalive_checkbutton1_toggled(self, widget):
|
||||||
|
@ -1992,14 +2043,14 @@ class AccountsWindow:
|
||||||
custom_port)
|
custom_port)
|
||||||
|
|
||||||
def on_gpg_choose_button_clicked(self, widget, data = None):
|
def on_gpg_choose_button_clicked(self, widget, data = None):
|
||||||
if gajim.connections.has_key(self.current_account):
|
if gajim.connections.has_key(self.current_account) and \
|
||||||
|
gajim.connections[self.current_account].gpg:
|
||||||
secret_keys = gajim.connections[self.current_account].\
|
secret_keys = gajim.connections[self.current_account].\
|
||||||
ask_gpg_secrete_keys()
|
ask_gpg_secrete_keys()
|
||||||
|
|
||||||
# self.current_account is None and/or gajim.connections is {}
|
# self.current_account is None and/or gajim.connections is {}
|
||||||
else:
|
else:
|
||||||
from common import GnuPG
|
if gajim.HAVE_GPG:
|
||||||
if GnuPG.USE_GPG:
|
|
||||||
secret_keys = GnuPG.GnuPG().get_secret_keys()
|
secret_keys = GnuPG.GnuPG().get_secret_keys()
|
||||||
else:
|
else:
|
||||||
secret_keys = []
|
secret_keys = []
|
||||||
|
@ -3030,7 +3081,7 @@ class AccountCreationWizardWindow:
|
||||||
elif cur_page == 1:
|
elif cur_page == 1:
|
||||||
# We are adding an existing account
|
# We are adding an existing account
|
||||||
username = self.xml.get_widget('username_entry').get_text().decode(
|
username = self.xml.get_widget('username_entry').get_text().decode(
|
||||||
'utf-8')
|
'utf-8').strip()
|
||||||
if not username:
|
if not username:
|
||||||
pritext = _('Invalid username')
|
pritext = _('Invalid username')
|
||||||
sectext = _(
|
sectext = _(
|
||||||
|
@ -3038,7 +3089,7 @@ class AccountCreationWizardWindow:
|
||||||
dialogs.ErrorDialog(pritext, sectext)
|
dialogs.ErrorDialog(pritext, sectext)
|
||||||
return
|
return
|
||||||
server = self.xml.get_widget('server_comboboxentry').child.get_text().\
|
server = self.xml.get_widget('server_comboboxentry').child.get_text().\
|
||||||
decode('utf-8')
|
decode('utf-8').strip()
|
||||||
savepass = self.xml.get_widget('save_password_checkbutton').\
|
savepass = self.xml.get_widget('save_password_checkbutton').\
|
||||||
get_active()
|
get_active()
|
||||||
password = self.xml.get_widget('password_entry').get_text().decode(
|
password = self.xml.get_widget('password_entry').get_text().decode(
|
||||||
|
@ -3142,12 +3193,22 @@ class AccountCreationWizardWindow:
|
||||||
if checked:
|
if checked:
|
||||||
hostname = gajim.connections[self.account].new_account_info[
|
hostname = gajim.connections[self.account].new_account_info[
|
||||||
'hostname']
|
'hostname']
|
||||||
f = open(gajim.MY_CACERTS, 'a')
|
# Check if cert is already in file
|
||||||
f.write(hostname + '\n')
|
certs = ''
|
||||||
f.write(self.ssl_cert + '\n\n')
|
if os.path.isfile(gajim.MY_CACERTS):
|
||||||
f.close()
|
f = open(gajim.MY_CACERTS)
|
||||||
gajim.connections[self.account].new_account_info[
|
certs = f.read()
|
||||||
'ssl_fingerprint_sha1'] = self.ssl_fingerprint
|
f.close()
|
||||||
|
if self.ssl_cert in certs:
|
||||||
|
dialogs.ErrorDialog(_('Certificate Already in File'),
|
||||||
|
_('This certificate is already in file %s, so it\'s not added again.') % gajim.MY_CACERTS)
|
||||||
|
else:
|
||||||
|
f = open(gajim.MY_CACERTS, 'a')
|
||||||
|
f.write(hostname + '\n')
|
||||||
|
f.write(self.ssl_cert + '\n\n')
|
||||||
|
f.close()
|
||||||
|
gajim.connections[self.account].new_account_info[
|
||||||
|
'ssl_fingerprint_sha1'] = self.ssl_fingerprint
|
||||||
self.notebook.set_current_page(4) # show fom page
|
self.notebook.set_current_page(4) # show fom page
|
||||||
elif cur_page == 4:
|
elif cur_page == 4:
|
||||||
if self.is_form:
|
if self.is_form:
|
||||||
|
@ -3188,7 +3249,7 @@ class AccountCreationWizardWindow:
|
||||||
self.progressbar.pulse()
|
self.progressbar.pulse()
|
||||||
return True # loop forever
|
return True # loop forever
|
||||||
|
|
||||||
def new_acc_connected(self, form, is_form, ssl_msg, ssl_cert,
|
def new_acc_connected(self, form, is_form, ssl_msg, ssl_err, ssl_cert,
|
||||||
ssl_fingerprint):
|
ssl_fingerprint):
|
||||||
'''connection to server succeded, present the form to the user.'''
|
'''connection to server succeded, present the form to the user.'''
|
||||||
if self.update_progressbar_timeout_id is not None:
|
if self.update_progressbar_timeout_id is not None:
|
||||||
|
@ -3213,8 +3274,12 @@ class AccountCreationWizardWindow:
|
||||||
'SSL Error: %s\n'
|
'SSL Error: %s\n'
|
||||||
'Do you still want to connect to this server?') % (hostname,
|
'Do you still want to connect to this server?') % (hostname,
|
||||||
ssl_msg))
|
ssl_msg))
|
||||||
text = _('Add this certificate to the list of trusted certificates.\nSHA1 fingerprint of the certificate:\n%s') % ssl_fingerprint
|
if ssl_err in (18, 27):
|
||||||
self.xml.get_widget('ssl_checkbutton').set_label(text)
|
text = _('Add this certificate to the list of trusted certificates.\nSHA1 fingerprint of the certificate:\n%s') % ssl_fingerprint
|
||||||
|
self.xml.get_widget('ssl_checkbutton').set_label(text)
|
||||||
|
else:
|
||||||
|
self.xml.get_widget('ssl_checkbutton').set_no_show_all(True)
|
||||||
|
self.xml.get_widget('ssl_checkbutton').hide()
|
||||||
self.notebook.set_current_page(3) # show SSL page
|
self.notebook.set_current_page(3) # show SSL page
|
||||||
else:
|
else:
|
||||||
self.notebook.set_current_page(4) # show form page
|
self.notebook.set_current_page(4) # show form page
|
||||||
|
@ -3406,3 +3471,277 @@ class AccountCreationWizardWindow:
|
||||||
gajim.interface.roster.draw_roster()
|
gajim.interface.roster.draw_roster()
|
||||||
gajim.interface.roster.set_actions_menu_needs_rebuild()
|
gajim.interface.roster.set_actions_menu_needs_rebuild()
|
||||||
gajim.interface.save_config()
|
gajim.interface.save_config()
|
||||||
|
|
||||||
|
#---------- ZeroconfPropertiesWindow class -------------#
|
||||||
|
class ZeroconfPropertiesWindow:
|
||||||
|
def __init__(self):
|
||||||
|
self.xml = gtkgui_helpers.get_glade('zeroconf_properties_window.glade')
|
||||||
|
self.window = self.xml.get_widget('zeroconf_properties_window')
|
||||||
|
self.window.set_transient_for(gajim.interface.roster.window)
|
||||||
|
self.xml.signal_autoconnect(self)
|
||||||
|
|
||||||
|
self.init_account()
|
||||||
|
self.init_account_gpg()
|
||||||
|
|
||||||
|
self.xml.get_widget('save_button').grab_focus()
|
||||||
|
self.window.show_all()
|
||||||
|
|
||||||
|
def init_account(self):
|
||||||
|
st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
|
||||||
|
'autoconnect')
|
||||||
|
if st:
|
||||||
|
self.xml.get_widget('autoconnect_checkbutton').set_active(st)
|
||||||
|
|
||||||
|
list_no_log_for = gajim.config.get_per('accounts',
|
||||||
|
gajim.ZEROCONF_ACC_NAME,'no_log_for').split()
|
||||||
|
if gajim.ZEROCONF_ACC_NAME in list_no_log_for:
|
||||||
|
self.xml.get_widget('log_history_checkbutton').set_active(0)
|
||||||
|
else:
|
||||||
|
self.xml.get_widget('log_history_checkbutton').set_active(1)
|
||||||
|
|
||||||
|
|
||||||
|
st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
|
||||||
|
'sync_with_global_status')
|
||||||
|
if st:
|
||||||
|
self.xml.get_widget('sync_with_global_status_checkbutton').set_active(
|
||||||
|
st)
|
||||||
|
|
||||||
|
for opt in ('first_name', 'last_name', 'jabber_id', 'email'):
|
||||||
|
st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
|
||||||
|
'zeroconf_' + opt)
|
||||||
|
if st:
|
||||||
|
self.xml.get_widget(opt + '_entry').set_text(st)
|
||||||
|
|
||||||
|
st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
|
||||||
|
'custom_port')
|
||||||
|
if st:
|
||||||
|
self.xml.get_widget('custom_port_entry').set_text(str(st))
|
||||||
|
|
||||||
|
st = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
|
||||||
|
'use_custom_host')
|
||||||
|
if st:
|
||||||
|
self.xml.get_widget('custom_port_checkbutton').set_active(st)
|
||||||
|
|
||||||
|
self.xml.get_widget('custom_port_entry').set_sensitive(bool(st))
|
||||||
|
|
||||||
|
if not st:
|
||||||
|
gajim.config.set_per('accounts', gajim.ZEROCONF_ACC_NAME,
|
||||||
|
'custom_port', '5298')
|
||||||
|
|
||||||
|
def init_account_gpg(self):
|
||||||
|
keyid = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'keyid')
|
||||||
|
keyname = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
|
||||||
|
'keyname')
|
||||||
|
savegpgpass = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
|
||||||
|
'savegpgpass')
|
||||||
|
|
||||||
|
if not keyid or not gajim.config.get('usegpg'):
|
||||||
|
return
|
||||||
|
|
||||||
|
self.xml.get_widget('gpg_key_label').set_text(keyid)
|
||||||
|
self.xml.get_widget('gpg_name_label').set_text(keyname)
|
||||||
|
gpg_save_password_checkbutton = \
|
||||||
|
self.xml.get_widget('gpg_save_password_checkbutton')
|
||||||
|
gpg_save_password_checkbutton.set_sensitive(True)
|
||||||
|
gpg_save_password_checkbutton.set_active(savegpgpass)
|
||||||
|
|
||||||
|
if savegpgpass:
|
||||||
|
entry = self.xml.get_widget('gpg_password_entry')
|
||||||
|
entry.set_sensitive(True)
|
||||||
|
gpgpassword = gajim.config.get_per('accounts',
|
||||||
|
gajim.ZEROCONF_ACC_NAME, 'gpgpassword')
|
||||||
|
entry.set_text(gpgpassword)
|
||||||
|
|
||||||
|
def on_zeroconf_properties_window_destroy(self, widget):
|
||||||
|
# close window
|
||||||
|
if gajim.interface.instances.has_key('zeroconf_properties'):
|
||||||
|
del gajim.interface.instances['zeroconf_properties']
|
||||||
|
|
||||||
|
def on_custom_port_checkbutton_toggled(self, widget):
|
||||||
|
st = self.xml.get_widget('custom_port_checkbutton').get_active()
|
||||||
|
self.xml.get_widget('custom_port_entry').set_sensitive(bool(st))
|
||||||
|
|
||||||
|
def on_cancel_button_clicked(self, widget):
|
||||||
|
self.window.destroy()
|
||||||
|
|
||||||
|
def on_save_button_clicked(self, widget):
|
||||||
|
config = {}
|
||||||
|
|
||||||
|
st = self.xml.get_widget('autoconnect_checkbutton').get_active()
|
||||||
|
config['autoconnect'] = st
|
||||||
|
list_no_log_for = gajim.config.get_per('accounts',
|
||||||
|
gajim.ZEROCONF_ACC_NAME, 'no_log_for').split()
|
||||||
|
if gajim.ZEROCONF_ACC_NAME in list_no_log_for:
|
||||||
|
list_no_log_for.remove(gajim.ZEROCONF_ACC_NAME)
|
||||||
|
if not self.xml.get_widget('log_history_checkbutton').get_active():
|
||||||
|
list_no_log_for.append(gajim.ZEROCONF_ACC_NAME)
|
||||||
|
config['no_log_for'] = ' '.join(list_no_log_for)
|
||||||
|
|
||||||
|
st = self.xml.get_widget('sync_with_global_status_checkbutton').\
|
||||||
|
get_active()
|
||||||
|
config['sync_with_global_status'] = st
|
||||||
|
|
||||||
|
st = self.xml.get_widget('first_name_entry').get_text()
|
||||||
|
config['zeroconf_first_name'] = st.decode('utf-8')
|
||||||
|
|
||||||
|
st = self.xml.get_widget('last_name_entry').get_text()
|
||||||
|
config['zeroconf_last_name'] = st.decode('utf-8')
|
||||||
|
|
||||||
|
st = self.xml.get_widget('jabber_id_entry').get_text()
|
||||||
|
config['zeroconf_jabber_id'] = st.decode('utf-8')
|
||||||
|
|
||||||
|
st = self.xml.get_widget('email_entry').get_text()
|
||||||
|
config['zeroconf_email'] = st.decode('utf-8')
|
||||||
|
|
||||||
|
use_custom_port = self.xml.get_widget('custom_port_checkbutton').\
|
||||||
|
get_active()
|
||||||
|
config['use_custom_host'] = use_custom_port
|
||||||
|
|
||||||
|
old_port = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME,
|
||||||
|
'custom_port')
|
||||||
|
if use_custom_port:
|
||||||
|
port = self.xml.get_widget('custom_port_entry').get_text()
|
||||||
|
else:
|
||||||
|
port = 5298
|
||||||
|
|
||||||
|
config['custom_port'] = port
|
||||||
|
|
||||||
|
config['keyname'] = self.xml.get_widget('gpg_name_label').get_text().\
|
||||||
|
decode('utf-8')
|
||||||
|
if config['keyname'] == '': # no key selected
|
||||||
|
config['keyid'] = ''
|
||||||
|
config['savegpgpass'] = False
|
||||||
|
config['gpgpassword'] = ''
|
||||||
|
else:
|
||||||
|
config['keyid'] = self.xml.get_widget('gpg_key_label').get_text().\
|
||||||
|
decode('utf-8')
|
||||||
|
config['savegpgpass'] = self.xml.get_widget(
|
||||||
|
'gpg_save_password_checkbutton').get_active()
|
||||||
|
config['gpgpassword'] = self.xml.get_widget('gpg_password_entry'
|
||||||
|
).get_text().decode('utf-8')
|
||||||
|
|
||||||
|
reconnect = False
|
||||||
|
for opt in ('zeroconf_first_name','zeroconf_last_name',
|
||||||
|
'zeroconf_jabber_id', 'zeroconf_email', 'custom_port'):
|
||||||
|
if gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, opt) != \
|
||||||
|
config[opt]:
|
||||||
|
reconnect = True
|
||||||
|
|
||||||
|
for opt in config:
|
||||||
|
gajim.config.set_per('accounts', gajim.ZEROCONF_ACC_NAME, opt,
|
||||||
|
config[opt])
|
||||||
|
|
||||||
|
if gajim.connections.has_key(gajim.ZEROCONF_ACC_NAME):
|
||||||
|
if port != old_port or reconnect:
|
||||||
|
gajim.connections[gajim.ZEROCONF_ACC_NAME].update_details()
|
||||||
|
|
||||||
|
self.window.destroy()
|
||||||
|
|
||||||
|
def on_gpg_choose_button_clicked(self, widget, data = None):
|
||||||
|
if gajim.connections.has_key(gajim.ZEROCONF_ACC_NAME):
|
||||||
|
secret_keys = gajim.connections[gajim.ZEROCONF_ACC_NAME].\
|
||||||
|
ask_gpg_secrete_keys()
|
||||||
|
|
||||||
|
# self.account is None and/or gajim.connections is {}
|
||||||
|
else:
|
||||||
|
if gajim.HAVE_GPG:
|
||||||
|
secret_keys = GnuPG.GnuPG().get_secret_keys()
|
||||||
|
else:
|
||||||
|
secret_keys = []
|
||||||
|
if not secret_keys:
|
||||||
|
dialogs.ErrorDialog(_('Failed to get secret keys'),
|
||||||
|
_('There was a problem retrieving your OpenPGP secret keys.'))
|
||||||
|
return
|
||||||
|
secret_keys[_('None')] = _('None')
|
||||||
|
instance = dialogs.ChooseGPGKeyDialog(_('OpenPGP Key Selection'),
|
||||||
|
_('Choose your OpenPGP key'), secret_keys)
|
||||||
|
keyID = instance.run()
|
||||||
|
if keyID is None:
|
||||||
|
return
|
||||||
|
checkbutton = self.xml.get_widget('gpg_save_password_checkbutton')
|
||||||
|
gpg_key_label = self.xml.get_widget('gpg_key_label')
|
||||||
|
gpg_name_label = self.xml.get_widget('gpg_name_label')
|
||||||
|
if keyID[0] == _('None'):
|
||||||
|
gpg_key_label.set_text(_('No key selected'))
|
||||||
|
gpg_name_label.set_text('')
|
||||||
|
checkbutton.set_sensitive(False)
|
||||||
|
self.xml.get_widget('gpg_password_entry').set_sensitive(False)
|
||||||
|
else:
|
||||||
|
gpg_key_label.set_text(keyID[0])
|
||||||
|
gpg_name_label.set_text(keyID[1])
|
||||||
|
checkbutton.set_sensitive(True)
|
||||||
|
checkbutton.set_active(False)
|
||||||
|
self.xml.get_widget('gpg_password_entry').set_text('')
|
||||||
|
|
||||||
|
def on_gpg_save_password_checkbutton_toggled(self, widget):
|
||||||
|
st = widget.get_active()
|
||||||
|
w = self.xml.get_widget('gpg_password_entry')
|
||||||
|
w.set_sensitive(bool(st))
|
||||||
|
|
||||||
|
class ManagePEPServicesWindow:
|
||||||
|
def __init__(self, account):
|
||||||
|
self.xml = gtkgui_helpers.get_glade('manage_pep_services_window.glade')
|
||||||
|
self.window = self.xml.get_widget('manage_pep_services_window')
|
||||||
|
self.window.set_transient_for(gajim.interface.roster.window)
|
||||||
|
self.xml.signal_autoconnect(self)
|
||||||
|
self.account = account
|
||||||
|
|
||||||
|
self.init_services()
|
||||||
|
self.window.show_all()
|
||||||
|
|
||||||
|
def on_manage_pep_services_window_destroy(self, widget):
|
||||||
|
'''close window'''
|
||||||
|
del gajim.interface.instances[self.account]['pep_services']
|
||||||
|
|
||||||
|
def on_ok_button_clicked(self, widget):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_cancel_button_clicked(self, widget):
|
||||||
|
self.window.destroy()
|
||||||
|
|
||||||
|
def cellrenderer_combo_edited(self, cellrenderer, path, new_text):
|
||||||
|
self.treestore[path][1] = new_text
|
||||||
|
|
||||||
|
def init_services(self):
|
||||||
|
treeview = self.xml.get_widget('services_treeview')
|
||||||
|
# service, access_model, group
|
||||||
|
self.treestore = gtk.ListStore(str, str, str)
|
||||||
|
treeview.set_model(self.treestore)
|
||||||
|
|
||||||
|
col = gtk.TreeViewColumn('Service')
|
||||||
|
treeview.append_column(col)
|
||||||
|
|
||||||
|
cellrenderer_text = gtk.CellRendererText()
|
||||||
|
col.pack_start(cellrenderer_text)
|
||||||
|
col.add_attribute(cellrenderer_text, 'text', 0)
|
||||||
|
|
||||||
|
col = gtk.TreeViewColumn('access model')
|
||||||
|
treeview.append_column(col)
|
||||||
|
|
||||||
|
model = gtk.ListStore(str)
|
||||||
|
model.append(['open'])
|
||||||
|
model.append(['presence'])
|
||||||
|
model.append(['roster'])
|
||||||
|
model.append(['whitelist'])
|
||||||
|
cellrenderer_combo = gtk.CellRendererCombo()
|
||||||
|
cellrenderer_combo.set_property('text-column', 0)
|
||||||
|
cellrenderer_combo.set_property('model', model)
|
||||||
|
cellrenderer_combo.set_property('has-entry', False)
|
||||||
|
cellrenderer_combo.set_property('editable', True)
|
||||||
|
cellrenderer_combo.connect('edited', self.cellrenderer_combo_edited)
|
||||||
|
col.pack_start(cellrenderer_combo)
|
||||||
|
col.add_attribute(cellrenderer_combo, 'text', 1)
|
||||||
|
|
||||||
|
our_jid = gajim.get_jid_from_account(self.account)
|
||||||
|
gajim.connections[self.account].discoverItems(our_jid)
|
||||||
|
|
||||||
|
def items_received(self, items):
|
||||||
|
our_jid = gajim.get_jid_from_account(self.account)
|
||||||
|
for item in items:
|
||||||
|
if 'jid' in item and item['jid'] == our_jid and 'node' in item:
|
||||||
|
# ask <configure> to have access model
|
||||||
|
gajim.connections[self.account].request_pb_configuration(
|
||||||
|
item['jid'], item['node'])
|
||||||
|
|
||||||
|
def new_service(self, node, model):
|
||||||
|
self.treestore.append([node, model, ''])
|
||||||
|
|
|
@ -61,8 +61,8 @@ class TextViewImage(gtk.Image):
|
||||||
self.anchor = anchor
|
self.anchor = anchor
|
||||||
self._selected = False
|
self._selected = False
|
||||||
self._disconnect_funcs = []
|
self._disconnect_funcs = []
|
||||||
self.connect("parent-set", self.on_parent_set)
|
self.connect('parent-set', self.on_parent_set)
|
||||||
self.connect("expose-event", self.on_expose)
|
self.connect('expose-event', self.on_expose)
|
||||||
|
|
||||||
def _get_selected(self):
|
def _get_selected(self):
|
||||||
parent = self.get_parent()
|
parent = self.get_parent()
|
||||||
|
@ -110,13 +110,13 @@ class TextViewImage(gtk.Image):
|
||||||
self._disconnect_signals()
|
self._disconnect_signals()
|
||||||
return
|
return
|
||||||
|
|
||||||
self._do_connect(parent, "style-set", self.do_queue_draw)
|
self._do_connect(parent, 'style-set', self.do_queue_draw)
|
||||||
self._do_connect(parent, "focus-in-event", self.do_queue_draw)
|
self._do_connect(parent, 'focus-in-event', self.do_queue_draw)
|
||||||
self._do_connect(parent, "focus-out-event", self.do_queue_draw)
|
self._do_connect(parent, 'focus-out-event', self.do_queue_draw)
|
||||||
|
|
||||||
textbuf = parent.get_buffer()
|
textbuf = parent.get_buffer()
|
||||||
self._do_connect(textbuf, "mark-set", self.on_mark_set)
|
self._do_connect(textbuf, 'mark-set', self.on_mark_set)
|
||||||
self._do_connect(textbuf, "mark-deleted", self.on_mark_deleted)
|
self._do_connect(textbuf, 'mark-deleted', self.on_mark_deleted)
|
||||||
|
|
||||||
def do_queue_draw(self, *args):
|
def do_queue_draw(self, *args):
|
||||||
self.queue_draw()
|
self.queue_draw()
|
||||||
|
@ -186,7 +186,7 @@ class ConversationTextview:
|
||||||
self.on_textview_button_press_event)
|
self.on_textview_button_press_event)
|
||||||
self.handlers[id] = self.tv
|
self.handlers[id] = self.tv
|
||||||
|
|
||||||
id = self.tv.connect("expose-event",
|
id = self.tv.connect('expose-event',
|
||||||
self.on_textview_expose_event)
|
self.on_textview_expose_event)
|
||||||
self.handlers[id] = self.tv
|
self.handlers[id] = self.tv
|
||||||
|
|
||||||
|
@ -213,10 +213,9 @@ class ConversationTextview:
|
||||||
|
|
||||||
colors = gajim.config.get('gc_nicknames_colors')
|
colors = gajim.config.get('gc_nicknames_colors')
|
||||||
colors = colors.split(':')
|
colors = colors.split(':')
|
||||||
for color in xrange(len(colors)):
|
for i,color in enumerate(colors):
|
||||||
tagname = 'gc_nickname_color_' + str(color)
|
tagname = 'gc_nickname_color_' + str(i)
|
||||||
tag = buffer.create_tag(tagname)
|
tag = buffer.create_tag(tagname)
|
||||||
color = colors[color]
|
|
||||||
tag.set_property('foreground', color)
|
tag.set_property('foreground', color)
|
||||||
|
|
||||||
tag = buffer.create_tag('marked')
|
tag = buffer.create_tag('marked')
|
||||||
|
@ -336,9 +335,9 @@ class ConversationTextview:
|
||||||
if None != self.smooth_id: # already scrolling
|
if None != self.smooth_id: # already scrolling
|
||||||
return False
|
return False
|
||||||
self.smooth_id = gobject.timeout_add(self.SCROLL_DELAY,
|
self.smooth_id = gobject.timeout_add(self.SCROLL_DELAY,
|
||||||
self.smooth_scroll)
|
self.smooth_scroll)
|
||||||
self.smooth_scroll_timer = Timer(self.MAX_SCROLL_TIME,
|
self.smooth_scroll_timer = Timer(self.MAX_SCROLL_TIME,
|
||||||
self.smooth_scroll_timeout)
|
self.smooth_scroll_timeout)
|
||||||
self.smooth_scroll_timer.start()
|
self.smooth_scroll_timer.start()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -353,9 +352,8 @@ class ConversationTextview:
|
||||||
adjustment.set_value(0)
|
adjustment.set_value(0)
|
||||||
return False # when called in an idle_add, just do it once
|
return False # when called in an idle_add, just do it once
|
||||||
|
|
||||||
def bring_scroll_to_end(self, diff_y = 0,\
|
def bring_scroll_to_end(self, diff_y = 0,
|
||||||
use_smooth =\
|
use_smooth=gajim.config.get('use_smooth_scrolling')):
|
||||||
gajim.config.get('use_smooth_scrolling')):
|
|
||||||
''' scrolls to the end of textview if end is not visible '''
|
''' scrolls to the end of textview if end is not visible '''
|
||||||
buffer = self.tv.get_buffer()
|
buffer = self.tv.get_buffer()
|
||||||
end_iter = buffer.get_end_iter()
|
end_iter = buffer.get_end_iter()
|
||||||
|
@ -423,7 +421,8 @@ class ConversationTextview:
|
||||||
|
|
||||||
end_iter = buffer.get_end_iter()
|
end_iter = buffer.get_end_iter()
|
||||||
before_img_iter = end_iter.copy()
|
before_img_iter = end_iter.copy()
|
||||||
before_img_iter.backward_char() # one char back (an image also takes one char)
|
# one char back (an image also takes one char)
|
||||||
|
before_img_iter.backward_char()
|
||||||
buffer.apply_tag_by_name('focus-out-line', before_img_iter, end_iter)
|
buffer.apply_tag_by_name('focus-out-line', before_img_iter, end_iter)
|
||||||
|
|
||||||
self.allow_focus_out_line = False
|
self.allow_focus_out_line = False
|
||||||
|
@ -452,7 +451,8 @@ class ConversationTextview:
|
||||||
# check if the current pointer is still over the line
|
# check if the current pointer is still over the line
|
||||||
position = self.tv.window.get_origin()
|
position = self.tv.window.get_origin()
|
||||||
self.line_tooltip.show_tooltip(_('Text below this line is what has '
|
self.line_tooltip.show_tooltip(_('Text below this line is what has '
|
||||||
'been said since the last time you paid attention to this group chat'), 8, position[1] + pointer[1])
|
'been said since the last time you paid attention to this group chat'),
|
||||||
|
8, position[1] + pointer[1])
|
||||||
|
|
||||||
def on_textview_expose_event(self, widget, event):
|
def on_textview_expose_event(self, widget, event):
|
||||||
expalloc = event.area
|
expalloc = event.area
|
||||||
|
@ -582,7 +582,8 @@ class ConversationTextview:
|
||||||
else:
|
else:
|
||||||
if dict_link.find('%s') == -1:
|
if dict_link.find('%s') == -1:
|
||||||
# we must have %s in the url if not WIKTIONARY
|
# we must have %s in the url if not WIKTIONARY
|
||||||
item = gtk.MenuItem(_('Dictionary URL is missing an "%s" and it is not WIKTIONARY'))
|
item = gtk.MenuItem(_(
|
||||||
|
'Dictionary URL is missing an "%s" and it is not WIKTIONARY'))
|
||||||
item.set_property('sensitive', False)
|
item.set_property('sensitive', False)
|
||||||
else:
|
else:
|
||||||
link = dict_link % self.selected_phrase
|
link = dict_link % self.selected_phrase
|
||||||
|
@ -639,7 +640,8 @@ class ConversationTextview:
|
||||||
if return_val: # if sth was selected when we right-clicked
|
if return_val: # if sth was selected when we right-clicked
|
||||||
# get the selected text
|
# get the selected text
|
||||||
start_sel, finish_sel = return_val[0], return_val[1]
|
start_sel, finish_sel = return_val[0], return_val[1]
|
||||||
self.selected_phrase = buffer.get_text(start_sel, finish_sel).decode('utf-8')
|
self.selected_phrase = buffer.get_text(start_sel, finish_sel).decode(
|
||||||
|
'utf-8')
|
||||||
|
|
||||||
def on_open_link_activate(self, widget, kind, text):
|
def on_open_link_activate(self, widget, kind, text):
|
||||||
helpers.launch_browser_mailer(kind, text)
|
helpers.launch_browser_mailer(kind, text)
|
||||||
|
@ -673,7 +675,8 @@ class ConversationTextview:
|
||||||
if kind == 'url':
|
if kind == 'url':
|
||||||
id = childs[0].connect('activate', self.on_copy_link_activate, text)
|
id = childs[0].connect('activate', self.on_copy_link_activate, text)
|
||||||
self.handlers[id] = childs[0]
|
self.handlers[id] = childs[0]
|
||||||
id = childs[1].connect('activate', self.on_open_link_activate, kind, text)
|
id = childs[1].connect('activate', self.on_open_link_activate, kind,
|
||||||
|
text)
|
||||||
self.handlers[id] = childs[1]
|
self.handlers[id] = childs[1]
|
||||||
childs[2].hide() # copy mail address
|
childs[2].hide() # copy mail address
|
||||||
childs[3].hide() # open mail composer
|
childs[3].hide() # open mail composer
|
||||||
|
@ -691,7 +694,8 @@ class ConversationTextview:
|
||||||
text = text.lower()
|
text = text.lower()
|
||||||
id = childs[2].connect('activate', self.on_copy_link_activate, text)
|
id = childs[2].connect('activate', self.on_copy_link_activate, text)
|
||||||
self.handlers[id] = childs[2]
|
self.handlers[id] = childs[2]
|
||||||
id = childs[3].connect('activate', self.on_open_link_activate, kind, text)
|
id = childs[3].connect('activate', self.on_open_link_activate, kind,
|
||||||
|
text)
|
||||||
self.handlers[id] = childs[3]
|
self.handlers[id] = childs[3]
|
||||||
id = childs[5].connect('activate', self.on_start_chat_activate, text)
|
id = childs[5].connect('activate', self.on_start_chat_activate, text)
|
||||||
self.handlers[id] = childs[5]
|
self.handlers[id] = childs[5]
|
||||||
|
@ -708,7 +712,8 @@ class ConversationTextview:
|
||||||
allow_add = True
|
allow_add = True
|
||||||
|
|
||||||
if allow_add:
|
if allow_add:
|
||||||
id = childs[7].connect('activate', self.on_add_to_roster_activate, text)
|
id = childs[7].connect('activate', self.on_add_to_roster_activate,
|
||||||
|
text)
|
||||||
self.handlers[id] = childs[7]
|
self.handlers[id] = childs[7]
|
||||||
childs[7].show() # show add to roster menuitem
|
childs[7].show() # show add to roster menuitem
|
||||||
else:
|
else:
|
||||||
|
@ -729,7 +734,8 @@ class ConversationTextview:
|
||||||
# we get the end of the tag
|
# we get the end of the tag
|
||||||
while not end_iter.ends_tag(texttag):
|
while not end_iter.ends_tag(texttag):
|
||||||
end_iter.forward_char()
|
end_iter.forward_char()
|
||||||
word = self.tv.get_buffer().get_text(begin_iter, end_iter).decode('utf-8')
|
word = self.tv.get_buffer().get_text(begin_iter, end_iter).decode(
|
||||||
|
'utf-8')
|
||||||
if event.button == 3: # right click
|
if event.button == 3: # right click
|
||||||
self.make_link_menu(event, kind, word)
|
self.make_link_menu(event, kind, word)
|
||||||
else:
|
else:
|
||||||
|
@ -786,16 +792,16 @@ class ConversationTextview:
|
||||||
exitcode = 0
|
exitcode = 0
|
||||||
|
|
||||||
# some latex commands are really bad
|
# some latex commands are really bad
|
||||||
blacklist = ["\\def", "\\let", "\\futurelet",
|
blacklist = ['\\def', '\\let', '\\futurelet',
|
||||||
"\\newcommand", "\\renewcomment", "\\else", "\\fi", "\\write",
|
'\\newcommand', '\\renewcomment', '\\else', '\\fi', '\\write',
|
||||||
"\\input", "\\include", "\\chardef", "\\catcode", "\\makeatletter",
|
'\\input', '\\include', '\\chardef', '\\catcode', '\\makeatletter',
|
||||||
"\\noexpand", "\\toksdef", "\\every", "\\errhelp", "\\errorstopmode",
|
'\\noexpand', '\\toksdef', '\\every', '\\errhelp', '\\errorstopmode',
|
||||||
"\\scrollmode", "\\nonstopmode", "\\batchmode", "\\read", "\\csname",
|
'\\scrollmode', '\\nonstopmode', '\\batchmode', '\\read', '\\csname',
|
||||||
"\\newhelp", "\\relax", "\\afterground", "\\afterassignment",
|
'\\newhelp', '\\relax', '\\afterground', '\\afterassignment',
|
||||||
"\\expandafter", "\\noexpand", "\\special", "\\command", "\\loop",
|
'\\expandafter', '\\noexpand', '\\special', '\\command', '\\loop',
|
||||||
"\\repeat", "\\toks", "\\output", "\\line", "\\mathcode", "\\name",
|
'\\repeat', '\\toks', '\\output', '\\line', '\\mathcode', '\\name',
|
||||||
"\\item", "\\section", "\\mbox", "\\DeclareRobustCommand", "\\[",
|
'\\item', '\\section', '\\mbox', '\\DeclareRobustCommand', '\\[',
|
||||||
"\\]"]
|
'\\]']
|
||||||
|
|
||||||
str = str[2:len(str)-2]
|
str = str[2:len(str)-2]
|
||||||
|
|
||||||
|
@ -807,16 +813,18 @@ class ConversationTextview:
|
||||||
|
|
||||||
if exitcode == 0:
|
if exitcode == 0:
|
||||||
random.seed()
|
random.seed()
|
||||||
tmpfile = os.path.join(gettempdir(), "gajimtex_" + random.randint(0,
|
tmpfile = os.path.join(gettempdir(), 'gajimtex_' + random.randint(0,
|
||||||
100).__str__())
|
100).__str__())
|
||||||
|
|
||||||
# build latex string
|
# build latex string
|
||||||
texstr = "\\documentclass[12pt]{article}\\usepackage[dvips]{graphicx}\\usepackage{amsmath}\\usepackage{amssymb}\\pagestyle{empty}"
|
texstr = '\\documentclass[12pt]{article}\\usepackage[dvips]{graphicx}'
|
||||||
texstr += "\\begin{document}\\begin{large}\\begin{gather*}"
|
texstr += '\\usepackage{amsmath}\\usepackage{amssymb}'
|
||||||
|
texstr += '\\pagestyle{empty}'
|
||||||
|
texstr += '\\begin{document}\\begin{large}\\begin{gather*}'
|
||||||
texstr += str
|
texstr += str
|
||||||
texstr += "\\end{gather*}\\end{large}\\end{document}"
|
texstr += '\\end{gather*}\\end{large}\\end{document}'
|
||||||
|
|
||||||
file = open(os.path.join(tmpfile + ".tex"), "w+")
|
file = open(os.path.join(tmpfile + '.tex'), 'w+')
|
||||||
file.write(texstr)
|
file.write(texstr)
|
||||||
file.flush()
|
file.flush()
|
||||||
file.close()
|
file.close()
|
||||||
|
@ -831,11 +839,11 @@ class ConversationTextview:
|
||||||
exitcode = p.wait()
|
exitcode = p.wait()
|
||||||
|
|
||||||
if exitcode == 0:
|
if exitcode == 0:
|
||||||
p = Popen(['convert', tmpfile + '.ps', tmpfile + '.png'],
|
p = Popen(['convert', '-alpha', 'off', tmpfile + '.ps',
|
||||||
cwd=gettempdir())
|
tmpfile + '.png'], cwd=gettempdir())
|
||||||
exitcode = p.wait()
|
exitcode = p.wait()
|
||||||
|
|
||||||
extensions = [".tex", ".log", ".aux", ".dvi", ".ps"]
|
extensions = ['.tex', '.log', '.aux', '.dvi', '.ps']
|
||||||
for ext in extensions:
|
for ext in extensions:
|
||||||
try:
|
try:
|
||||||
os.remove(tmpfile + ext)
|
os.remove(tmpfile + ext)
|
||||||
|
@ -895,11 +903,13 @@ class ConversationTextview:
|
||||||
use_other_tags = False
|
use_other_tags = False
|
||||||
elif special_text.startswith('*'): # it's a bold text
|
elif special_text.startswith('*'): # it's a bold text
|
||||||
tags.append('bold')
|
tags.append('bold')
|
||||||
if special_text[1] == '/' and special_text[-2] == '/' and len(special_text) > 4: # it's also italic
|
if special_text[1] == '/' and special_text[-2] == '/' and\
|
||||||
|
len(special_text) > 4: # it's also italic
|
||||||
tags.append('italic')
|
tags.append('italic')
|
||||||
if not show_ascii_formatting_chars:
|
if not show_ascii_formatting_chars:
|
||||||
special_text = special_text[2:-2] # remove */ /*
|
special_text = special_text[2:-2] # remove */ /*
|
||||||
elif special_text[1] == '_' and special_text[-2] == '_' and len(special_text) > 4: # it's also underlined
|
elif special_text[1] == '_' and special_text[-2] == '_' and \
|
||||||
|
len(special_text) > 4: # it's also underlined
|
||||||
tags.append('underline')
|
tags.append('underline')
|
||||||
if not show_ascii_formatting_chars:
|
if not show_ascii_formatting_chars:
|
||||||
special_text = special_text[2:-2] # remove *_ _*
|
special_text = special_text[2:-2] # remove *_ _*
|
||||||
|
@ -908,11 +918,13 @@ class ConversationTextview:
|
||||||
special_text = special_text[1:-1] # remove * *
|
special_text = special_text[1:-1] # remove * *
|
||||||
elif special_text.startswith('/'): # it's an italic text
|
elif special_text.startswith('/'): # it's an italic text
|
||||||
tags.append('italic')
|
tags.append('italic')
|
||||||
if special_text[1] == '*' and special_text[-2] == '*' and len(special_text) > 4: # it's also bold
|
if special_text[1] == '*' and special_text[-2] == '*' and \
|
||||||
|
len(special_text) > 4: # it's also bold
|
||||||
tags.append('bold')
|
tags.append('bold')
|
||||||
if not show_ascii_formatting_chars:
|
if not show_ascii_formatting_chars:
|
||||||
special_text = special_text[2:-2] # remove /* */
|
special_text = special_text[2:-2] # remove /* */
|
||||||
elif special_text[1] == '_' and special_text[-2] == '_' and len(special_text) > 4: # it's also underlined
|
elif special_text[1] == '_' and special_text[-2] == '_' and \
|
||||||
|
len(special_text) > 4: # it's also underlined
|
||||||
tags.append('underline')
|
tags.append('underline')
|
||||||
if not show_ascii_formatting_chars:
|
if not show_ascii_formatting_chars:
|
||||||
special_text = special_text[2:-2] # remove /_ _/
|
special_text = special_text[2:-2] # remove /_ _/
|
||||||
|
@ -921,11 +933,13 @@ class ConversationTextview:
|
||||||
special_text = special_text[1:-1] # remove / /
|
special_text = special_text[1:-1] # remove / /
|
||||||
elif special_text.startswith('_'): # it's an underlined text
|
elif special_text.startswith('_'): # it's an underlined text
|
||||||
tags.append('underline')
|
tags.append('underline')
|
||||||
if special_text[1] == '*' and special_text[-2] == '*' and len(special_text) > 4: # it's also bold
|
if special_text[1] == '*' and special_text[-2] == '*' and \
|
||||||
|
len(special_text) > 4: # it's also bold
|
||||||
tags.append('bold')
|
tags.append('bold')
|
||||||
if not show_ascii_formatting_chars:
|
if not show_ascii_formatting_chars:
|
||||||
special_text = special_text[2:-2] # remove _* *_
|
special_text = special_text[2:-2] # remove _* *_
|
||||||
elif special_text[1] == '/' and special_text[-2] == '/' and len(special_text) > 4: # it's also italic
|
elif special_text[1] == '/' and special_text[-2] == '/' and \
|
||||||
|
len(special_text) > 4: # it's also italic
|
||||||
tags.append('italic')
|
tags.append('italic')
|
||||||
if not show_ascii_formatting_chars:
|
if not show_ascii_formatting_chars:
|
||||||
special_text = special_text[2:-2] # remove _/ /_
|
special_text = special_text[2:-2] # remove _/ /_
|
||||||
|
@ -1123,8 +1137,8 @@ class ConversationTextview:
|
||||||
self.tv.display_html(xhtml.encode('utf-8'))
|
self.tv.display_html(xhtml.encode('utf-8'))
|
||||||
return
|
return
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
gajim.log.debug(str("Error processing xhtml")+str(e))
|
gajim.log.debug(str('Error processing xhtml')+str(e))
|
||||||
gajim.log.debug(str("with |"+xhtml+"|"))
|
gajim.log.debug(str('with |'+xhtml+'|'))
|
||||||
|
|
||||||
buffer = self.tv.get_buffer()
|
buffer = self.tv.get_buffer()
|
||||||
# /me is replaced by name if name is given
|
# /me is replaced by name if name is given
|
||||||
|
@ -1136,4 +1150,3 @@ class ConversationTextview:
|
||||||
# add the rest of text located in the index and after
|
# add the rest of text located in the index and after
|
||||||
end_iter = buffer.get_end_iter()
|
end_iter = buffer.get_end_iter()
|
||||||
buffer.insert_with_tags_by_name(end_iter, text[index:], *text_tags)
|
buffer.insert_with_tags_by_name(end_iter, text[index:], *text_tags)
|
||||||
|
|
||||||
|
|
|
@ -342,7 +342,7 @@ class SingleForm(gtk.Table, object):
|
||||||
for value, label in field.iter_options():
|
for value, label in field.iter_options():
|
||||||
radio = gtk.RadioButton(first_radio, label=label)
|
radio = gtk.RadioButton(first_radio, label=label)
|
||||||
radio.connect('toggled',
|
radio.connect('toggled',
|
||||||
self.on_list_single_radiobutton_toggled, field, value)
|
self.on_list_single_radiobutton_toggled, field, value)
|
||||||
if first_radio is None:
|
if first_radio is None:
|
||||||
first_radio = radio
|
first_radio = radio
|
||||||
if field.value == '': # TODO: is None when done
|
if field.value == '': # TODO: is None when done
|
||||||
|
|
244
src/dialogs.py
244
src/dialogs.py
|
@ -256,7 +256,7 @@ class PassphraseDialog:
|
||||||
self.window.destroy()
|
self.window.destroy()
|
||||||
return passphrase, checked
|
return passphrase, checked
|
||||||
|
|
||||||
def __init__(self, titletext, labeltext, checkbuttontext=None, is_modal = True,
|
def __init__(self, titletext, labeltext, checkbuttontext=None, is_modal=True,
|
||||||
ok_handler = None, cancel_handler = None):
|
ok_handler = None, cancel_handler = None):
|
||||||
self.xml = gtkgui_helpers.get_glade('passphrase_dialog.glade')
|
self.xml = gtkgui_helpers.get_glade('passphrase_dialog.glade')
|
||||||
self.window = self.xml.get_widget('passphrase_dialog')
|
self.window = self.xml.get_widget('passphrase_dialog')
|
||||||
|
@ -351,9 +351,9 @@ class ChooseGPGKeyDialog:
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
rep = self.window.run()
|
rep = self.window.run()
|
||||||
if rep == gtk.RESPONSE_OK:
|
selection = self.keys_treeview.get_selection()
|
||||||
selection = self.keys_treeview.get_selection()
|
(model, iter) = selection.get_selected()
|
||||||
(model, iter) = selection.get_selected()
|
if iter and rep == gtk.RESPONSE_OK:
|
||||||
keyID = [ model[iter][0].decode('utf-8'),
|
keyID = [ model[iter][0].decode('utf-8'),
|
||||||
model[iter][1].decode('utf-8') ]
|
model[iter][1].decode('utf-8') ]
|
||||||
else:
|
else:
|
||||||
|
@ -370,6 +370,125 @@ class ChooseGPGKeyDialog:
|
||||||
self.keys_treeview.set_cursor(path)
|
self.keys_treeview.set_cursor(path)
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeActivityDialog:
|
||||||
|
activities = [_('doing_chores'), _('drinking'), _('eating'),
|
||||||
|
_('excercising'), _('grooming'), _('having_appointment'),
|
||||||
|
_('inactive'), _('relaxing'), _('talking'), _('traveling'),
|
||||||
|
_('working'), ]
|
||||||
|
subactivities = [_('at_the_spa'), _('brushing_teeth'),
|
||||||
|
_('buying_groceries'), _('cleaning'), _('coding'),
|
||||||
|
_('commuting'), _('cooking'), _('cycling'), _('day_off'),
|
||||||
|
_('doing_maintenance'), _('doing_the_dishes'),
|
||||||
|
_('doing_the_laundry'), _('driving'), _('gaming'),
|
||||||
|
_('gardening'), _('getting_a_haircut'), _('going_out'),
|
||||||
|
_('hanging_out'), _('having_a_beer'), _('having_a_snack'),
|
||||||
|
_('having_breakfast'), _('having_coffee'),
|
||||||
|
_('having_dinner'), _('having_lunch'), _('having_tea'),
|
||||||
|
_('hiking'), _('in_a_car'), _('in_a_meeting'),
|
||||||
|
_('in_real_life'), _('jogging'), _('on_a_bus'),
|
||||||
|
_('on_a_plane'), _('on_a_train'), _('on_a_trip'),
|
||||||
|
_('on_the_phone'), _('on_vacation'), _('other'),
|
||||||
|
_('partying'), _('playing_sports'), _('reading'),
|
||||||
|
_('rehearsing'), _('running'), _('running_an_errand'),
|
||||||
|
_('scheduled_holiday'), _('shaving'), _('shopping'),
|
||||||
|
_('skiing'), _('sleeping'), _('socializing'),
|
||||||
|
_('studying'), _('sunbathing'), _('swimming'),
|
||||||
|
_('taking_a_bath'), _('taking_a_shower'), _('walking'),
|
||||||
|
_('walking_the_dog'), _('watching_tv'),
|
||||||
|
_('watching_a_movie'), _('working_out'), _('writing'), ]
|
||||||
|
def __init__(self, account):
|
||||||
|
self.account = account
|
||||||
|
self.xml = gtkgui_helpers.get_glade('change_activity_dialog.glade')
|
||||||
|
self.window = self.xml.get_widget('change_activity_dialog')
|
||||||
|
self.window.set_transient_for(gajim.interface.roster.window)
|
||||||
|
self.window.set_title(_('Activity'))
|
||||||
|
|
||||||
|
self.entry = self.xml.get_widget('entry')
|
||||||
|
|
||||||
|
self.combo1 = self.xml.get_widget('combobox1')
|
||||||
|
self.liststore1 = gtk.ListStore(str)
|
||||||
|
self.combo1.set_model(self.liststore1)
|
||||||
|
|
||||||
|
for activity in self.activities:
|
||||||
|
self.liststore1.append((activity,))
|
||||||
|
|
||||||
|
cellrenderertext = gtk.CellRendererText()
|
||||||
|
self.combo1.pack_start(cellrenderertext, True)
|
||||||
|
self.combo1.add_attribute(cellrenderertext, 'text', 0)
|
||||||
|
|
||||||
|
self.combo2 = self.xml.get_widget('combobox2')
|
||||||
|
self.liststore2 = gtk.ListStore(str)
|
||||||
|
self.combo2.set_model(self.liststore2)
|
||||||
|
|
||||||
|
for subactivity in self.subactivities:
|
||||||
|
self.liststore2.append((subactivity,))
|
||||||
|
|
||||||
|
cellrenderertext = gtk.CellRendererText()
|
||||||
|
self.combo2.pack_start(cellrenderertext, True)
|
||||||
|
self.combo2.add_attribute(cellrenderertext, 'text', 0)
|
||||||
|
|
||||||
|
self.xml.signal_autoconnect(self)
|
||||||
|
self.window.show_all()
|
||||||
|
|
||||||
|
def on_ok_button_clicked(self, widget):
|
||||||
|
'''Return activity and messsage (None if no activity selected)'''
|
||||||
|
activity = None
|
||||||
|
subactivity = None
|
||||||
|
message = None
|
||||||
|
active1 = self.combo1.get_active()
|
||||||
|
active2 = self.combo2.get_active()
|
||||||
|
if active1 > -1:
|
||||||
|
activity = self.liststore1[active1][0].decode('utf-8')
|
||||||
|
if active2 > -1:
|
||||||
|
subactivity = self.liststore2[active2][0].decode('utf-8')
|
||||||
|
message = self.entry.get_text().decode('utf-8')
|
||||||
|
from common import pep
|
||||||
|
pep.user_send_activity(self.account, activity,
|
||||||
|
subactivity, message)
|
||||||
|
self.window.destroy()
|
||||||
|
|
||||||
|
def on_cancel_button_clicked(self, widget):
|
||||||
|
self.window.destroy()
|
||||||
|
|
||||||
|
class ChangeMoodDialog:
|
||||||
|
moods = [_('afraid'), _('amazed'), _('angry'), _('annoyed'), _('anxious'), _('aroused'), _('ashamed'), _('bored'), _('brave'), _('calm'), _('cold'), _('confused'), _('contented'), _('cranky'), _('curious'), _('depressed'), _('disappointed'), _('disgusted'), _('distracted'), _('embarrassed'), _('excited'), _('flirtatious'), _('frustrated'), _('grumpy'), _('guilty'), _('happy'), _('hot'), _('humbled'), _('humiliated'), _('hungry'), _('hurt'), _('impressed'), _('in_awe'), _('in_love'), _('indignant'), _('interested'), _('intoxicated'), _('invincible'), _('jealous'), _('lonely'), _('mean'), _('moody'), _('nervous'), _('neutral'), _('offended'), _('playful'), _('proud'), _('relieved'), _('remorseful'), _('restless'), _('sad'), _('sarcastic'), _('serious'), _('shocked'), _('shy'), _('sick'), _('sleepy'), _('stressed'), _('surprised'), _('thirsty'), _('worried')]
|
||||||
|
def __init__(self, account):
|
||||||
|
self.account = account
|
||||||
|
self.xml = gtkgui_helpers.get_glade('change_mood_dialog.glade')
|
||||||
|
self.window = self.xml.get_widget('change_mood_dialog')
|
||||||
|
self.window.set_transient_for(gajim.interface.roster.window)
|
||||||
|
self.window.set_title(_('Mood'))
|
||||||
|
|
||||||
|
self.entry = self.xml.get_widget('entry')
|
||||||
|
|
||||||
|
self.combo = self.xml.get_widget('combobox')
|
||||||
|
self.liststore = gtk.ListStore(str)
|
||||||
|
self.combo.set_model(self.liststore)
|
||||||
|
|
||||||
|
for mood in self.moods:
|
||||||
|
self.liststore.append((mood,))
|
||||||
|
|
||||||
|
cellrenderertext = gtk.CellRendererText()
|
||||||
|
self.combo.pack_start(cellrenderertext, True)
|
||||||
|
self.combo.add_attribute(cellrenderertext, 'text', 0)
|
||||||
|
self.xml.signal_autoconnect(self)
|
||||||
|
self.window.show_all()
|
||||||
|
|
||||||
|
def on_ok_button_clicked(self, widget):
|
||||||
|
'''Return mood and messsage (None if no mood selected)'''
|
||||||
|
mood = None
|
||||||
|
message = None
|
||||||
|
active = self.combo.get_active()
|
||||||
|
if active > -1:
|
||||||
|
mood = self.liststore[active][0].decode('utf-8')
|
||||||
|
message = self.entry.get_text().decode('utf-8')
|
||||||
|
from common import pep
|
||||||
|
pep.user_send_mood(self.account, mood, message)
|
||||||
|
self.window.destroy()
|
||||||
|
|
||||||
|
def on_cancel_button_clicked(self, widget):
|
||||||
|
self.window.destroy()
|
||||||
|
|
||||||
class ChangeStatusMessageDialog:
|
class ChangeStatusMessageDialog:
|
||||||
def __init__(self, show = None):
|
def __init__(self, show = None):
|
||||||
self.show = show
|
self.show = show
|
||||||
|
@ -922,7 +1041,7 @@ class HigDialog(gtk.MessageDialog):
|
||||||
gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
|
gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
|
||||||
type, buttons, message_format = pritext)
|
type, buttons, message_format = pritext)
|
||||||
|
|
||||||
self.format_secondary_text(sectext)
|
self.format_secondary_markup(sectext)
|
||||||
|
|
||||||
buttons = self.action_area.get_children()
|
buttons = self.action_area.get_children()
|
||||||
possible_responses = {gtk.STOCK_OK: on_response_ok,
|
possible_responses = {gtk.STOCK_OK: on_response_ok,
|
||||||
|
@ -1101,15 +1220,47 @@ class ErrorDialog(HigDialog):
|
||||||
self.popup()
|
self.popup()
|
||||||
|
|
||||||
class YesNoDialog(HigDialog):
|
class YesNoDialog(HigDialog):
|
||||||
def __init__(self, pritext, sectext='', on_response_yes = None,
|
def __init__(self, pritext, sectext='', checktext='', on_response_yes=None,
|
||||||
on_response_no = None):
|
on_response_no=None):
|
||||||
'''HIG compliant YesNo dialog.'''
|
'''HIG compliant YesNo dialog.'''
|
||||||
|
self.user_response_yes = on_response_yes
|
||||||
|
self.user_response_no = on_response_no
|
||||||
HigDialog.__init__( self, None,
|
HigDialog.__init__( self, None,
|
||||||
gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, pritext, sectext,
|
gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, pritext, sectext,
|
||||||
on_response_yes = on_response_yes, on_response_no = on_response_no)
|
on_response_yes=self.on_response_yes,
|
||||||
|
on_response_no=self.on_response_no)
|
||||||
|
|
||||||
|
if checktext:
|
||||||
|
self.checkbutton = gtk.CheckButton(checktext)
|
||||||
|
self.vbox.pack_start(self.checkbutton, expand=False, fill=True)
|
||||||
|
else:
|
||||||
|
self.checkbutton = None
|
||||||
self.set_modal(False)
|
self.set_modal(False)
|
||||||
self.popup()
|
self.popup()
|
||||||
|
|
||||||
|
def on_response_yes(self, widget):
|
||||||
|
if self.user_response_yes:
|
||||||
|
if isinstance(self.user_response_yes, tuple):
|
||||||
|
self.user_response_yes[0](self.is_checked(),
|
||||||
|
*self.user_response_yes[1:])
|
||||||
|
else:
|
||||||
|
self.user_response_yes(self.is_checked())
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
def on_response_no(self, widget):
|
||||||
|
if self.user_response_no:
|
||||||
|
if isinstance(self.user_response_no, tuple):
|
||||||
|
self.user_response_no[0](*self.user_response_no[1:])
|
||||||
|
else:
|
||||||
|
self.user_response_no()
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
def is_checked(self):
|
||||||
|
''' Get active state of the checkbutton '''
|
||||||
|
if not self.checkbutton:
|
||||||
|
return False
|
||||||
|
return self.checkbutton.get_active()
|
||||||
|
|
||||||
class ConfirmationDialogCheck(ConfirmationDialog):
|
class ConfirmationDialogCheck(ConfirmationDialog):
|
||||||
'''HIG compliant confirmation dialog with checkbutton.'''
|
'''HIG compliant confirmation dialog with checkbutton.'''
|
||||||
def __init__(self, pritext, sectext='', checktext = '',
|
def __init__(self, pritext, sectext='', checktext = '',
|
||||||
|
@ -1145,7 +1296,7 @@ class ConfirmationDialogCheck(ConfirmationDialog):
|
||||||
def on_response_cancel(self, widget):
|
def on_response_cancel(self, widget):
|
||||||
if self.user_response_cancel:
|
if self.user_response_cancel:
|
||||||
if isinstance(self.user_response_cancel, tuple):
|
if isinstance(self.user_response_cancel, tuple):
|
||||||
self.user_response_cancel[0](*self.user_response_ok[1:])
|
self.user_response_cancel[0](*self.user_response_cancel[1:])
|
||||||
else:
|
else:
|
||||||
self.user_response_cancel()
|
self.user_response_cancel()
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
@ -1922,14 +2073,14 @@ class SingleMessageWindow:
|
||||||
self.completion_dict = {}
|
self.completion_dict = {}
|
||||||
self.xml.signal_autoconnect(self)
|
self.xml.signal_autoconnect(self)
|
||||||
|
|
||||||
if gajim.config.get('saveposition'):
|
# get window position and size from config
|
||||||
# get window position and size from config
|
gtkgui_helpers.resize_window(self.window,
|
||||||
gtkgui_helpers.move_window(self.window,
|
gajim.config.get('single-msg-width'),
|
||||||
gajim.config.get('single-msg-x-position'),
|
gajim.config.get('single-msg-height'))
|
||||||
gajim.config.get('single-msg-y-position'))
|
gtkgui_helpers.move_window(self.window,
|
||||||
gtkgui_helpers.resize_window(self.window,
|
gajim.config.get('single-msg-x-position'),
|
||||||
gajim.config.get('single-msg-width'),
|
gajim.config.get('single-msg-y-position'))
|
||||||
gajim.config.get('single-msg-height'))
|
|
||||||
self.window.show_all()
|
self.window.show_all()
|
||||||
|
|
||||||
def on_single_message_window_destroy(self, widget):
|
def on_single_message_window_destroy(self, widget):
|
||||||
|
@ -1940,15 +2091,14 @@ class SingleMessageWindow:
|
||||||
self.message_tv_buffer.place_cursor(end_iter)
|
self.message_tv_buffer.place_cursor(end_iter)
|
||||||
|
|
||||||
def save_pos(self):
|
def save_pos(self):
|
||||||
if gajim.config.get('saveposition'):
|
# save the window size and position
|
||||||
# save the window size and position
|
x, y = self.window.get_position()
|
||||||
x, y = self.window.get_position()
|
gajim.config.set('single-msg-x-position', x)
|
||||||
gajim.config.set('single-msg-x-position', x)
|
gajim.config.set('single-msg-y-position', y)
|
||||||
gajim.config.set('single-msg-y-position', y)
|
width, height = self.window.get_size()
|
||||||
width, height = self.window.get_size()
|
gajim.config.set('single-msg-width', width)
|
||||||
gajim.config.set('single-msg-width', width)
|
gajim.config.set('single-msg-height', height)
|
||||||
gajim.config.set('single-msg-height', height)
|
gajim.interface.save_config()
|
||||||
gajim.interface.save_config()
|
|
||||||
|
|
||||||
def on_single_message_window_delete_event(self, window, ev):
|
def on_single_message_window_delete_event(self, window, ev):
|
||||||
self.save_pos()
|
self.save_pos()
|
||||||
|
@ -3417,6 +3567,15 @@ class TransformChatToMUC:
|
||||||
|
|
||||||
self.guests_treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
|
self.guests_treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
|
||||||
|
|
||||||
|
# All contacts beside the following can be invited:
|
||||||
|
# transports, zeroconf contacts, minimized groupchats
|
||||||
|
invitable = lambda contact, contact_transport = None:\
|
||||||
|
contact.jid not in self.auto_jids and\
|
||||||
|
contact.jid != gajim.get_jid_from_account(self.account) and\
|
||||||
|
contact.jid not in gajim.interface.minimized_controls[account] and\
|
||||||
|
not contact.is_transport() and\
|
||||||
|
not contact_transport
|
||||||
|
|
||||||
# set jabber id and pseudos
|
# set jabber id and pseudos
|
||||||
for account in gajim.contacts.get_accounts():
|
for account in gajim.contacts.get_accounts():
|
||||||
if gajim.connections[account].is_zeroconf:
|
if gajim.connections[account].is_zeroconf:
|
||||||
|
@ -3425,24 +3584,20 @@ class TransformChatToMUC:
|
||||||
contact = \
|
contact = \
|
||||||
gajim.contacts.get_contact_with_highest_priority(account, jid)
|
gajim.contacts.get_contact_with_highest_priority(account, jid)
|
||||||
contact_transport = gajim.get_transport_name_from_jid(jid)
|
contact_transport = gajim.get_transport_name_from_jid(jid)
|
||||||
# do not add transports, zeroconf contacs, minimized groupchats
|
# Add contact if it can be invited
|
||||||
# and selfjid to list of invitable jids
|
if invitable(contact, contact_transport) and \
|
||||||
if contact.jid not in self.auto_jids and contact.jid != \
|
contact.show not in ('offline', 'error'):
|
||||||
gajim.get_jid_from_account(self.account) and not contact_transport \
|
img = gajim.interface.roster.jabber_state_images['16'][
|
||||||
and not contact.is_transport() and contact.jid not in \
|
contact.show]
|
||||||
gajim.interface.minimized_controls[account]:
|
name = contact.name
|
||||||
if contact.show not in ('offline', 'error'):
|
if name == '':
|
||||||
img = gajim.interface.roster.jabber_state_images['16'][
|
name = jid.split('@')[0]
|
||||||
contact.show]
|
iter = self.store.append([img.get_pixbuf(), name, jid])
|
||||||
name = contact.name
|
# preselect treeview rows
|
||||||
if name == '':
|
if self.preselected_jids and jid in self.preselected_jids:
|
||||||
name = jid.split('@')[0]
|
path = self.store.get_path(iter)
|
||||||
iter = self.store.append([img.get_pixbuf(), name, jid])
|
self.guests_treeview.get_selection().\
|
||||||
# preselect treeview rows
|
select_path(path)
|
||||||
if self.preselected_jids and jid in self.preselected_jids:
|
|
||||||
path = self.store.get_path(iter)
|
|
||||||
self.guests_treeview.get_selection().\
|
|
||||||
select_path(path)
|
|
||||||
|
|
||||||
# show all
|
# show all
|
||||||
self.window.show_all()
|
self.window.show_all()
|
||||||
|
@ -3460,7 +3615,6 @@ class TransformChatToMUC:
|
||||||
server = self.server_list_comboboxentry.get_active_text()
|
server = self.server_list_comboboxentry.get_active_text()
|
||||||
if server == '':
|
if server == '':
|
||||||
return
|
return
|
||||||
room_id = gajim.nicks[self.account] + str(randrange(9999999))
|
|
||||||
gajim.connections[self.account].check_unique_room_id_support(server, self)
|
gajim.connections[self.account].check_unique_room_id_support(server, self)
|
||||||
|
|
||||||
def unique_room_id_supported(self, server, room_id):
|
def unique_room_id_supported(self, server, room_id):
|
||||||
|
|
|
@ -46,7 +46,6 @@ import inspect
|
||||||
import weakref
|
import weakref
|
||||||
import gobject
|
import gobject
|
||||||
import gtk
|
import gtk
|
||||||
import gobject
|
|
||||||
import pango
|
import pango
|
||||||
|
|
||||||
import dialogs
|
import dialogs
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import gtk
|
import gtk
|
||||||
import gobject
|
|
||||||
import gtkgui_helpers
|
import gtkgui_helpers
|
||||||
|
|
||||||
import dialogs
|
import dialogs
|
||||||
|
@ -53,7 +52,7 @@ class FeaturesWindow:
|
||||||
_('Requires python-avahi.'),
|
_('Requires python-avahi.'),
|
||||||
_('Requires pybonjour (http://o2s.csail.mit.edu/o2s-wiki/pybonjour).')),
|
_('Requires pybonjour (http://o2s.csail.mit.edu/o2s-wiki/pybonjour).')),
|
||||||
_('gajim-remote'): (self.dbus_available,
|
_('gajim-remote'): (self.dbus_available,
|
||||||
_('A script to controle gajim via commandline.'),
|
_('A script to controle Gajim via commandline.'),
|
||||||
_('Requires python-dbus.'),
|
_('Requires python-dbus.'),
|
||||||
_('Feature not available under Windows.')),
|
_('Feature not available under Windows.')),
|
||||||
_('OpenGPG'): (self.gpg_available,
|
_('OpenGPG'): (self.gpg_available,
|
||||||
|
@ -86,14 +85,14 @@ class FeaturesWindow:
|
||||||
_('Feature not available under Windows.')),
|
_('Feature not available under Windows.')),
|
||||||
_('Trayicon'): (self.trayicon_available,
|
_('Trayicon'): (self.trayicon_available,
|
||||||
_('A icon in systemtray reflecting the current presence.'),
|
_('A icon in systemtray reflecting the current presence.'),
|
||||||
_('Requires python-gnome2-extras or compiled trayicon module from Gajim sources.'),
|
_('Requires python-gnome2-extras or compiled trayicon module from Gajim sources.'),
|
||||||
_('Requires PyGTK >= 2.10.')),
|
_('Requires PyGTK >= 2.10.')),
|
||||||
_('Idle'): (self.idle_available,
|
_('Idle'): (self.idle_available,
|
||||||
_('Ability to measure idle time, in order to set auto status.'),
|
_('Ability to measure idle time, in order to set auto status.'),
|
||||||
_('Requires compilation of the idle module from Gajim sources.'),
|
_('Requires compilation of the idle module from Gajim sources.'),
|
||||||
_('Requires compilation of the idle module from Gajim sources.')),
|
_('Requires compilation of the idle module from Gajim sources.')),
|
||||||
_('LaTeX'): (self.latex_available,
|
_('LaTeX'): (self.latex_available,
|
||||||
_('Transform LaTeX espressions between $$ $$.'),
|
_('Transform LaTeX expressions between $$ $$.'),
|
||||||
_('Requires texlive-latex-base, dvips and imagemagick. You have to set \'use_latex\' to True in the Advanced Configuration Editor.'),
|
_('Requires texlive-latex-base, dvips and imagemagick. You have to set \'use_latex\' to True in the Advanced Configuration Editor.'),
|
||||||
_('Feature not available under Windows.')),
|
_('Feature not available under Windows.')),
|
||||||
_('End to end encryption'): (self.pycrypto_available,
|
_('End to end encryption'): (self.pycrypto_available,
|
||||||
|
@ -141,6 +140,8 @@ class FeaturesWindow:
|
||||||
|
|
||||||
def on_features_treeview_cursor_changed(self, widget):
|
def on_features_treeview_cursor_changed(self, widget):
|
||||||
selection = widget.get_selection()
|
selection = widget.get_selection()
|
||||||
|
if not selection:
|
||||||
|
return
|
||||||
path = selection.get_selected_rows()[1][0]
|
path = selection.get_selected_rows()[1][0]
|
||||||
available = self.model[path][1]
|
available = self.model[path][1]
|
||||||
feature = self.model[path][0].decode('utf-8')
|
feature = self.model[path][0].decode('utf-8')
|
||||||
|
@ -178,8 +179,8 @@ class FeaturesWindow:
|
||||||
def gpg_available(self):
|
def gpg_available(self):
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
return False
|
return False
|
||||||
from common import GnuPG
|
from common import gajim
|
||||||
return GnuPG.USE_GPG
|
return gajim.HAVE_GPG
|
||||||
|
|
||||||
def network_manager_available(self):
|
def network_manager_available(self):
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
|
|
166
src/gajim.py
166
src/gajim.py
|
@ -44,7 +44,6 @@ if os.name == 'nt':
|
||||||
# os.environ['GTK_BASEPATH'] = 'gtk'
|
# os.environ['GTK_BASEPATH'] = 'gtk'
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import urllib
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
consoleloghandler = logging.StreamHandler()
|
consoleloghandler = logging.StreamHandler()
|
||||||
|
@ -222,7 +221,6 @@ import gobject
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import signal
|
import signal
|
||||||
import getopt
|
|
||||||
import time
|
import time
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
@ -457,10 +455,13 @@ class Interface:
|
||||||
|
|
||||||
def handle_event_http_auth(self, account, data):
|
def handle_event_http_auth(self, account, data):
|
||||||
#('HTTP_AUTH', account, (method, url, transaction_id, iq_obj, msg))
|
#('HTTP_AUTH', account, (method, url, transaction_id, iq_obj, msg))
|
||||||
def response(widget, account, iq_obj, answer):
|
def response(account, iq_obj, answer):
|
||||||
self.dialog.destroy()
|
self.dialog.destroy()
|
||||||
gajim.connections[account].build_http_auth_answer(iq_obj, answer)
|
gajim.connections[account].build_http_auth_answer(iq_obj, answer)
|
||||||
|
|
||||||
|
def on_yes(is_checked, account, iq_obj):
|
||||||
|
response(account, iq_obj, 'yes')
|
||||||
|
|
||||||
sec_msg = _('Do you accept this request?')
|
sec_msg = _('Do you accept this request?')
|
||||||
if gajim.get_number_of_connected_accounts() > 1:
|
if gajim.get_number_of_connected_accounts() > 1:
|
||||||
sec_msg = _('Do you accept this request on account %s?') % account
|
sec_msg = _('Do you accept this request on account %s?') % account
|
||||||
|
@ -468,8 +469,8 @@ class Interface:
|
||||||
sec_msg = data[4] + '\n' + sec_msg
|
sec_msg = data[4] + '\n' + sec_msg
|
||||||
self.dialog = dialogs.YesNoDialog(_('HTTP (%s) Authorization for %s (id: %s)') \
|
self.dialog = dialogs.YesNoDialog(_('HTTP (%s) Authorization for %s (id: %s)') \
|
||||||
% (data[0], data[1], data[2]), sec_msg,
|
% (data[0], data[1], data[2]), sec_msg,
|
||||||
on_response_yes = (response, account, data[3], 'yes'),
|
on_response_yes=(on_yes, account, data[3]),
|
||||||
on_response_no = (response, account, data[3], 'no'))
|
on_response_no=(response, account, data[3], 'no'))
|
||||||
|
|
||||||
def handle_event_error_answer(self, account, array):
|
def handle_event_error_answer(self, account, array):
|
||||||
#('ERROR_ANSWER', account, (id, jid_from, errmsg, errcode))
|
#('ERROR_ANSWER', account, (id, jid_from, errmsg, errcode))
|
||||||
|
@ -581,10 +582,11 @@ class Interface:
|
||||||
jid = array[0].split('/')[0]
|
jid = array[0].split('/')[0]
|
||||||
keyID = array[5]
|
keyID = array[5]
|
||||||
contact_nickname = array[7]
|
contact_nickname = array[7]
|
||||||
attached_keys = gajim.config.get_per('accounts', account,
|
|
||||||
'attached_gpg_keys').split()
|
# Get the proper keyID
|
||||||
if jid in attached_keys:
|
keyID = helpers.prepare_and_validate_gpg_keyID(account,
|
||||||
keyID = attached_keys[attached_keys.index(jid) + 1]
|
jid, keyID)
|
||||||
|
|
||||||
resource = array[3]
|
resource = array[3]
|
||||||
if not resource:
|
if not resource:
|
||||||
resource = ''
|
resource = ''
|
||||||
|
@ -723,7 +725,7 @@ class Interface:
|
||||||
# remove in 2007
|
# remove in 2007
|
||||||
# It's maybe a GC_NOTIFY (specialy for MSN gc)
|
# It's maybe a GC_NOTIFY (specialy for MSN gc)
|
||||||
self.handle_event_gc_notify(account, (jid, array[1], status_message,
|
self.handle_event_gc_notify(account, (jid, array[1], status_message,
|
||||||
array[3], None, None, None, None, None, None, None, None))
|
array[3], None, None, None, None, None, [], None, None))
|
||||||
|
|
||||||
|
|
||||||
def handle_event_msg(self, account, array):
|
def handle_event_msg(self, account, array):
|
||||||
|
@ -848,8 +850,14 @@ class Interface:
|
||||||
msg = message
|
msg = message
|
||||||
if subject:
|
if subject:
|
||||||
msg = _('Subject: %s') % subject + '\n' + msg
|
msg = _('Subject: %s') % subject + '\n' + msg
|
||||||
|
focused = False
|
||||||
|
if chat_control:
|
||||||
|
parent_win = chat_control.parent_win
|
||||||
|
if chat_control == parent_win.get_active_control() and \
|
||||||
|
parent_win.window.has_focus:
|
||||||
|
focused = True
|
||||||
notify.notify('new_message', jid_of_control, account, [msg_type,
|
notify.notify('new_message', jid_of_control, account, [msg_type,
|
||||||
first, nickname, msg], advanced_notif_num)
|
first, nickname, msg, focused], advanced_notif_num)
|
||||||
|
|
||||||
if self.remote_ctrl:
|
if self.remote_ctrl:
|
||||||
self.remote_ctrl.raise_signal('NewMessage', (account, array))
|
self.remote_ctrl.raise_signal('NewMessage', (account, array))
|
||||||
|
@ -949,13 +957,22 @@ class Interface:
|
||||||
self.remote_ctrl.raise_signal('Subscribed', (account, array))
|
self.remote_ctrl.raise_signal('Subscribed', (account, array))
|
||||||
|
|
||||||
def handle_event_unsubscribed(self, account, jid):
|
def handle_event_unsubscribed(self, account, jid):
|
||||||
dialogs.InformationDialog(_('Contact "%s" removed subscription from you')\
|
|
||||||
% jid, _('You will always see him or her as offline.'))
|
|
||||||
# FIXME: Per RFC 3921, we can "deny" ack as well, but the GUI does not show deny
|
|
||||||
gajim.connections[account].ack_unsubscribed(jid)
|
gajim.connections[account].ack_unsubscribed(jid)
|
||||||
if self.remote_ctrl:
|
if self.remote_ctrl:
|
||||||
self.remote_ctrl.raise_signal('Unsubscribed', (account, jid))
|
self.remote_ctrl.raise_signal('Unsubscribed', (account, jid))
|
||||||
|
|
||||||
|
contact = gajim.contacts.get_first_contact_from_jid(account, jid)
|
||||||
|
if not contact:
|
||||||
|
return
|
||||||
|
def on_yes(is_checked, list_):
|
||||||
|
self.roster.on_req_usub(None, list_)
|
||||||
|
list_ = [(contact, account)]
|
||||||
|
dialogs.YesNoDialog(
|
||||||
|
_('Contact "%s" removed subscription from you') % jid,
|
||||||
|
_('You will always see him or her as offline.\nDo you want to remove him or her from your contact list?'),
|
||||||
|
on_response_yes=(on_yes, list_))
|
||||||
|
# FIXME: Per RFC 3921, we can "deny" ack as well, but the GUI does not show deny
|
||||||
|
|
||||||
def handle_event_agent_info_error(self, account, agent):
|
def handle_event_agent_info_error(self, account, agent):
|
||||||
#('AGENT_ERROR_INFO', account, (agent))
|
#('AGENT_ERROR_INFO', account, (agent))
|
||||||
try:
|
try:
|
||||||
|
@ -999,6 +1016,11 @@ class Interface:
|
||||||
|
|
||||||
def handle_event_agent_info_items(self, account, array):
|
def handle_event_agent_info_items(self, account, array):
|
||||||
#('AGENT_INFO_ITEMS', account, (agent, node, items))
|
#('AGENT_INFO_ITEMS', account, (agent, node, items))
|
||||||
|
our_jid = gajim.get_jid_from_account(account)
|
||||||
|
if gajim.interface.instances[account].has_key('pep_services') and \
|
||||||
|
array[0] == our_jid:
|
||||||
|
gajim.interface.instances[account]['pep_services'].items_received(
|
||||||
|
array[2])
|
||||||
try:
|
try:
|
||||||
gajim.connections[account].services_cache.agent_items(array[0],
|
gajim.connections[account].services_cache.agent_items(array[0],
|
||||||
array[1], array[2])
|
array[1], array[2])
|
||||||
|
@ -1014,11 +1036,11 @@ class Interface:
|
||||||
return
|
return
|
||||||
|
|
||||||
def handle_event_new_acc_connected(self, account, array):
|
def handle_event_new_acc_connected(self, account, array):
|
||||||
#('NEW_ACC_CONNECTED', account, (infos, is_form, ssl_msg, ssl_cert,
|
#('NEW_ACC_CONNECTED', account, (infos, is_form, ssl_msg, ssl_err,
|
||||||
# ssl_fingerprint))
|
# ssl_cert, ssl_fingerprint))
|
||||||
if self.instances.has_key('account_creation_wizard'):
|
if self.instances.has_key('account_creation_wizard'):
|
||||||
self.instances['account_creation_wizard'].new_acc_connected(array[0],
|
self.instances['account_creation_wizard'].new_acc_connected(array[0],
|
||||||
array[1], array[2], array[3], array[4])
|
array[1], array[2], array[3], array[4], array[5])
|
||||||
|
|
||||||
def handle_event_new_acc_not_connected(self, account, array):
|
def handle_event_new_acc_not_connected(self, account, array):
|
||||||
#('NEW_ACC_NOT_CONNECTED', account, (reason))
|
#('NEW_ACC_NOT_CONNECTED', account, (reason))
|
||||||
|
@ -1407,14 +1429,19 @@ class Interface:
|
||||||
gajim.connections[account].gpg_passphrase(self.gpg_passphrase[keyid])
|
gajim.connections[account].gpg_passphrase(self.gpg_passphrase[keyid])
|
||||||
callback()
|
callback()
|
||||||
return
|
return
|
||||||
|
if self.gpg_dialog:
|
||||||
|
# A GPG dialog is already open, retry in 0.5 second
|
||||||
|
gobject.timeout_add(500, self.handle_event_gpg_password_required,
|
||||||
|
account, array)
|
||||||
|
return
|
||||||
password_ok = False
|
password_ok = False
|
||||||
count = 0
|
count = 0
|
||||||
title = _('Passphrase Required')
|
title = _('Passphrase Required')
|
||||||
second = _('Enter GPG key passphrase for account %s.') % account
|
second = _('Enter GPG key passphrase for account %s.') % account
|
||||||
while not password_ok and count < 3:
|
while not password_ok and count < 3:
|
||||||
count += 1
|
count += 1
|
||||||
w = dialogs.PassphraseDialog(title, second, '')
|
self.gpg_dialog = dialogs.PassphraseDialog(title, second, '')
|
||||||
passphrase, save = w.run()
|
passphrase, save = self.gpg_dialog.run()
|
||||||
if passphrase == -1:
|
if passphrase == -1:
|
||||||
# User pressed cancel
|
# User pressed cancel
|
||||||
passphrase = None
|
passphrase = None
|
||||||
|
@ -1424,6 +1451,7 @@ class Interface:
|
||||||
test_gpg_passphrase(passphrase)
|
test_gpg_passphrase(passphrase)
|
||||||
title = _('Wrong Passphrase')
|
title = _('Wrong Passphrase')
|
||||||
second = _('Please retype your GPG passphrase or press Cancel.')
|
second = _('Please retype your GPG passphrase or press Cancel.')
|
||||||
|
self.gpg_dialog = None
|
||||||
if passphrase != None:
|
if passphrase != None:
|
||||||
self.gpg_passphrase[keyid] = passphrase
|
self.gpg_passphrase[keyid] = passphrase
|
||||||
gobject.timeout_add(30000, self.forget_gpg_passphrase, keyid)
|
gobject.timeout_add(30000, self.forget_gpg_passphrase, keyid)
|
||||||
|
@ -1857,6 +1885,7 @@ class Interface:
|
||||||
# block signed in notifications for 30 seconds
|
# block signed in notifications for 30 seconds
|
||||||
gajim.block_signed_in_notifications[account] = True
|
gajim.block_signed_in_notifications[account] = True
|
||||||
self.roster.set_actions_menu_needs_rebuild()
|
self.roster.set_actions_menu_needs_rebuild()
|
||||||
|
self.roster.draw_account(account)
|
||||||
if self.sleeper.getState() != common.sleepy.STATE_UNKNOWN and \
|
if self.sleeper.getState() != common.sleepy.STATE_UNKNOWN and \
|
||||||
gajim.connections[account].connected in (2, 3):
|
gajim.connections[account].connected in (2, 3):
|
||||||
# we go online or free for chat, so we activate auto status
|
# we go online or free for chat, so we activate auto status
|
||||||
|
@ -1922,12 +1951,12 @@ class Interface:
|
||||||
negotiated, not_acceptable, ask_user = session.verify_options_bob(form)
|
negotiated, not_acceptable, ask_user = session.verify_options_bob(form)
|
||||||
|
|
||||||
if ask_user:
|
if ask_user:
|
||||||
def accept_nondefault_options(widget):
|
def accept_nondefault_options(is_checked):
|
||||||
self.dialog.destroy()
|
self.dialog.destroy()
|
||||||
negotiated.update(ask_user)
|
negotiated.update(ask_user)
|
||||||
session.respond_e2e_bob(form, negotiated, not_acceptable)
|
session.respond_e2e_bob(form, negotiated, not_acceptable)
|
||||||
|
|
||||||
def reject_nondefault_options(widget):
|
def reject_nondefault_options():
|
||||||
self.dialog.destroy()
|
self.dialog.destroy()
|
||||||
for key in ask_user.keys():
|
for key in ask_user.keys():
|
||||||
not_acceptable.append(key)
|
not_acceptable.append(key)
|
||||||
|
@ -1939,8 +1968,8 @@ class Interface:
|
||||||
%s
|
%s
|
||||||
|
|
||||||
Are these options acceptable?''') % (negotiation.describe_features(ask_user)),
|
Are these options acceptable?''') % (negotiation.describe_features(ask_user)),
|
||||||
on_response_yes = accept_nondefault_options,
|
on_response_yes=accept_nondefault_options,
|
||||||
on_response_no = reject_nondefault_options)
|
on_response_no=reject_nondefault_options)
|
||||||
else:
|
else:
|
||||||
session.respond_e2e_bob(form, negotiated, not_acceptable)
|
session.respond_e2e_bob(form, negotiated, not_acceptable)
|
||||||
|
|
||||||
|
@ -1963,7 +1992,7 @@ class Interface:
|
||||||
session.check_identity = _cb
|
session.check_identity = _cb
|
||||||
|
|
||||||
if ask_user:
|
if ask_user:
|
||||||
def accept_nondefault_options(widget):
|
def accept_nondefault_options(is_checked):
|
||||||
dialog.destroy()
|
dialog.destroy()
|
||||||
|
|
||||||
negotiated.update(ask_user)
|
negotiated.update(ask_user)
|
||||||
|
@ -1973,7 +2002,7 @@ class Interface:
|
||||||
except exceptions.NegotiationError, details:
|
except exceptions.NegotiationError, details:
|
||||||
session.fail_bad_negotiation(details)
|
session.fail_bad_negotiation(details)
|
||||||
|
|
||||||
def reject_nondefault_options(widget):
|
def reject_nondefault_options():
|
||||||
session.reject_negotiation()
|
session.reject_negotiation()
|
||||||
dialog.destroy()
|
dialog.destroy()
|
||||||
|
|
||||||
|
@ -2169,6 +2198,11 @@ class Interface:
|
||||||
_('You are already connected to this account with the same resource. Please type a new one'), input_str = gajim.connections[account].server_resource,
|
_('You are already connected to this account with the same resource. Please type a new one'), input_str = gajim.connections[account].server_resource,
|
||||||
is_modal = False, ok_handler = on_ok)
|
is_modal = False, ok_handler = on_ok)
|
||||||
|
|
||||||
|
def handle_event_pep_access_model(self, account, data):
|
||||||
|
# ('PEP_ACCESS_MODEL', account, (node, model))
|
||||||
|
if self.instances[account].has_key('pep_services'):
|
||||||
|
self.instances[account]['pep_services'].new_service(data[0], data[1])
|
||||||
|
|
||||||
def handle_event_unique_room_id_supported(self, account, data):
|
def handle_event_unique_room_id_supported(self, account, data):
|
||||||
'''Receive confirmation that unique_room_id are supported'''
|
'''Receive confirmation that unique_room_id are supported'''
|
||||||
# ('UNIQUE_ROOM_ID_SUPPORTED', server, instance, room_id)
|
# ('UNIQUE_ROOM_ID_SUPPORTED', server, instance, room_id)
|
||||||
|
@ -2181,44 +2215,76 @@ class Interface:
|
||||||
instance.unique_room_id_error(data[0])
|
instance.unique_room_id_error(data[0])
|
||||||
|
|
||||||
def handle_event_ssl_error(self, account, data):
|
def handle_event_ssl_error(self, account, data):
|
||||||
# ('SSL_ERROR', account, (text, cert, sha1_fingerprint))
|
# ('SSL_ERROR', account, (text, errnum, cert, sha1_fingerprint))
|
||||||
server = gajim.config.get_per('accounts', account, 'hostname')
|
server = gajim.config.get_per('accounts', account, 'hostname')
|
||||||
def on_ok(is_checked):
|
def on_ok(is_checked=False):
|
||||||
if is_checked:
|
if is_checked:
|
||||||
f = open(gajim.MY_CACERTS, 'a')
|
# Check if cert is already in file
|
||||||
f.write(server + '\n')
|
certs = ''
|
||||||
f.write(data[1] + '\n\n')
|
if os.path.isfile(gajim.MY_CACERTS):
|
||||||
f.close()
|
f = open(gajim.MY_CACERTS)
|
||||||
|
certs = f.read()
|
||||||
|
f.close()
|
||||||
|
if data[2] in certs:
|
||||||
|
dialogs.ErrorDialog(_('Certificate Already in File'),
|
||||||
|
_('This certificate is already in file %s, so it\'s not added again.') % gajim.MY_CACERTS)
|
||||||
|
else:
|
||||||
|
f = open(gajim.MY_CACERTS, 'a')
|
||||||
|
f.write(server + '\n')
|
||||||
|
f.write(data[2] + '\n\n')
|
||||||
|
f.close()
|
||||||
gajim.config.set_per('accounts', account, 'ssl_fingerprint_sha1',
|
gajim.config.set_per('accounts', account, 'ssl_fingerprint_sha1',
|
||||||
data[2])
|
data[3])
|
||||||
gajim.connections[account].ssl_certificate_accepted()
|
gajim.connections[account].ssl_certificate_accepted()
|
||||||
def on_cancel():
|
def on_cancel():
|
||||||
gajim.connections[account].disconnect(on_purpose=True)
|
gajim.connections[account].disconnect(on_purpose=True)
|
||||||
self.handle_event_status(account, 'offline')
|
self.handle_event_status(account, 'offline')
|
||||||
pritext = _('Error verifying SSL certificate')
|
pritext = _('Error verifying SSL certificate')
|
||||||
sectext = _('There was an error verifying the SSL certificate of your jabber server: %(error)s\nDo you still want to connect to this server?') % {'error': data[0]}
|
sectext = _('There was an error verifying the SSL certificate of your jabber server: %(error)s\nDo you still want to connect to this server?') % {'error': data[0]}
|
||||||
checktext = _('Add this certificate to the list of trusted certificates.\nSHA1 fingerprint of the certificate:\n%s') % data[2]
|
if data[1] in (18, 27):
|
||||||
dialogs.ConfirmationDialogCheck(pritext, sectext, checktext,
|
checktext = _('Add this certificate to the list of trusted certificates.\nSHA1 fingerprint of the certificate:\n%s') % data[3]
|
||||||
on_response_ok=on_ok, on_response_cancel=on_cancel)
|
dialogs.ConfirmationDialogCheck(pritext, sectext, checktext,
|
||||||
|
on_response_ok=on_ok, on_response_cancel=on_cancel)
|
||||||
|
else:
|
||||||
|
dialogs.ConfirmationDialog(pritext, sectext,
|
||||||
|
on_response_ok=on_ok, on_response_cancel=on_cancel)
|
||||||
|
|
||||||
def handle_event_fingerprint_error(self, account, data):
|
def handle_event_fingerprint_error(self, account, data):
|
||||||
# ('FINGERPRINT_ERROR', account, (fingerprint,))
|
# ('FINGERPRINT_ERROR', account, (new_fingerprint,))
|
||||||
def on_yes(widget):
|
def on_yes(is_checked):
|
||||||
dialog.destroy()
|
|
||||||
gajim.config.set_per('accounts', account, 'ssl_fingerprint_sha1',
|
gajim.config.set_per('accounts', account, 'ssl_fingerprint_sha1',
|
||||||
data[0])
|
data[0])
|
||||||
gajim.connections[account].ssl_certificate_accepted()
|
gajim.connections[account].ssl_certificate_accepted()
|
||||||
def on_no(widget):
|
def on_no():
|
||||||
dialog.destroy()
|
|
||||||
gajim.connections[account].disconnect(on_purpose=True)
|
gajim.connections[account].disconnect(on_purpose=True)
|
||||||
self.handle_event_status(account, 'offline')
|
self.handle_event_status(account, 'offline')
|
||||||
pritext = _('SSL certificate error')
|
pritext = _('SSL certificate error')
|
||||||
sectext = _('It seems SSL certificate has changed or your connection is '
|
sectext = _('It seems the SSL certificate has changed or your connection '
|
||||||
'being hacked. Do you still want to connect and update the fingerprint'
|
'is being hacked.\nOld fingerprint: %s\nNew fingerprint: %s\n\nDo you '
|
||||||
'of the certificate?')
|
'still want to connect and update the fingerprint of the certificate?'\
|
||||||
|
) % (gajim.config.get_per('accounts', account, 'ssl_fingerprint_sha1'),
|
||||||
|
data[0])
|
||||||
dialog = dialogs.YesNoDialog(pritext, sectext, on_response_yes=on_yes,
|
dialog = dialogs.YesNoDialog(pritext, sectext, on_response_yes=on_yes,
|
||||||
on_response_no=on_no)
|
on_response_no=on_no)
|
||||||
|
|
||||||
|
def handle_event_plain_connection(self, account, data):
|
||||||
|
# ('PLAIN_CONNECTION', account, (connection))
|
||||||
|
server = gajim.config.get_per('accounts', account, 'hostname')
|
||||||
|
def on_yes(is_checked):
|
||||||
|
if is_checked:
|
||||||
|
gajim.config.set_per('accounts', account,
|
||||||
|
'warn_when_insecure_connection', False)
|
||||||
|
gajim.connections[account].connection_accepted(data[0], 'tcp')
|
||||||
|
def on_no():
|
||||||
|
gajim.connections[account].disconnect(on_purpose=True)
|
||||||
|
self.handle_event_status(account, 'offline')
|
||||||
|
pritext = _('Insecure connection')
|
||||||
|
sectext = _('You are about to send your password on an insecure '
|
||||||
|
'conection. Are you sure you want to do that?')
|
||||||
|
checktext = _('Do _not ask me again')
|
||||||
|
dialog = dialogs.YesNoDialog(pritext, sectext, checktext,
|
||||||
|
on_response_yes=on_yes, on_response_no=on_no)
|
||||||
|
|
||||||
def read_sleepy(self):
|
def read_sleepy(self):
|
||||||
'''Check idle status and change that status if needed'''
|
'''Check idle status and change that status if needed'''
|
||||||
if not self.sleeper.poll():
|
if not self.sleeper.poll():
|
||||||
|
@ -2328,7 +2394,7 @@ class Interface:
|
||||||
|
|
||||||
#FIXME: recognize xmpp: and treat it specially
|
#FIXME: recognize xmpp: and treat it specially
|
||||||
|
|
||||||
links = r'\b(%s)\S*[\w\/\=]|' % prefixes
|
links = r"(www\.(?!\.)|[a-z][a-z0-9+.-]*://)[^\s<>'\"]+[^!,\.\s<>\)'\"\]]"
|
||||||
#2nd one: at_least_one_char@at_least_one_char.at_least_one_char
|
#2nd one: at_least_one_char@at_least_one_char.at_least_one_char
|
||||||
mail = r'\bmailto:\S*[^\s\W]|' r'\b\S+@\S+\.\S*[^\s\W]'
|
mail = r'\bmailto:\S*[^\s\W]|' r'\b\S+@\S+\.\S*[^\s\W]'
|
||||||
|
|
||||||
|
@ -2340,7 +2406,7 @@ class Interface:
|
||||||
|
|
||||||
latex = r'|\$\$[^$\\]*?([\]\[0-9A-Za-z()|+*/-]|[\\][\]\[0-9A-Za-z()|{}$])(.*?[^\\])?\$\$'
|
latex = r'|\$\$[^$\\]*?([\]\[0-9A-Za-z()|+*/-]|[\\][\]\[0-9A-Za-z()|{}$])(.*?[^\\])?\$\$'
|
||||||
|
|
||||||
basic_pattern = links + mail
|
basic_pattern = links + '|' + mail
|
||||||
|
|
||||||
if gajim.config.get('use_latex'):
|
if gajim.config.get('use_latex'):
|
||||||
basic_pattern += latex
|
basic_pattern += latex
|
||||||
|
@ -2551,6 +2617,7 @@ class Interface:
|
||||||
'SEARCH_FORM': self.handle_event_search_form,
|
'SEARCH_FORM': self.handle_event_search_form,
|
||||||
'SEARCH_RESULT': self.handle_event_search_result,
|
'SEARCH_RESULT': self.handle_event_search_result,
|
||||||
'RESOURCE_CONFLICT': self.handle_event_resource_conflict,
|
'RESOURCE_CONFLICT': self.handle_event_resource_conflict,
|
||||||
|
'PEP_ACCESS_MODEL': self.handle_event_pep_access_model,
|
||||||
'UNIQUE_ROOM_ID_UNSUPPORTED': \
|
'UNIQUE_ROOM_ID_UNSUPPORTED': \
|
||||||
self.handle_event_unique_room_id_unsupported,
|
self.handle_event_unique_room_id_unsupported,
|
||||||
'UNIQUE_ROOM_ID_SUPPORTED': self.handle_event_unique_room_id_supported,
|
'UNIQUE_ROOM_ID_SUPPORTED': self.handle_event_unique_room_id_supported,
|
||||||
|
@ -2558,6 +2625,7 @@ class Interface:
|
||||||
'GPG_PASSWORD_REQUIRED': self.handle_event_gpg_password_required,
|
'GPG_PASSWORD_REQUIRED': self.handle_event_gpg_password_required,
|
||||||
'SSL_ERROR': self.handle_event_ssl_error,
|
'SSL_ERROR': self.handle_event_ssl_error,
|
||||||
'FINGERPRINT_ERROR': self.handle_event_fingerprint_error,
|
'FINGERPRINT_ERROR': self.handle_event_fingerprint_error,
|
||||||
|
'PLAIN_CONNECTION': self.handle_event_plain_connection,
|
||||||
}
|
}
|
||||||
gajim.handlers = self.handlers
|
gajim.handlers = self.handlers
|
||||||
|
|
||||||
|
@ -2674,6 +2742,7 @@ class Interface:
|
||||||
self.status_sent_to_users = {}
|
self.status_sent_to_users = {}
|
||||||
self.status_sent_to_groups = {}
|
self.status_sent_to_groups = {}
|
||||||
self.gpg_passphrase = {}
|
self.gpg_passphrase = {}
|
||||||
|
self.gpg_dialog = None
|
||||||
self.default_colors = {
|
self.default_colors = {
|
||||||
'inmsgcolor': gajim.config.get('inmsgcolor'),
|
'inmsgcolor': gajim.config.get('inmsgcolor'),
|
||||||
'outmsgcolor': gajim.config.get('outmsgcolor'),
|
'outmsgcolor': gajim.config.get('outmsgcolor'),
|
||||||
|
@ -2903,7 +2972,7 @@ if __name__ == '__main__':
|
||||||
print >> sys.stderr, _('Session Management support not available (missing gnome.ui module)')
|
print >> sys.stderr, _('Session Management support not available (missing gnome.ui module)')
|
||||||
else:
|
else:
|
||||||
def die_cb(cli):
|
def die_cb(cli):
|
||||||
gtk.main_quit()
|
gajim.interface.roster.quit_gtkgui_interface()
|
||||||
gnome.program_init('gajim', gajim.version)
|
gnome.program_init('gajim', gajim.version)
|
||||||
cli = gnome.ui.master_client()
|
cli = gnome.ui.master_client()
|
||||||
cli.connect('die', die_cb)
|
cli.connect('die', die_cb)
|
||||||
|
@ -2928,4 +2997,7 @@ if __name__ == '__main__':
|
||||||
osx.init()
|
osx.init()
|
||||||
|
|
||||||
Interface()
|
Interface()
|
||||||
gtk.main()
|
try:
|
||||||
|
gtk.main()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print >> sys.stderr, 'KeyboardInterrupt'
|
||||||
|
|
|
@ -72,12 +72,19 @@ def tree_cell_data_func(column, renderer, model, iter, tv=None):
|
||||||
# reference to GroupchatControl instance (self)
|
# reference to GroupchatControl instance (self)
|
||||||
theme = gajim.config.get('roster_theme')
|
theme = gajim.config.get('roster_theme')
|
||||||
# allocate space for avatar only if needed
|
# allocate space for avatar only if needed
|
||||||
|
parent_iter = model.iter_parent(iter)
|
||||||
if isinstance(renderer, gtk.CellRendererPixbuf):
|
if isinstance(renderer, gtk.CellRendererPixbuf):
|
||||||
if model[iter][C_AVATAR]:
|
avatar_position = gajim.config.get('avatar_position_in_roster')
|
||||||
|
if avatar_position == 'right':
|
||||||
|
renderer.set_property('xalign', 1) # align pixbuf to the right
|
||||||
|
else:
|
||||||
|
renderer.set_property('xalign', 0.5)
|
||||||
|
if parent_iter and (model[iter][C_AVATAR] or avatar_position == 'left'):
|
||||||
renderer.set_property('visible', True)
|
renderer.set_property('visible', True)
|
||||||
|
renderer.set_property('width', gajim.config.get('roster_avatar_width'))
|
||||||
else:
|
else:
|
||||||
renderer.set_property('visible', False)
|
renderer.set_property('visible', False)
|
||||||
if model.iter_parent(iter):
|
if parent_iter:
|
||||||
bgcolor = gajim.config.get_per('themes', theme, 'contactbgcolor')
|
bgcolor = gajim.config.get_per('themes', theme, 'contactbgcolor')
|
||||||
if bgcolor:
|
if bgcolor:
|
||||||
renderer.set_property('cell-background', bgcolor)
|
renderer.set_property('cell-background', bgcolor)
|
||||||
|
@ -228,6 +235,12 @@ class GroupchatControl(ChatControlBase):
|
||||||
|
|
||||||
self.tooltip = tooltips.GCTooltip()
|
self.tooltip = tooltips.GCTooltip()
|
||||||
|
|
||||||
|
# nickname coloring
|
||||||
|
self.gc_count_nicknames_colors = 0
|
||||||
|
self.gc_custom_colors = {}
|
||||||
|
self.number_of_colors = len(gajim.config.get('gc_nicknames_colors').\
|
||||||
|
split(':'))
|
||||||
|
|
||||||
# connect the menuitems to their respective functions
|
# connect the menuitems to their respective functions
|
||||||
xm = gtkgui_helpers.get_glade('gc_control_popup_menu.glade')
|
xm = gtkgui_helpers.get_glade('gc_control_popup_menu.glade')
|
||||||
|
|
||||||
|
@ -301,6 +314,16 @@ class GroupchatControl(ChatControlBase):
|
||||||
# first one img, second one text, third is sec pixbuf
|
# first one img, second one text, third is sec pixbuf
|
||||||
column = gtk.TreeViewColumn()
|
column = gtk.TreeViewColumn()
|
||||||
|
|
||||||
|
def add_avatar_renderer():
|
||||||
|
renderer_pixbuf = gtk.CellRendererPixbuf() # avatar image
|
||||||
|
column.pack_start(renderer_pixbuf, expand = False)
|
||||||
|
column.add_attribute(renderer_pixbuf, 'pixbuf', C_AVATAR)
|
||||||
|
column.set_cell_data_func(renderer_pixbuf, tree_cell_data_func,
|
||||||
|
self.list_treeview)
|
||||||
|
|
||||||
|
if gajim.config.get('avatar_position_in_roster') == 'left':
|
||||||
|
add_avatar_renderer()
|
||||||
|
|
||||||
renderer_image = cell_renderer_image.CellRendererImage(0, 0) # status img
|
renderer_image = cell_renderer_image.CellRendererImage(0, 0) # status img
|
||||||
renderer_image.set_property('width', 26)
|
renderer_image.set_property('width', 26)
|
||||||
column.pack_start(renderer_image, expand = False)
|
column.pack_start(renderer_image, expand = False)
|
||||||
|
@ -315,12 +338,8 @@ class GroupchatControl(ChatControlBase):
|
||||||
column.set_cell_data_func(renderer_text, tree_cell_data_func,
|
column.set_cell_data_func(renderer_text, tree_cell_data_func,
|
||||||
self.list_treeview)
|
self.list_treeview)
|
||||||
|
|
||||||
renderer_pixbuf = gtk.CellRendererPixbuf() # avatar image
|
if gajim.config.get('avatar_position_in_roster') == 'right':
|
||||||
column.pack_start(renderer_pixbuf, expand = False)
|
add_avatar_renderer()
|
||||||
column.add_attribute(renderer_pixbuf, 'pixbuf', C_AVATAR)
|
|
||||||
column.set_cell_data_func(renderer_pixbuf, tree_cell_data_func,
|
|
||||||
self.list_treeview)
|
|
||||||
renderer_pixbuf.set_property('xalign', 1) # align pixbuf to the right
|
|
||||||
|
|
||||||
self.list_treeview.append_column(column)
|
self.list_treeview.append_column(column)
|
||||||
|
|
||||||
|
@ -639,9 +658,6 @@ class GroupchatControl(ChatControlBase):
|
||||||
fin = True
|
fin = True
|
||||||
return None
|
return None
|
||||||
|
|
||||||
gc_count_nicknames_colors = 0
|
|
||||||
gc_custom_colors = {}
|
|
||||||
|
|
||||||
def print_old_conversation(self, text, contact = '', tim = None,
|
def print_old_conversation(self, text, contact = '', tim = None,
|
||||||
xhtml = None):
|
xhtml = None):
|
||||||
if isinstance(text, str):
|
if isinstance(text, str):
|
||||||
|
@ -692,9 +708,7 @@ class GroupchatControl(ChatControlBase):
|
||||||
str(self.gc_custom_colors[contact]))
|
str(self.gc_custom_colors[contact]))
|
||||||
else:
|
else:
|
||||||
self.gc_count_nicknames_colors += 1
|
self.gc_count_nicknames_colors += 1
|
||||||
number_of_colors = len(gajim.config.get('gc_nicknames_colors').\
|
if self.gc_count_nicknames_colors == self.number_of_colors:
|
||||||
split(':'))
|
|
||||||
if self.gc_count_nicknames_colors == number_of_colors:
|
|
||||||
self.gc_count_nicknames_colors = 0
|
self.gc_count_nicknames_colors = 0
|
||||||
self.gc_custom_colors[contact] = \
|
self.gc_custom_colors[contact] = \
|
||||||
self.gc_count_nicknames_colors
|
self.gc_count_nicknames_colors
|
||||||
|
@ -813,6 +827,13 @@ class GroupchatControl(ChatControlBase):
|
||||||
return False
|
return False
|
||||||
else: # Special word == word, no char after in word
|
else: # Special word == word, no char after in word
|
||||||
return True
|
return True
|
||||||
|
for special_word in special_words:
|
||||||
|
if special_word.find(' ') > -1:
|
||||||
|
# There is a space in this special word, do a global search
|
||||||
|
# without splitting by words as previously
|
||||||
|
# We don't search this in all cases so we don't loose time
|
||||||
|
if text.find(special_word) > -1:
|
||||||
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def set_subject(self, subject):
|
def set_subject(self, subject):
|
||||||
|
@ -1979,7 +2000,8 @@ class GroupchatControl(ChatControlBase):
|
||||||
self.handlers[id] = item
|
self.handlers[id] = item
|
||||||
|
|
||||||
item = xml.get_widget('add_to_roster_menuitem')
|
item = xml.get_widget('add_to_roster_menuitem')
|
||||||
if not jid:
|
our_jid = gajim.get_jid_from_account(self.account)
|
||||||
|
if not jid or jid == our_jid:
|
||||||
item.set_sensitive(False)
|
item.set_sensitive(False)
|
||||||
else:
|
else:
|
||||||
id = item.connect('activate', self.on_add_to_roster, jid)
|
id = item.connect('activate', self.on_add_to_roster, jid)
|
||||||
|
@ -2079,12 +2101,7 @@ class GroupchatControl(ChatControlBase):
|
||||||
if not nick in gajim.contacts.get_nick_list(self.account,
|
if not nick in gajim.contacts.get_nick_list(self.account,
|
||||||
self.room_jid):
|
self.room_jid):
|
||||||
# it's a group
|
# it's a group
|
||||||
col = widget.get_column(0)
|
if x < 27:
|
||||||
avatar_cell = col.get_cell_renderers()[0]
|
|
||||||
(pos, avatar_size) = col.cell_get_position(avatar_cell)
|
|
||||||
status_cell = col.get_cell_renderers()[1]
|
|
||||||
(pos, status_size) = col.cell_get_position(status_cell)
|
|
||||||
if x > avatar_size and x < avatar_size + status_size:
|
|
||||||
if (widget.row_expanded(path)):
|
if (widget.row_expanded(path)):
|
||||||
widget.collapse_row(path)
|
widget.collapse_row(path)
|
||||||
else:
|
else:
|
||||||
|
@ -2142,6 +2159,9 @@ class GroupchatControl(ChatControlBase):
|
||||||
self.tooltip.hide_tooltip()
|
self.tooltip.hide_tooltip()
|
||||||
|
|
||||||
def show_tooltip(self, contact):
|
def show_tooltip(self, contact):
|
||||||
|
if not self.list_treeview.window:
|
||||||
|
# control has been destroyed since tooltip was requested
|
||||||
|
return
|
||||||
pointer = self.list_treeview.get_pointer()
|
pointer = self.list_treeview.get_pointer()
|
||||||
props = self.list_treeview.get_path_at_pos(pointer[0], pointer[1])
|
props = self.list_treeview.get_path_at_pos(pointer[0], pointer[1])
|
||||||
# check if the current pointer is at the same path
|
# check if the current pointer is at the same path
|
||||||
|
|
|
@ -247,6 +247,11 @@ def move_window(window, x, y):
|
||||||
x = 0
|
x = 0
|
||||||
if y < 0:
|
if y < 0:
|
||||||
y = 0
|
y = 0
|
||||||
|
w, h = window.get_size()
|
||||||
|
if x + w > screen_w:
|
||||||
|
x = screen_w - w
|
||||||
|
if y + h > screen_h:
|
||||||
|
y = screen_h - h
|
||||||
window.move(x, y)
|
window.move(x, y)
|
||||||
|
|
||||||
def resize_window(window, w, h):
|
def resize_window(window, w, h):
|
||||||
|
|
|
@ -100,7 +100,7 @@ class HistoryManager:
|
||||||
self.logs_scrolledwindow = xml.get_widget('logs_scrolledwindow')
|
self.logs_scrolledwindow = xml.get_widget('logs_scrolledwindow')
|
||||||
self.search_results_scrolledwindow = xml.get_widget(
|
self.search_results_scrolledwindow = xml.get_widget(
|
||||||
'search_results_scrolledwindow')
|
'search_results_scrolledwindow')
|
||||||
self.welcome_label = xml.get_widget('welcome_label')
|
self.welcome_vbox = xml.get_widget('welcome_vbox')
|
||||||
|
|
||||||
self.jids_already_in = [] # holds jids that we already have in DB
|
self.jids_already_in = [] # holds jids that we already have in DB
|
||||||
self.AT_LEAST_ONE_DELETION_DONE = False
|
self.AT_LEAST_ONE_DELETION_DONE = False
|
||||||
|
@ -236,7 +236,7 @@ class HistoryManager:
|
||||||
|
|
||||||
self.logs_liststore.clear() # clear the store
|
self.logs_liststore.clear() # clear the store
|
||||||
|
|
||||||
self.welcome_label.hide()
|
self.welcome_vbox.hide()
|
||||||
self.search_results_scrolledwindow.hide()
|
self.search_results_scrolledwindow.hide()
|
||||||
self.logs_scrolledwindow.show()
|
self.logs_scrolledwindow.show()
|
||||||
|
|
||||||
|
@ -579,7 +579,7 @@ class HistoryManager:
|
||||||
if text == '':
|
if text == '':
|
||||||
return
|
return
|
||||||
|
|
||||||
self.welcome_label.hide()
|
self.welcome_vbox.hide()
|
||||||
self.logs_scrolledwindow.hide()
|
self.logs_scrolledwindow.hide()
|
||||||
self.search_results_scrolledwindow.show()
|
self.search_results_scrolledwindow.show()
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ __version__ = '$Revision: 64 $'
|
||||||
|
|
||||||
from urllib import urlopen
|
from urllib import urlopen
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
from time import time, strftime
|
from time import time
|
||||||
|
|
||||||
class LastFM:
|
class LastFM:
|
||||||
# Where to fetch the played song information
|
# Where to fetch the played song information
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
## message_control.py
|
## message_control.py
|
||||||
##
|
##
|
||||||
## Copyright (C) 2006 Travis Shirk <travis@pobox.com>
|
## Copyright (C) 2006-2007 Travis Shirk <travis@pobox.com>
|
||||||
## Copyright (C) 2007 Stephan Erb <steve-e@h3c.de>
|
## Copyright (C) 2007 Stephan Erb <steve-e@h3c.de>
|
||||||
##
|
##
|
||||||
## This file is part of Gajim.
|
## This file is part of Gajim.
|
||||||
|
@ -86,7 +86,7 @@ class MessageControl:
|
||||||
pass # NOTE: Derived classes SHOULD implement this
|
pass # NOTE: Derived classes SHOULD implement this
|
||||||
|
|
||||||
def get_tab_label(self, chatstate):
|
def get_tab_label(self, chatstate):
|
||||||
'''Return a suitable the tab label string. Returns a tuple such as:
|
'''Return a suitable tab label string. Returns a tuple such as:
|
||||||
(label_str, color) either of which can be None
|
(label_str, color) either of which can be None
|
||||||
if chatstate is given that means we have HE SENT US a chatstate and
|
if chatstate is given that means we have HE SENT US a chatstate and
|
||||||
we want it displayed'''
|
we want it displayed'''
|
||||||
|
@ -126,8 +126,8 @@ class MessageControl:
|
||||||
if self.session.enable_encryption:
|
if self.session.enable_encryption:
|
||||||
was_encrypted = True
|
was_encrypted = True
|
||||||
|
|
||||||
print "starting a new session, dropping the old one!"
|
gajim.connections[self.account].delete_session(self.session.jid,
|
||||||
gajim.connections[self.account].delete_session(self.session.jid, self.session.thread_id)
|
self.session.thread_id)
|
||||||
|
|
||||||
self.session = session
|
self.session = session
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,9 @@
|
||||||
## Vincent Hanquez <tab@snarc.org>
|
## Vincent Hanquez <tab@snarc.org>
|
||||||
## Nikos Kouremenos <kourem@gmail.com>
|
## Nikos Kouremenos <kourem@gmail.com>
|
||||||
## Dimitur Kirov <dkirov@gmail.com>
|
## Dimitur Kirov <dkirov@gmail.com>
|
||||||
## Travis Shirk <travis@pobox.com>
|
|
||||||
## Norman Rasmussen <norman@rasmussen.co.za>
|
## Norman Rasmussen <norman@rasmussen.co.za>
|
||||||
## Copyright (C) 2006 Travis Shirk <travis@pobox.com>
|
## Copyright (C) 2005-2007 Travis Shirk <travis@pobox.com>
|
||||||
## Geobert Quach <geobert@gmail.com>
|
## Copyright (C) 2006 Geobert Quach <geobert@gmail.com>
|
||||||
## Copyright (C) 2007 Stephan Erb <steve-e@h3c.de>
|
## Copyright (C) 2007 Stephan Erb <steve-e@h3c.de>
|
||||||
##
|
##
|
||||||
## This file is part of Gajim.
|
## This file is part of Gajim.
|
||||||
|
@ -39,7 +38,7 @@ from common import gajim
|
||||||
|
|
||||||
####################
|
####################
|
||||||
|
|
||||||
class MessageWindow:
|
class MessageWindow(object):
|
||||||
'''Class for windows which contain message like things; chats,
|
'''Class for windows which contain message like things; chats,
|
||||||
groupchats, etc.'''
|
groupchats, etc.'''
|
||||||
|
|
||||||
|
@ -54,7 +53,7 @@ class MessageWindow:
|
||||||
CLOSE_CTRL_KEY
|
CLOSE_CTRL_KEY
|
||||||
) = range(5)
|
) = range(5)
|
||||||
|
|
||||||
def __init__(self, acct, type):
|
def __init__(self, acct, type, parent_window=None, parent_paned=None):
|
||||||
# A dictionary of dictionaries where _contacts[account][jid] == A MessageControl
|
# A dictionary of dictionaries where _contacts[account][jid] == A MessageControl
|
||||||
self._controls = {}
|
self._controls = {}
|
||||||
# If None, the window is not tied to any specific account
|
# If None, the window is not tied to any specific account
|
||||||
|
@ -68,6 +67,18 @@ class MessageWindow:
|
||||||
self.widget_name = 'message_window'
|
self.widget_name = 'message_window'
|
||||||
self.xml = gtkgui_helpers.get_glade('%s.glade' % self.widget_name)
|
self.xml = gtkgui_helpers.get_glade('%s.glade' % self.widget_name)
|
||||||
self.window = self.xml.get_widget(self.widget_name)
|
self.window = self.xml.get_widget(self.widget_name)
|
||||||
|
self.notebook = self.xml.get_widget('notebook')
|
||||||
|
self.parent_paned = None
|
||||||
|
|
||||||
|
if parent_window:
|
||||||
|
orig_window = self.window
|
||||||
|
self.window = parent_window
|
||||||
|
self.parent_paned = parent_paned
|
||||||
|
self.notebook.reparent(self.parent_paned)
|
||||||
|
self.parent_paned.pack2(self.notebook, resize=True, shrink=True)
|
||||||
|
orig_window.destroy()
|
||||||
|
del orig_window
|
||||||
|
|
||||||
id = self.window.connect('delete-event', self._on_window_delete)
|
id = self.window.connect('delete-event', self._on_window_delete)
|
||||||
self.handlers[id] = self.window
|
self.handlers[id] = self.window
|
||||||
id = self.window.connect('destroy', self._on_window_destroy)
|
id = self.window.connect('destroy', self._on_window_destroy)
|
||||||
|
@ -91,7 +102,6 @@ class MessageWindow:
|
||||||
self.window.add_events(gtk.gdk.POINTER_MOTION_MASK)
|
self.window.add_events(gtk.gdk.POINTER_MOTION_MASK)
|
||||||
self.alignment = self.xml.get_widget('alignment')
|
self.alignment = self.xml.get_widget('alignment')
|
||||||
|
|
||||||
self.notebook = self.xml.get_widget('notebook')
|
|
||||||
id = self.notebook.connect('switch-page',
|
id = self.notebook.connect('switch-page',
|
||||||
self._on_notebook_switch_page)
|
self._on_notebook_switch_page)
|
||||||
self.handlers[id] = self.notebook
|
self.handlers[id] = self.notebook
|
||||||
|
@ -144,6 +154,9 @@ class MessageWindow:
|
||||||
n += len(dict)
|
n += len(dict)
|
||||||
return n
|
return n
|
||||||
|
|
||||||
|
def resize(self, width, height):
|
||||||
|
gtkgui_helpers.resize_window(self.window, width, height)
|
||||||
|
|
||||||
def _on_window_focus(self, widget, event):
|
def _on_window_focus(self, widget, event):
|
||||||
# window received focus, so if we had urgency REMOVE IT
|
# window received focus, so if we had urgency REMOVE IT
|
||||||
# NOTE: we do not have to read the message (it maybe in a bg tab)
|
# NOTE: we do not have to read the message (it maybe in a bg tab)
|
||||||
|
@ -179,6 +192,8 @@ class MessageWindow:
|
||||||
for ctrl in self.controls():
|
for ctrl in self.controls():
|
||||||
ctrl.shutdown()
|
ctrl.shutdown()
|
||||||
self._controls.clear()
|
self._controls.clear()
|
||||||
|
# Clean up handlers connected to the parent window, this is important since
|
||||||
|
# self.window may be the RosterWindow
|
||||||
for i in self.handlers.keys():
|
for i in self.handlers.keys():
|
||||||
if self.handlers[i].handler_is_connected(i):
|
if self.handlers[i].handler_is_connected(i):
|
||||||
self.handlers[i].disconnect(i)
|
self.handlers[i].disconnect(i)
|
||||||
|
@ -211,7 +226,8 @@ class MessageWindow:
|
||||||
id = widget.connect('clicked', self._on_close_button_clicked, control)
|
id = widget.connect('clicked', self._on_close_button_clicked, control)
|
||||||
control.handlers[id] = widget
|
control.handlers[id] = widget
|
||||||
|
|
||||||
id = tab_label_box.connect('button-press-event', self.on_tab_eventbox_button_press_event, control.widget)
|
id = tab_label_box.connect('button-press-event', self.on_tab_eventbox_button_press_event,
|
||||||
|
control.widget)
|
||||||
control.handlers[id] = tab_label_box
|
control.handlers[id] = tab_label_box
|
||||||
self.notebook.append_page(control.widget, tab_label_box)
|
self.notebook.append_page(control.widget, tab_label_box)
|
||||||
|
|
||||||
|
@ -222,7 +238,10 @@ class MessageWindow:
|
||||||
self.setup_tab_dnd(control.widget)
|
self.setup_tab_dnd(control.widget)
|
||||||
|
|
||||||
self.redraw_tab(control)
|
self.redraw_tab(control)
|
||||||
self.window.show_all()
|
if self.parent_paned:
|
||||||
|
self.notebook.show_all()
|
||||||
|
else:
|
||||||
|
self.window.show_all()
|
||||||
# NOTE: we do not call set_control_active(True) since we don't know whether
|
# NOTE: we do not call set_control_active(True) since we don't know whether
|
||||||
# the tab is the active one.
|
# the tab is the active one.
|
||||||
self.show_title()
|
self.show_title()
|
||||||
|
@ -307,7 +326,7 @@ class MessageWindow:
|
||||||
'''When close button is pressed: close a tab'''
|
'''When close button is pressed: close a tab'''
|
||||||
self.remove_tab(control, self.CLOSE_CLOSE_BUTTON)
|
self.remove_tab(control, self.CLOSE_CLOSE_BUTTON)
|
||||||
|
|
||||||
def show_title(self, urgent = True, control = None):
|
def show_title(self, urgent=True, control=None):
|
||||||
'''redraw the window's title'''
|
'''redraw the window's title'''
|
||||||
if not control:
|
if not control:
|
||||||
control = self.get_active_control()
|
control = self.get_active_control()
|
||||||
|
@ -341,10 +360,7 @@ class MessageWindow:
|
||||||
name += '/' + control.resource
|
name += '/' + control.resource
|
||||||
|
|
||||||
window_mode = gajim.interface.msg_win_mgr.mode
|
window_mode = gajim.interface.msg_win_mgr.mode
|
||||||
|
if window_mode == MessageWindowMgr.ONE_MSG_WINDOW_PERTYPE:
|
||||||
if self.get_num_controls() == 1:
|
|
||||||
label = name
|
|
||||||
elif window_mode == MessageWindowMgr.ONE_MSG_WINDOW_PERTYPE:
|
|
||||||
# Show the plural form since number of tabs > 1
|
# Show the plural form since number of tabs > 1
|
||||||
if self.type == 'chat':
|
if self.type == 'chat':
|
||||||
label = _('Chats')
|
label = _('Chats')
|
||||||
|
@ -352,9 +368,16 @@ class MessageWindow:
|
||||||
label = _('Group Chats')
|
label = _('Group Chats')
|
||||||
else:
|
else:
|
||||||
label = _('Private Chats')
|
label = _('Private Chats')
|
||||||
|
elif window_mode == MessageWindowMgr.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER:
|
||||||
|
label = None
|
||||||
|
elif self.get_num_controls() == 1:
|
||||||
|
label = name
|
||||||
else:
|
else:
|
||||||
label = _('Messages')
|
label = _('Messages')
|
||||||
title = _('%s - Gajim') % label
|
|
||||||
|
title = 'Gajim'
|
||||||
|
if label:
|
||||||
|
title = _('%s - %s') % (label, title)
|
||||||
|
|
||||||
if window_mode == MessageWindowMgr.ONE_MSG_WINDOW_PERACCT:
|
if window_mode == MessageWindowMgr.ONE_MSG_WINDOW_PERACCT:
|
||||||
title = title + ": " + control.account
|
title = title + ": " + control.account
|
||||||
|
@ -413,7 +436,12 @@ class MessageWindow:
|
||||||
gajim.interface.msg_win_mgr._on_window_destroy(self.window)
|
gajim.interface.msg_win_mgr._on_window_destroy(self.window)
|
||||||
# dnd clean up
|
# dnd clean up
|
||||||
self.notebook.drag_dest_unset()
|
self.notebook.drag_dest_unset()
|
||||||
self.window.destroy()
|
if self.parent_paned:
|
||||||
|
# Don't close parent window, just remove the child
|
||||||
|
child = self.parent_paned.get_child2()
|
||||||
|
self.parent_paned.remove(child)
|
||||||
|
else:
|
||||||
|
self.window.destroy()
|
||||||
return # don't show_title, we are dead
|
return # don't show_title, we are dead
|
||||||
elif self.get_num_controls() == 1: # we are going from two tabs to one
|
elif self.get_num_controls() == 1: # we are going from two tabs to one
|
||||||
show_tabs_if_one_tab = gajim.config.get('tabs_always_visible')
|
show_tabs_if_one_tab = gajim.config.get('tabs_always_visible')
|
||||||
|
@ -598,8 +626,8 @@ class MessageWindow:
|
||||||
def _on_notebook_key_press(self, widget, event):
|
def _on_notebook_key_press(self, widget, event):
|
||||||
control = self.get_active_control()
|
control = self.get_active_control()
|
||||||
# Ctrl+PageUP / DOWN has to be handled by notebook
|
# Ctrl+PageUP / DOWN has to be handled by notebook
|
||||||
if event.state & gtk.gdk.CONTROL_MASK and event.keyval in (
|
if (event.state & gtk.gdk.CONTROL_MASK and
|
||||||
gtk.keysyms.Page_Down, gtk.keysyms.Page_Up):
|
event.keyval in (gtk.keysyms.Page_Down, gtk.keysyms.Page_Up)):
|
||||||
return False
|
return False
|
||||||
if isinstance(control, ChatControlBase):
|
if isinstance(control, ChatControlBase):
|
||||||
# we forwarded it to message textview
|
# we forwarded it to message textview
|
||||||
|
@ -679,36 +707,53 @@ class MessageWindow:
|
||||||
tab_label.disconnect(tab_label.dnd_handler)
|
tab_label.disconnect(tab_label.dnd_handler)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
class MessageWindowMgr:
|
class MessageWindowMgr(gobject.GObject):
|
||||||
'''A manager and factory for MessageWindow objects'''
|
'''A manager and factory for MessageWindow objects'''
|
||||||
|
__gsignals__ = {
|
||||||
|
'window-delete': (gobject.SIGNAL_RUN_LAST, None, (object,)),
|
||||||
|
}
|
||||||
|
|
||||||
# These constants map to common.config.opt_one_window_types indices
|
# These constants map to common.config.opt_one_window_types indices
|
||||||
(
|
(
|
||||||
ONE_MSG_WINDOW_NEVER,
|
ONE_MSG_WINDOW_NEVER,
|
||||||
ONE_MSG_WINDOW_ALWAYS,
|
ONE_MSG_WINDOW_ALWAYS,
|
||||||
|
ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER,
|
||||||
ONE_MSG_WINDOW_PERACCT,
|
ONE_MSG_WINDOW_PERACCT,
|
||||||
ONE_MSG_WINDOW_PERTYPE
|
ONE_MSG_WINDOW_PERTYPE,
|
||||||
) = range(4)
|
) = range(5)
|
||||||
# A key constant for the main window for all messages
|
# A key constant for the main window in ONE_MSG_WINDOW_ALWAYS mode
|
||||||
MAIN_WIN = 'main'
|
MAIN_WIN = 'main'
|
||||||
|
# A key constant for the main window in ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER mode
|
||||||
|
ROSTER_MAIN_WIN = 'roster'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, parent_window, parent_paned):
|
||||||
''' A dictionary of windows; the key depends on the config:
|
''' A dictionary of windows; the key depends on the config:
|
||||||
ONE_MSG_WINDOW_NEVER: The key is the contact JID
|
ONE_MSG_WINDOW_NEVER: The key is the contact JID
|
||||||
ONE_MSG_WINDOW_ALWAYS: The key is MessageWindowMgr.MAIN_WIN
|
ONE_MSG_WINDOW_ALWAYS: The key is MessageWindowMgr.MAIN_WIN
|
||||||
|
ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER: The key is MessageWindowMgr.MAIN_WIN
|
||||||
ONE_MSG_WINDOW_PERACCT: The key is the account name
|
ONE_MSG_WINDOW_PERACCT: The key is the account name
|
||||||
ONE_MSG_WINDOW_PERTYPE: The key is a message type constant'''
|
ONE_MSG_WINDOW_PERTYPE: The key is a message type constant'''
|
||||||
|
gobject.GObject.__init__(self)
|
||||||
self._windows = {}
|
self._windows = {}
|
||||||
|
|
||||||
# Map the mode to a int constant for frequent compares
|
# Map the mode to a int constant for frequent compares
|
||||||
mode = gajim.config.get('one_message_window')
|
mode = gajim.config.get('one_message_window')
|
||||||
self.mode = common.config.opt_one_window_types.index(mode)
|
self.mode = common.config.opt_one_window_types.index(mode)
|
||||||
|
|
||||||
|
self.parent_win = parent_window
|
||||||
|
self.parent_paned = parent_paned
|
||||||
|
|
||||||
def change_account_name(self, old_name, new_name):
|
def change_account_name(self, old_name, new_name):
|
||||||
for win in self.windows():
|
for win in self.windows():
|
||||||
win.change_account_name(old_name, new_name)
|
win.change_account_name(old_name, new_name)
|
||||||
|
|
||||||
def _new_window(self, acct, type):
|
def _new_window(self, acct, type):
|
||||||
win = MessageWindow(acct, type)
|
parent_win = None
|
||||||
|
parent_paned = None
|
||||||
|
if self.mode == self.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER:
|
||||||
|
parent_win = self.parent_win
|
||||||
|
parent_paned = self.parent_paned
|
||||||
|
win = MessageWindow(acct, type, parent_win, parent_paned)
|
||||||
# we track the lifetime of this window
|
# we track the lifetime of this window
|
||||||
win.window.connect('delete-event', self._on_window_delete)
|
win.window.connect('delete-event', self._on_window_delete)
|
||||||
win.window.connect('destroy', self._on_window_destroy)
|
win.window.connect('destroy', self._on_window_destroy)
|
||||||
|
@ -729,7 +774,7 @@ class MessageWindowMgr:
|
||||||
def has_window(self, jid, acct):
|
def has_window(self, jid, acct):
|
||||||
return self.get_window(jid, acct) != None
|
return self.get_window(jid, acct) != None
|
||||||
|
|
||||||
def one_window_opened(self, contact, acct, type):
|
def one_window_opened(self, contact=None, acct=None, type=None):
|
||||||
try:
|
try:
|
||||||
return self._windows[self._mode_to_key(contact, acct, type)] != None
|
return self._windows[self._mode_to_key(contact, acct, type)] != None
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -737,12 +782,13 @@ class MessageWindowMgr:
|
||||||
|
|
||||||
def _resize_window(self, win, acct, type):
|
def _resize_window(self, win, acct, type):
|
||||||
'''Resizes window according to config settings'''
|
'''Resizes window according to config settings'''
|
||||||
if not gajim.config.get('saveposition'):
|
if self.mode in (self.ONE_MSG_WINDOW_ALWAYS,
|
||||||
return
|
self.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER):
|
||||||
|
|
||||||
if self.mode == self.ONE_MSG_WINDOW_ALWAYS:
|
|
||||||
size = (gajim.config.get('msgwin-width'),
|
size = (gajim.config.get('msgwin-width'),
|
||||||
gajim.config.get('msgwin-height'))
|
gajim.config.get('msgwin-height'))
|
||||||
|
if self.mode == self.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER:
|
||||||
|
parent_size = win.window.get_size()
|
||||||
|
size = (parent_size[0] + size[0], size[1])
|
||||||
elif self.mode == self.ONE_MSG_WINDOW_PERACCT:
|
elif self.mode == self.ONE_MSG_WINDOW_PERACCT:
|
||||||
size = (gajim.config.get_per('accounts', acct, 'msgwin-width'),
|
size = (gajim.config.get_per('accounts', acct, 'msgwin-width'),
|
||||||
gajim.config.get_per('accounts', acct, 'msgwin-height'))
|
gajim.config.get_per('accounts', acct, 'msgwin-height'))
|
||||||
|
@ -754,13 +800,12 @@ class MessageWindowMgr:
|
||||||
size = (gajim.config.get(opt_width), gajim.config.get(opt_height))
|
size = (gajim.config.get(opt_width), gajim.config.get(opt_height))
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
win.resize(size[0], size[1])
|
||||||
gtkgui_helpers.resize_window(win.window, size[0], size[1])
|
|
||||||
|
|
||||||
def _position_window(self, win, acct, type):
|
def _position_window(self, win, acct, type):
|
||||||
'''Moves window according to config settings'''
|
'''Moves window according to config settings'''
|
||||||
if not gajim.config.get('saveposition') or\
|
if (self.mode in [self.ONE_MSG_WINDOW_NEVER,
|
||||||
self.mode == self.ONE_MSG_WINDOW_NEVER:
|
self.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER]):
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.mode == self.ONE_MSG_WINDOW_ALWAYS:
|
if self.mode == self.ONE_MSG_WINDOW_ALWAYS:
|
||||||
|
@ -782,21 +827,22 @@ class MessageWindowMgr:
|
||||||
key = acct + contact.jid
|
key = acct + contact.jid
|
||||||
if resource:
|
if resource:
|
||||||
key += '/' + resource
|
key += '/' + resource
|
||||||
|
return key
|
||||||
elif self.mode == self.ONE_MSG_WINDOW_ALWAYS:
|
elif self.mode == self.ONE_MSG_WINDOW_ALWAYS:
|
||||||
key = self.MAIN_WIN
|
return self.MAIN_WIN
|
||||||
|
elif self.mode == self.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER:
|
||||||
|
return self.ROSTER_MAIN_WIN
|
||||||
elif self.mode == self.ONE_MSG_WINDOW_PERACCT:
|
elif self.mode == self.ONE_MSG_WINDOW_PERACCT:
|
||||||
key = acct
|
return acct
|
||||||
elif self.mode == self.ONE_MSG_WINDOW_PERTYPE:
|
elif self.mode == self.ONE_MSG_WINDOW_PERTYPE:
|
||||||
key = type
|
return type
|
||||||
return key
|
|
||||||
|
|
||||||
def create_window(self, contact, acct, type, resource = None):
|
def create_window(self, contact, acct, type, resource = None):
|
||||||
key = None
|
|
||||||
win_acct = None
|
win_acct = None
|
||||||
win_type = None
|
win_type = None
|
||||||
win_role = 'messages'
|
win_role = None # X11 window role
|
||||||
|
|
||||||
key = self._mode_to_key(contact, acct, type, resource)
|
win_key = self._mode_to_key(contact, acct, type, resource)
|
||||||
if self.mode == self.ONE_MSG_WINDOW_PERACCT:
|
if self.mode == self.ONE_MSG_WINDOW_PERACCT:
|
||||||
win_acct = acct
|
win_acct = acct
|
||||||
win_role = acct
|
win_role = acct
|
||||||
|
@ -806,21 +852,24 @@ class MessageWindowMgr:
|
||||||
elif self.mode == self.ONE_MSG_WINDOW_NEVER:
|
elif self.mode == self.ONE_MSG_WINDOW_NEVER:
|
||||||
win_type = type
|
win_type = type
|
||||||
win_role = contact.jid
|
win_role = contact.jid
|
||||||
|
elif self.mode == self.ONE_MSG_WINDOW_ALWAYS:
|
||||||
|
win_role = 'messages'
|
||||||
|
|
||||||
win = None
|
win = None
|
||||||
try:
|
try:
|
||||||
win = self._windows[key]
|
win = self._windows[win_key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
win = self._new_window(win_acct, win_type)
|
win = self._new_window(win_acct, win_type)
|
||||||
|
|
||||||
win.window.set_role(win_role)
|
if win_role:
|
||||||
|
win.window.set_role(win_role)
|
||||||
|
|
||||||
# Position and size window based on saved state and window mode
|
# Position and size window based on saved state and window mode
|
||||||
if not self.one_window_opened(contact, acct, type):
|
if not self.one_window_opened(contact, acct, type):
|
||||||
self._position_window(win, acct, type)
|
|
||||||
self._resize_window(win, acct, type)
|
self._resize_window(win, acct, type)
|
||||||
|
self._position_window(win, acct, type)
|
||||||
|
|
||||||
self._windows[key] = win
|
self._windows[win_key] = win
|
||||||
return win
|
return win
|
||||||
|
|
||||||
def change_key(self, old_jid, new_jid, acct):
|
def change_key(self, old_jid, new_jid, acct):
|
||||||
|
@ -842,6 +891,7 @@ class MessageWindowMgr:
|
||||||
def _on_window_destroy(self, win):
|
def _on_window_destroy(self, win):
|
||||||
for k in self._windows.keys():
|
for k in self._windows.keys():
|
||||||
if self._windows[k].window == win:
|
if self._windows[k].window == win:
|
||||||
|
self.emit('window-delete', self._windows[k])
|
||||||
del self._windows[k]
|
del self._windows[k]
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -870,17 +920,16 @@ class MessageWindowMgr:
|
||||||
for c in w.controls():
|
for c in w.controls():
|
||||||
yield c
|
yield c
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self, width_adjust=0):
|
||||||
for w in self.windows():
|
for w in self.windows():
|
||||||
self.save_state(w)
|
self.save_state(w, width_adjust)
|
||||||
w.window.hide()
|
if not w.parent_paned:
|
||||||
w.window.destroy()
|
w.window.hide()
|
||||||
|
w.window.destroy()
|
||||||
|
|
||||||
gajim.interface.save_config()
|
gajim.interface.save_config()
|
||||||
|
|
||||||
def save_state(self, msg_win):
|
def save_state(self, msg_win, width_adjust=0):
|
||||||
if not gajim.config.get('saveposition'):
|
|
||||||
return
|
|
||||||
|
|
||||||
# Save window size and position
|
# Save window size and position
|
||||||
pos_x_key = 'msgwin-x-position'
|
pos_x_key = 'msgwin-x-position'
|
||||||
pos_y_key = 'msgwin-y-position'
|
pos_y_key = 'msgwin-y-position'
|
||||||
|
@ -907,6 +956,9 @@ class MessageWindowMgr:
|
||||||
type = msg_win.type
|
type = msg_win.type
|
||||||
size_width_key = type + '-msgwin-width'
|
size_width_key = type + '-msgwin-width'
|
||||||
size_height_key = type + '-msgwin-height'
|
size_height_key = type + '-msgwin-height'
|
||||||
|
elif self.mode == self.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER:
|
||||||
|
# Ignore any hpaned width
|
||||||
|
width = msg_win.notebook.allocation.width
|
||||||
|
|
||||||
if acct:
|
if acct:
|
||||||
gajim.config.set_per('accounts', acct, size_width_key, width)
|
gajim.config.set_per('accounts', acct, size_width_key, width)
|
||||||
|
@ -917,6 +969,7 @@ class MessageWindowMgr:
|
||||||
gajim.config.set_per('accounts', acct, pos_y_key, y)
|
gajim.config.set_per('accounts', acct, pos_y_key, y)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
width += width_adjust
|
||||||
gajim.config.set(size_width_key, width)
|
gajim.config.set(size_width_key, width)
|
||||||
gajim.config.set(size_height_key, height)
|
gajim.config.set(size_height_key, height)
|
||||||
|
|
||||||
|
@ -937,17 +990,24 @@ class MessageWindowMgr:
|
||||||
|
|
||||||
controls = []
|
controls = []
|
||||||
for w in self.windows():
|
for w in self.windows():
|
||||||
w.window.hide()
|
# Note, we are taking care not to hide/delete the roster window when the
|
||||||
|
# MessageWindow is embedded.
|
||||||
|
if not w.parent_paned:
|
||||||
|
w.window.hide()
|
||||||
while w.notebook.get_n_pages():
|
while w.notebook.get_n_pages():
|
||||||
page = w.notebook.get_nth_page(0)
|
page = w.notebook.get_nth_page(0)
|
||||||
ctrl = w._widget_to_control(page)
|
ctrl = w._widget_to_control(page)
|
||||||
w.notebook.remove_page(0)
|
w.notebook.remove_page(0)
|
||||||
page.unparent()
|
page.unparent()
|
||||||
controls.append(ctrl)
|
controls.append(ctrl)
|
||||||
# Must clear _controls from window to prevent
|
# Must clear _controls from window to prevent MessageControl.shutdown calls
|
||||||
# MessageControl.shutdown calls
|
|
||||||
w._controls = {}
|
w._controls = {}
|
||||||
w.window.destroy()
|
if not w.parent_paned:
|
||||||
|
w.window.destroy()
|
||||||
|
else:
|
||||||
|
# Don't close parent window, just remove the child
|
||||||
|
child = w.parent_paned.get_child2()
|
||||||
|
w.parent_paned.remove(child)
|
||||||
|
|
||||||
self._windows = {}
|
self._windows = {}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
## You should have received a copy of the GNU General Public License
|
## You should have received a copy of the GNU General Public License
|
||||||
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
##
|
##
|
||||||
|
import os
|
||||||
import gobject
|
import gobject
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# install _() func before importing dbus_support
|
# install _() func before importing dbus_support
|
||||||
|
@ -51,6 +52,13 @@ class MusicTrackListener(gobject.GObject):
|
||||||
|
|
||||||
bus = dbus.SessionBus()
|
bus = dbus.SessionBus()
|
||||||
|
|
||||||
|
## MPRIS
|
||||||
|
bus.add_signal_receiver(self._mpris_music_track_change_cb, 'TrackChange',
|
||||||
|
'org.freedesktop.MediaPlayer')
|
||||||
|
bus.add_signal_receiver(self._mpris_playing_changed_cb, 'StatusChange',
|
||||||
|
'org.freedesktop.MediaPlayer')
|
||||||
|
|
||||||
|
|
||||||
## Muine
|
## Muine
|
||||||
bus.add_signal_receiver(self._muine_music_track_change_cb, 'SongChanged',
|
bus.add_signal_receiver(self._muine_music_track_change_cb, 'SongChanged',
|
||||||
'org.gnome.Muine.Player')
|
'org.gnome.Muine.Player')
|
||||||
|
@ -60,30 +68,32 @@ class MusicTrackListener(gobject.GObject):
|
||||||
'org.gnome.Muine.Player')
|
'org.gnome.Muine.Player')
|
||||||
|
|
||||||
## Rhythmbox
|
## Rhythmbox
|
||||||
bus.add_signal_receiver(self._rhythmbox_music_track_change_cb,
|
|
||||||
'playingUriChanged', 'org.gnome.Rhythmbox.Player')
|
|
||||||
bus.add_signal_receiver(self._player_name_owner_changed,
|
bus.add_signal_receiver(self._player_name_owner_changed,
|
||||||
'NameOwnerChanged', 'org.freedesktop.DBus', arg0='org.gnome.Rhythmbox')
|
'NameOwnerChanged', 'org.freedesktop.DBus', arg0='org.gnome.Rhythmbox')
|
||||||
bus.add_signal_receiver(self._player_playing_changed_cb,
|
bus.add_signal_receiver(self._rhythmbox_playing_changed_cb,
|
||||||
'playingChanged', 'org.gnome.Rhythmbox.Player')
|
'playingChanged', 'org.gnome.Rhythmbox.Player')
|
||||||
bus.add_signal_receiver(self._player_playing_song_property_changed_cb,
|
bus.add_signal_receiver(self._player_playing_song_property_changed_cb,
|
||||||
'playingSongPropertyChanged', 'org.gnome.Rhythmbox.Player')
|
'playingSongPropertyChanged', 'org.gnome.Rhythmbox.Player')
|
||||||
|
|
||||||
## Banshee
|
## Banshee
|
||||||
banshee_bus = dbus.SessionBus()
|
# Banshee sucks because it only supports polling.
|
||||||
dubus = banshee_bus.get_object('org.freedesktop.DBus',
|
# Thus, we only register this is we are very sure that it's
|
||||||
'/org/freedesktop/dbus')
|
# installed.
|
||||||
self.dubus_methods = dbus.Interface(dubus, 'org.freedesktop.DBus')
|
if os.name == 'posix' and os.system('which banshee >/dev/null 2>&1') == 0:
|
||||||
self.current_banshee_title = ''
|
banshee_bus = dbus.SessionBus()
|
||||||
self.banshee_paused_before = False
|
dubus = banshee_bus.get_object('org.freedesktop.DBus',
|
||||||
self.banshee_is_here = False
|
'/org/freedesktop/dbus')
|
||||||
gobject.timeout_add(10000, self._check_if_banshee_bus)
|
self.dubus_methods = dbus.Interface(dubus, 'org.freedesktop.DBus')
|
||||||
if self.dubus_methods.NameHasOwner('org.gnome.Banshee'):
|
self.current_banshee_title = ''
|
||||||
self._get_banshee_bus()
|
self.banshee_paused_before = False
|
||||||
self.banshee_is_here = True
|
self.banshee_is_here = False
|
||||||
# Otherwise, it opens Banshee!
|
gobject.timeout_add(10000, self._check_if_banshee_bus)
|
||||||
self.banshee_props ={}
|
if self.dubus_methods.NameHasOwner('org.gnome.Banshee'):
|
||||||
gobject.timeout_add(1000, self._banshee_check_track_status)
|
self._get_banshee_bus()
|
||||||
|
self.banshee_is_here = True
|
||||||
|
# Otherwise, it opens Banshee!
|
||||||
|
self.banshee_props ={}
|
||||||
|
gobject.timeout_add(1000, self._banshee_check_track_status)
|
||||||
|
|
||||||
def _check_if_banshee_bus(self):
|
def _check_if_banshee_bus(self):
|
||||||
if self.dubus_methods.NameHasOwner('org.gnome.Banshee'):
|
if self.dubus_methods.NameHasOwner('org.gnome.Banshee'):
|
||||||
|
@ -116,6 +126,40 @@ class MusicTrackListener(gobject.GObject):
|
||||||
if b == 'rb:stream-song-title':
|
if b == 'rb:stream-song-title':
|
||||||
self.emit('music-track-changed', self._last_playing_music)
|
self.emit('music-track-changed', self._last_playing_music)
|
||||||
|
|
||||||
|
def _mpris_properties_extract(self, song):
|
||||||
|
info = MusicTrackInfo()
|
||||||
|
|
||||||
|
if song.has_key('title'):
|
||||||
|
info.title = song['title']
|
||||||
|
else:
|
||||||
|
info.title = ''
|
||||||
|
|
||||||
|
if song.has_key('album'):
|
||||||
|
info.album = song['album']
|
||||||
|
else:
|
||||||
|
info.album = ''
|
||||||
|
|
||||||
|
if song.has_key('artist'):
|
||||||
|
info.artist = song['artist']
|
||||||
|
else:
|
||||||
|
info.artist = ''
|
||||||
|
|
||||||
|
if song.has_key('length'):
|
||||||
|
info.duration = int(song['length'])
|
||||||
|
else:
|
||||||
|
info.duration = 0
|
||||||
|
|
||||||
|
return info
|
||||||
|
|
||||||
|
def _mpris_playing_changed_cb(self, playing):
|
||||||
|
if playing == 0:
|
||||||
|
self.emit('music-track-changed', self._last_playing_music)
|
||||||
|
else:
|
||||||
|
self.emit('music-track-changed', None)
|
||||||
|
|
||||||
|
def _mpris_music_track_change_cb(self, arg):
|
||||||
|
self._last_playing_music = self._mpris_properties_extract(arg)
|
||||||
|
|
||||||
def _muine_properties_extract(self, song_string):
|
def _muine_properties_extract(self, song_string):
|
||||||
d = dict((x.strip() for x in s1.split(':', 1)) for s1 in \
|
d = dict((x.strip() for x in s1.split(':', 1)) for s1 in \
|
||||||
song_string.split('\n'))
|
song_string.split('\n'))
|
||||||
|
@ -131,6 +175,13 @@ class MusicTrackListener(gobject.GObject):
|
||||||
info = self._muine_properties_extract(arg)
|
info = self._muine_properties_extract(arg)
|
||||||
self.emit('music-track-changed', info)
|
self.emit('music-track-changed', info)
|
||||||
|
|
||||||
|
def _rhythmbox_playing_changed_cb(self, playing):
|
||||||
|
if playing:
|
||||||
|
info = self.get_playing_track()
|
||||||
|
self.emit('music-track-changed', info)
|
||||||
|
else:
|
||||||
|
self.emit('music-track-changed', None)
|
||||||
|
|
||||||
def _rhythmbox_properties_extract(self, props):
|
def _rhythmbox_properties_extract(self, props):
|
||||||
info = MusicTrackInfo()
|
info = MusicTrackInfo()
|
||||||
info.title = props['title']
|
info.title = props['title']
|
||||||
|
@ -140,17 +191,6 @@ class MusicTrackListener(gobject.GObject):
|
||||||
info.track_number = int(props['track-number'])
|
info.track_number = int(props['track-number'])
|
||||||
return info
|
return info
|
||||||
|
|
||||||
def _rhythmbox_music_track_change_cb(self, uri):
|
|
||||||
if not uri:
|
|
||||||
return
|
|
||||||
bus = dbus.SessionBus()
|
|
||||||
rbshellobj = bus.get_object('org.gnome.Rhythmbox',
|
|
||||||
'/org/gnome/Rhythmbox/Shell')
|
|
||||||
rbshell = dbus.Interface(rbshellobj, 'org.gnome.Rhythmbox.Shell')
|
|
||||||
props = rbshell.getSongProperties(uri)
|
|
||||||
info = self._rhythmbox_properties_extract(props)
|
|
||||||
self.emit('music-track-changed', info)
|
|
||||||
|
|
||||||
def _banshee_check_track_status(self):
|
def _banshee_check_track_status(self):
|
||||||
if self.dubus_methods.NameHasOwner('org.gnome.Banshee') and \
|
if self.dubus_methods.NameHasOwner('org.gnome.Banshee') and \
|
||||||
not hasattr(self, 'banshee_methods'):
|
not hasattr(self, 'banshee_methods'):
|
||||||
|
|
|
@ -170,17 +170,25 @@ def notify(event, jid, account, parameters, advanced_notif_num = None):
|
||||||
nickname = parameters[2]
|
nickname = parameters[2]
|
||||||
if gajim.config.get('notification_preview_message'):
|
if gajim.config.get('notification_preview_message'):
|
||||||
message = parameters[3]
|
message = parameters[3]
|
||||||
|
if message.startswith('/me ') or message.startswith('/me\n'):
|
||||||
|
message = '* ' + nickname + message[3:]
|
||||||
else:
|
else:
|
||||||
# We don't want message preview, do_preview = False
|
# We don't want message preview, do_preview = False
|
||||||
message = ''
|
message = ''
|
||||||
|
focused = parameters[4]
|
||||||
if helpers.allow_showing_notification(account, 'notify_on_new_message',
|
if helpers.allow_showing_notification(account, 'notify_on_new_message',
|
||||||
advanced_notif_num, is_first_message):
|
advanced_notif_num, is_first_message):
|
||||||
do_popup = True
|
do_popup = True
|
||||||
if is_first_message and helpers.allow_sound_notification(
|
if is_first_message and helpers.allow_sound_notification(
|
||||||
'first_message_received', advanced_notif_num):
|
'first_message_received', advanced_notif_num):
|
||||||
do_sound = True
|
do_sound = True
|
||||||
elif not is_first_message and helpers.allow_sound_notification(
|
elif not is_first_message and focused and \
|
||||||
'next_message_received', advanced_notif_num):
|
helpers.allow_sound_notification('next_message_received_focused',
|
||||||
|
advanced_notif_num):
|
||||||
|
do_sound = True
|
||||||
|
elif not is_first_message and not focused and \
|
||||||
|
helpers.allow_sound_notification('next_message_received_unfocused',
|
||||||
|
advanced_notif_num):
|
||||||
do_sound = True
|
do_sound = True
|
||||||
else:
|
else:
|
||||||
print '*Event not implemeted yet*'
|
print '*Event not implemeted yet*'
|
||||||
|
@ -283,8 +291,10 @@ def notify(event, jid, account, parameters, advanced_notif_num = None):
|
||||||
pass # do not set snd_event
|
pass # do not set snd_event
|
||||||
elif is_first_message:
|
elif is_first_message:
|
||||||
snd_event = 'first_message_received'
|
snd_event = 'first_message_received'
|
||||||
|
elif focused:
|
||||||
|
snd_event = 'next_message_received_focused'
|
||||||
else:
|
else:
|
||||||
snd_event = 'next_message_received'
|
snd_event = 'next_message_received_unfocused'
|
||||||
elif event in ('contact_connected', 'contact_disconnected'):
|
elif event in ('contact_connected', 'contact_disconnected'):
|
||||||
snd_event = event
|
snd_event = event
|
||||||
if snd_file:
|
if snd_file:
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
# dummy
|
|
|
@ -1 +0,0 @@
|
||||||
# dummy
|
|
|
@ -1 +0,0 @@
|
||||||
# dummy
|
|
|
@ -1 +0,0 @@
|
||||||
# dummy
|
|
|
@ -114,6 +114,7 @@ static PyObject * idle_getIdleSec(PyObject *self, PyObject *args)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("Couldn't grab properties of system\n");
|
printf("Couldn't grab properties of system\n");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj)
|
if (obj)
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
# dummy
|
|
|
@ -1 +0,0 @@
|
||||||
# dummy
|
|
|
@ -6,6 +6,7 @@
|
||||||
## Copyright (C) 2005-2006 Andrew Sayman <lorien420@myrealbox.com>
|
## Copyright (C) 2005-2006 Andrew Sayman <lorien420@myrealbox.com>
|
||||||
## Copyright (C) 2007 Lukas Petrovicky <lukas@petrovicky.net>
|
## Copyright (C) 2007 Lukas Petrovicky <lukas@petrovicky.net>
|
||||||
## Copyright (C) 2007 Julien Pivotto <roidelapluie@gmail.com>
|
## Copyright (C) 2007 Julien Pivotto <roidelapluie@gmail.com>
|
||||||
|
## Copyright (C) 2007 Travis Shirk <travis@pobox.com>
|
||||||
##
|
##
|
||||||
## This file is part of Gajim.
|
## This file is part of Gajim.
|
||||||
##
|
##
|
||||||
|
@ -373,7 +374,6 @@ class SignalObject(dbus.service.Object):
|
||||||
if not specified status is changed for all accounts. '''
|
if not specified status is changed for all accounts. '''
|
||||||
if status not in ('offline', 'online', 'chat',
|
if status not in ('offline', 'online', 'chat',
|
||||||
'away', 'xa', 'dnd', 'invisible'):
|
'away', 'xa', 'dnd', 'invisible'):
|
||||||
raise InvalidArgument
|
|
||||||
return DBUS_BOOLEAN(False)
|
return DBUS_BOOLEAN(False)
|
||||||
if account:
|
if account:
|
||||||
gobject.idle_add(gajim.interface.roster.send_status, account,
|
gobject.idle_add(gajim.interface.roster.send_status, account,
|
||||||
|
@ -615,7 +615,10 @@ class SignalObject(dbus.service.Object):
|
||||||
for contact in contacts:
|
for contact in contacts:
|
||||||
resource_props = dbus.Struct((DBUS_STRING(contact.resource),
|
resource_props = dbus.Struct((DBUS_STRING(contact.resource),
|
||||||
dbus.Int32(contact.priority), DBUS_STRING(contact.status)))
|
dbus.Int32(contact.priority), DBUS_STRING(contact.status)))
|
||||||
contact_dict['resources'].append(resource_props)
|
contact_dict['resources'].append(resource_props)
|
||||||
|
contact_dict['groups'] = dbus.Array([], signature='s')
|
||||||
|
for group in prim_contact.groups:
|
||||||
|
contact_dict['groups'].append(DBUS_STRING(group))
|
||||||
return contact_dict
|
return contact_dict
|
||||||
|
|
||||||
@dbus.service.method(INTERFACE, in_signature='', out_signature='s')
|
@dbus.service.method(INTERFACE, in_signature='', out_signature='s')
|
||||||
|
@ -654,4 +657,4 @@ class SignalObject(dbus.service.Object):
|
||||||
gajim.interface.instances[account]['join_gc'] = \
|
gajim.interface.instances[account]['join_gc'] = \
|
||||||
JoinGroupchatWindow(account, room_jid, nick)
|
JoinGroupchatWindow(account, room_jid, nick)
|
||||||
else:
|
else:
|
||||||
gajim.connections[account].join_gc(nick, room_jid, password)
|
gajim.interface.roster.join_gc_room(account, room_jid, nick, password)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -22,7 +22,6 @@
|
||||||
import sys
|
import sys
|
||||||
import gtk
|
import gtk
|
||||||
import systray
|
import systray
|
||||||
import gobject
|
|
||||||
|
|
||||||
from common import gajim
|
from common import gajim
|
||||||
from common import helpers
|
from common import helpers
|
||||||
|
@ -60,7 +59,7 @@ class StatusIcon(systray.Systray):
|
||||||
self.unsubscribe_events()
|
self.unsubscribe_events()
|
||||||
|
|
||||||
def on_status_icon_left_clicked(self, widget):
|
def on_status_icon_left_clicked(self, widget):
|
||||||
gobject.idle_add(self.on_left_click)
|
self.on_left_click()
|
||||||
|
|
||||||
def set_img(self):
|
def set_img(self):
|
||||||
'''apart from image, we also update tooltip text here'''
|
'''apart from image, we also update tooltip text here'''
|
||||||
|
|
|
@ -254,14 +254,10 @@ class Systray:
|
||||||
item = gtk.MenuItem(_('Hide this menu'))
|
item = gtk.MenuItem(_('Hide this menu'))
|
||||||
self.systray_context_menu.prepend(item)
|
self.systray_context_menu.prepend(item)
|
||||||
self.added_hide_menuitem = True
|
self.added_hide_menuitem = True
|
||||||
self.systray_context_menu.popup(None, None,
|
|
||||||
gtk.status_icon_position_menu, event_button,
|
|
||||||
event_time, self.status_icon)
|
|
||||||
|
|
||||||
else: # GNU and Unices
|
|
||||||
self.systray_context_menu.popup(None, None, None, event_button,
|
|
||||||
event_time)
|
|
||||||
self.systray_context_menu.show_all()
|
self.systray_context_menu.show_all()
|
||||||
|
self.systray_context_menu.popup(None, None, None, event_button,
|
||||||
|
event_time)
|
||||||
|
|
||||||
def on_show_all_events_menuitem_activate(self, widget):
|
def on_show_all_events_menuitem_activate(self, widget):
|
||||||
events = gajim.events.get_systray_events()
|
events = gajim.events.get_systray_events()
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
## tooltips.py
|
## tooltips.py
|
||||||
##
|
##
|
||||||
## Copyright (C) 2005-2006 Dimitur Kirov <dkirov@gmail.com>
|
## Copyright (C) 2005-2006 Dimitur Kirov <dkirov@gmail.com>
|
||||||
|
@ -463,6 +464,10 @@ class RosterTooltip(NotificationAreaTooltip):
|
||||||
contact.last_status_time)
|
contact.last_status_time)
|
||||||
properties.append((self.table, None))
|
properties.append((self.table, None))
|
||||||
else: # only one resource
|
else: # only one resource
|
||||||
|
|
||||||
|
#FIXME: User {Mood, Activity, Tune} not shown if there are
|
||||||
|
#multiple resources
|
||||||
|
#FIXME: User {Mood, Activity, Tune} not shown for self
|
||||||
if contact.show:
|
if contact.show:
|
||||||
show = helpers.get_uf_show(contact.show)
|
show = helpers.get_uf_show(contact.show)
|
||||||
if contact.last_status_time:
|
if contact.last_status_time:
|
||||||
|
@ -494,6 +499,52 @@ class RosterTooltip(NotificationAreaTooltip):
|
||||||
show = '<i>' + show + '</i>'
|
show = '<i>' + show + '</i>'
|
||||||
# we append show below
|
# we append show below
|
||||||
|
|
||||||
|
if contact.mood.has_key('mood'):
|
||||||
|
mood = contact.mood['mood'].strip()
|
||||||
|
mood = gobject.markup_escape_text(mood)
|
||||||
|
mood_string = _('Mood:') + ' <b>%s</b>' % mood
|
||||||
|
if contact.mood.has_key('text') and contact.mood['text'] != '':
|
||||||
|
mood_text = contact.mood['text'].strip()
|
||||||
|
mood_text = gobject.markup_escape_text(mood_text)
|
||||||
|
mood_string += ' (%s)' % mood_text
|
||||||
|
properties.append((mood_string, None))
|
||||||
|
|
||||||
|
if contact.activity.has_key('activity'):
|
||||||
|
activity = contact.activity['activity'].strip()
|
||||||
|
activity = gobject.markup_escape_text(activity)
|
||||||
|
activity_string = _('Activity:') + ' <b>%s' % activity
|
||||||
|
if contact.activity.has_key('subactivity'):
|
||||||
|
activity_sub = contact.activity['subactivity'].strip()
|
||||||
|
activity_sub = gobject.markup_escape_text(activity_sub)
|
||||||
|
activity_string += ' (%s)</b>' % activity_sub
|
||||||
|
else:
|
||||||
|
activity_string += '</b>'
|
||||||
|
if contact.activity.has_key('text'):
|
||||||
|
activity_text = contact.activity['text'].strip()
|
||||||
|
activity_text = gobject.markup_escape_text(activity_text)
|
||||||
|
activity_string += ' (%s)' % activity_text
|
||||||
|
properties.append((activity_string, None))
|
||||||
|
|
||||||
|
if contact.tune.has_key('artist') or contact.tune.has_key('title'):
|
||||||
|
if contact.tune.has_key('artist'):
|
||||||
|
artist = contact.tune['artist'].strip()
|
||||||
|
artist = gobject.markup_escape_text(artist)
|
||||||
|
else:
|
||||||
|
artist = _('Unknown Artist')
|
||||||
|
if contact.tune.has_key('title'):
|
||||||
|
title = contact.tune['title'].strip()
|
||||||
|
title = gobject.markup_escape_text(title)
|
||||||
|
else:
|
||||||
|
title = _('Unknown Title')
|
||||||
|
if contact.tune.has_key('source'):
|
||||||
|
source = contact.tune['source'].strip()
|
||||||
|
source = gobject.markup_escape_text(source)
|
||||||
|
else:
|
||||||
|
source = _('Unknown Source')
|
||||||
|
tune_string = _('Tune:') + ' ' + _('<b>"%(title)s"</b> by <i>%(artist)s</i>\nfrom <i>%(source)s</i>' %\
|
||||||
|
{'title': title, 'artist': artist, 'source': source})
|
||||||
|
properties.append((tune_string, None))
|
||||||
|
|
||||||
if contact.status:
|
if contact.status:
|
||||||
status = contact.status.strip()
|
status = contact.status.strip()
|
||||||
if status:
|
if status:
|
||||||
|
|
|
@ -178,8 +178,6 @@ class VcardWindow:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def set_values(self, vcard):
|
def set_values(self, vcard):
|
||||||
if not 'PHOTO' in vcard:
|
|
||||||
self.xml.get_widget('no_user_avatar_label').show()
|
|
||||||
for i in vcard.keys():
|
for i in vcard.keys():
|
||||||
if i == 'PHOTO' and self.xml.get_widget('information_notebook').\
|
if i == 'PHOTO' and self.xml.get_widget('information_notebook').\
|
||||||
get_n_pages() > 4:
|
get_n_pages() > 4:
|
||||||
|
@ -187,6 +185,7 @@ class VcardWindow:
|
||||||
get_avatar_pixbuf_encoded_mime(vcard[i])
|
get_avatar_pixbuf_encoded_mime(vcard[i])
|
||||||
image = self.xml.get_widget('PHOTO_image')
|
image = self.xml.get_widget('PHOTO_image')
|
||||||
image.show()
|
image.show()
|
||||||
|
self.xml.get_widget('user_avatar_label').show()
|
||||||
if not pixbuf:
|
if not pixbuf:
|
||||||
image.set_from_icon_name('stock_person',
|
image.set_from_icon_name('stock_person',
|
||||||
gtk.ICON_SIZE_DIALOG)
|
gtk.ICON_SIZE_DIALOG)
|
||||||
|
|
Loading…
Add table
Reference in a new issue