Merge changes from default to refacotring branch

This commit is contained in:
Stephan Erb 2009-11-05 14:43:05 +01:00
commit c6448d0f2b
77 changed files with 4332 additions and 3824 deletions

View File

@ -1,3 +1,26 @@
Gajim 0.13 (XX November 2009)
* Improve gtkspell (fix memleak)
* BOSH connection
* Roster versioning
* Ability to send contacts
* GUI to send XHTML messages
* Improve sessions handling
* pubsub storage (for bookmarks)
* Ability to select account when joining a groupchat
* Better Gnome keyring support
* Ability to ignore occupants in groupchats
* Ability to show / hide self contact row
* Automatically go away when screensaver is enabled under windows
* Ability to enable / disable accounts
* better URL recognition
* groupchat autoreconnect
* Store passwords in KDE wallet if available
* Better MUC errors handling
* Fix sound player launch (don't create zombies anymore)
* Optional shell like completion
* New color theme
Gajim 0.12.5 (08 August 2009) Gajim 0.12.5 (08 August 2009)
* Don't depend on GTK 2.14 * Don't depend on GTK 2.14

View File

@ -2,7 +2,9 @@ Anders Ström
Christophe Got Christophe Got
Dennis Craven Dennis Craven
Guillaume Morin Guillaume Morin
Gvorcek Spajreh
Josef Vybíral Josef Vybíral
Membris Khan Membris Khan
Rederick Asher Rederick Asher
Jakub Szypulka Jakub Szypulka

View File

@ -1,5 +1,5 @@
AC_INIT([Gajim - A Jabber Instant Messager], AC_INIT([Gajim - A Jabber Instant Messager],
[0.12.5.7-dev],[http://trac.gajim.org/],[gajim]) [0.12.5.8-dev],[http://trac.gajim.org/],[gajim])
AC_PREREQ([2.59]) AC_PREREQ([2.59])
AC_CONFIG_HEADER(config.h) AC_CONFIG_HEADER(config.h)

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 929 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 938 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 941 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 466 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 901 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 949 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 895 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 924 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 939 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 929 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 929 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -174,7 +174,6 @@ Section "Gajim" SecGajim
File "bin\pywintypes25.dll" File "bin\pywintypes25.dll"
File "bin\OpenSSL.rand.pyd" File "bin\OpenSSL.rand.pyd"
File "bin\select.pyd" File "bin\select.pyd"
File "bin\Crypto.Hash.SHA256.pyd"
File "bin\sqlite3.dll" File "bin\sqlite3.dll"
File "bin\ssleay32.dll" File "bin\ssleay32.dll"
File "bin\OpenSSL.SSL.pyd" File "bin\OpenSSL.SSL.pyd"
@ -286,6 +285,11 @@ Section "sun" SecIconsetsSun
File /r "data\iconsets\sun" File /r "data\iconsets\sun"
SectionEnd SectionEnd
Section "wroop" SecIconsetsWroop
SetOutPath "$INSTDIR\data\iconsets"
File /r "data\iconsets\wroop"
SectionEnd
Section "transports" SecIconsetsTransports Section "transports" SecIconsetsTransports
SetOutPath "$INSTDIR\data\iconsets" SetOutPath "$INSTDIR\data\iconsets"
File /r "data\iconsets\transports" File /r "data\iconsets\transports"
@ -646,7 +650,6 @@ Section "Uninstall"
Delete "$INSTDIR\bin\bz2.pyd" Delete "$INSTDIR\bin\bz2.pyd"
Delete "$INSTDIR\bin\cairo._cairo.pyd" Delete "$INSTDIR\bin\cairo._cairo.pyd"
Delete "$INSTDIR\bin\Crypto.Cipher.AES.pyd" Delete "$INSTDIR\bin\Crypto.Cipher.AES.pyd"
Delete "$INSTDIR\bin\Crypto.Hash.SHA256.pyd"
Delete "$INSTDIR\bin\gajim.exe" Delete "$INSTDIR\bin\gajim.exe"
Delete "$INSTDIR\bin\gobject._gobject.pyd" Delete "$INSTDIR\bin\gobject._gobject.pyd"
Delete "$INSTDIR\bin\gtk._gtk.pyd" Delete "$INSTDIR\bin\gtk._gtk.pyd"
@ -692,6 +695,7 @@ Section "Uninstall"
RMDir /r "$INSTDIR\data\iconsets\gota" RMDir /r "$INSTDIR\data\iconsets\gota"
RMDir /r "$INSTDIR\data\iconsets\jabberbulb" RMDir /r "$INSTDIR\data\iconsets\jabberbulb"
RMDir /r "$INSTDIR\data\iconsets\sun" RMDir /r "$INSTDIR\data\iconsets\sun"
RMDir /r "$INSTDIR\data\iconsets\wroop"
RMDir /r "$INSTDIR\data\iconsets\transports" RMDir /r "$INSTDIR\data\iconsets\transports"
RMDir "$INSTDIR\data\iconsets" RMDir "$INSTDIR\data\iconsets"
RMDir "$INSTDIR\data" RMDir "$INSTDIR\data"

View File

@ -65,7 +65,9 @@ class CommandProcessor(object):
Try to process text as a command. Returns True if it has been processed Try to process text as a command. Returns True if it has been processed
as a command and False otherwise. as a command and False otherwise.
""" """
if not text.startswith(self.COMMAND_PREFIX): prefix = text.startswith(self.COMMAND_PREFIX)
length = len(text) > len(self.COMMAND_PREFIX)
if not (prefix and length):
return False return False
body = text[len(self.COMMAND_PREFIX):] body = text[len(self.COMMAND_PREFIX):]
@ -158,7 +160,7 @@ class Command(object):
# in case if they was not set by the one who raised an exception. # in case if they was not set by the one who raised an exception.
except CommandError, error: except CommandError, error:
if not error.command and not error.name: if not error.command and not error.name:
raise CommandError(exception.message, self) raise CommandError(error.message, self)
raise raise
# This one is a little bit too wide, but as Python does not have # This one is a little bit too wide, but as Python does not have

View File

@ -22,6 +22,7 @@ from common import gajim
from common import helpers from common import helpers
from common.exceptions import GajimGeneralException from common.exceptions import GajimGeneralException
from ..errors import CommandError
from ..framework import CommandContainer, command, documentation from ..framework import CommandContainer, command, documentation
from ..mapping import generate_usage from ..mapping import generate_usage

View File

@ -198,7 +198,7 @@ class NullClientCaps(AbstractClientCaps):
def _lookup_in_cache(self, caps_cache): def _lookup_in_cache(self, caps_cache):
# lookup something which does not exist to get a new CacheItem created # lookup something which does not exist to get a new CacheItem created
cache_item = caps_cache[('old', '')] cache_item = caps_cache[('dummy', '')]
assert cache_item.queried == 0 assert cache_item.queried == 0
return cache_item return cache_item
@ -359,10 +359,10 @@ class ConnectionCaps(object):
else: else:
hash_method, node, caps_hash = caps_tag['hash'], caps_tag['node'], caps_tag['ver'] hash_method, node, caps_hash = caps_tag['hash'], caps_tag['node'], caps_tag['ver']
if node is None or caps_hash is None: if not node or not caps_hash:
# improper caps in stanza, ignore client capabilities. # improper caps in stanza, ignore client capabilities.
client_caps = NullClientCaps() client_caps = NullClientCaps()
elif hash_method is None: elif not hash_method:
client_caps = OldClientCaps(caps_hash, node) client_caps = OldClientCaps(caps_hash, node)
else: else:
client_caps = ClientCaps(caps_hash, node, hash_method) client_caps = ClientCaps(caps_hash, node, hash_method)

View File

@ -326,8 +326,7 @@ class Config:
'http_auth': [opt_str, 'ask'], # yes, no, ask 'http_auth': [opt_str, 'ask'], # yes, no, ask
'dont_ack_subscription': [opt_bool, False, _('Jabberd2 workaround')], 'dont_ack_subscription': [opt_bool, False, _('Jabberd2 workaround')],
# proxy65 for FT # proxy65 for FT
'file_transfer_proxies': [opt_str, 'file_transfer_proxies': [opt_str, 'proxy.eu.jabber.org, proxy.jabber.ru, proxy.jabbim.cz'],
'proxy65.talkonaut.com, proxy.jabber.org, proxy.netlab.cz, transfer.jabber.freenet.de, proxy.jabber.cd.chalmers.se'],
'use_ft_proxies': [opt_bool, True, _('If checked, Gajim will use your IP and proxies defined in file_transfer_proxies option for file transfer.'), True], 'use_ft_proxies': [opt_bool, True, _('If checked, Gajim will use your IP and proxies defined in file_transfer_proxies option for file transfer.'), True],
'msgwin-x-position': [opt_int, -1], # Default is to let the wm decide 'msgwin-x-position': [opt_int, -1], # Default is to let the wm decide
'msgwin-y-position': [opt_int, -1], # Default is to let the wm decide 'msgwin-y-position': [opt_int, -1], # Default is to let the wm decide

View File

@ -2259,7 +2259,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
is_gc = True is_gc = True
status = prs.getStatus() or '' status = prs.getStatus() or ''
show = prs.getShow() show = prs.getShow()
if not show in gajim.SHOW_LIST: if show not in ('chat', 'away', 'xa', 'dnd'):
show = '' # We ignore unknown show show = '' # We ignore unknown show
if not ptype and not show: if not ptype and not show:
show = 'online' show = 'online'

View File

@ -27,7 +27,7 @@ docdir = '../'
datadir = '../' datadir = '../'
localedir = '../po' localedir = '../po'
version = '0.12.5.7-dev' version = '0.12.5.8-dev'
import sys, os.path import sys, os.path
for base in ('.', 'common'): for base in ('.', 'common'):

View File

@ -216,12 +216,51 @@ class OptionsParser:
self.update_config_to_01256() self.update_config_to_01256()
if old < [0, 12, 5, 7] and new >= [0, 12, 5, 7]: if old < [0, 12, 5, 7] and new >= [0, 12, 5, 7]:
self.update_config_to_01257() self.update_config_to_01257()
if old < [0, 12, 5, 8] and new >= [0, 12, 5, 8]:
self.update_config_to_01258()
gajim.logger.init_vars() gajim.logger.init_vars()
gajim.config.set('version', new_version) gajim.config.set('version', new_version)
caps.capscache.initialize_from_db() caps.capscache.initialize_from_db()
def assert_unread_msgs_table_exists(self):
'''create table unread_messages if there is no such table'''
back = os.getcwd()
os.chdir(logger.LOG_DB_FOLDER)
con = sqlite.connect(logger.LOG_DB_FILE)
os.chdir(back)
cur = con.cursor()
try:
cur.executescript(
'''
CREATE TABLE unread_messages (
message_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
jid_id INTEGER
);
'''
)
con.commit()
gajim.logger.init_vars()
except sqlite.OperationalError:
pass
con.close()
def update_ft_proxies(self, to_remove=[], to_add=[]):
for account in gajim.config.get_per('accounts'):
proxies_str = gajim.config.get_per('accounts', account,
'file_transfer_proxies')
proxies = [p.strip() for p in proxies_str.split(',')]
for wrong_proxy in to_remove:
if wrong_proxy in proxies:
proxies.remove(wrong_proxy)
for new_proxy in to_add:
if new_proxy not in proxies:
proxies.append(new_proxy)
proxies_str = ', '.join(proxies)
gajim.config.set_per('accounts', account, 'file_transfer_proxies',
proxies_str)
def update_config_x_to_09(self): def update_config_x_to_09(self):
# Var name that changed: # Var name that changed:
# avatar_width /height -> chat_avatar_width / height # avatar_width /height -> chat_avatar_width / height
@ -262,38 +301,10 @@ class OptionsParser:
theme = gajim.config.get_per('themes')[0] theme = gajim.config.get_per('themes')[0]
gajim.config.set('roster_theme', theme) gajim.config.set('roster_theme', theme)
# new proxies in accounts.name.file_transfer_proxies # new proxies in accounts.name.file_transfer_proxies
for account in gajim.config.get_per('accounts'): self.update_ft_proxies(to_add=['proxy.netlab.cz'])
proxies = gajim.config.get_per('accounts', account,
'file_transfer_proxies')
if proxies.find('proxy.netlab.cz') < 0:
proxies += ', ' + 'proxy.netlab.cz'
gajim.config.set_per('accounts', account, 'file_transfer_proxies',
proxies)
gajim.config.set('version', '0.9') gajim.config.set('version', '0.9')
def assert_unread_msgs_table_exists(self):
'''create table unread_messages if there is no such table'''
back = os.getcwd()
os.chdir(logger.LOG_DB_FOLDER)
con = sqlite.connect(logger.LOG_DB_FILE)
os.chdir(back)
cur = con.cursor()
try:
cur.executescript(
'''
CREATE TABLE unread_messages (
message_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
jid_id INTEGER
);
'''
)
con.commit()
gajim.logger.init_vars()
except sqlite.OperationalError:
pass
con.close()
def update_config_09_to_010(self): def update_config_09_to_010(self):
if 'usetabbedchat' in self.old_values and not \ if 'usetabbedchat' in self.old_values and not \
self.old_values['usetabbedchat']: self.old_values['usetabbedchat']:
@ -311,21 +322,8 @@ class OptionsParser:
self.old_values['always_compact_view_gc'] != 'False': self.old_values['always_compact_view_gc'] != 'False':
gajim.config.set('always_hide_groupchat_buttons', True) gajim.config.set('always_hide_groupchat_buttons', True)
for account in gajim.config.get_per('accounts'): self.update_ft_proxies(to_remove=['proxy65.jabber.autocom.pl',
proxies_str = gajim.config.get_per('accounts', account, 'proxy65.jabber.ccc.de'], to_add=['transfer.jabber.freenet.de'])
'file_transfer_proxies')
proxies = proxies_str.split(',')
for i in range(0, len(proxies)):
proxies[i] = proxies[i].strip()
for wrong_proxy in ('proxy65.jabber.autocom.pl',
'proxy65.jabber.ccc.de'):
if wrong_proxy in proxies:
proxies.remove(wrong_proxy)
if not 'transfer.jabber.freenet.de' in proxies:
proxies.append('transfer.jabber.freenet.de')
proxies_str = ', '.join(proxies)
gajim.config.set_per('accounts', account, 'file_transfer_proxies',
proxies_str)
# create unread_messages table if needed # create unread_messages table if needed
self.assert_unread_msgs_table_exists() self.assert_unread_msgs_table_exists()
@ -811,4 +809,12 @@ class OptionsParser:
'simplebulb', 'stellar'): 'simplebulb', 'stellar'):
gajim.config.set('iconset', gajim.config.DEFAULT_ICONSET) gajim.config.set('iconset', gajim.config.DEFAULT_ICONSET)
gajim.config.set('version', '0.12.5.7') gajim.config.set('version', '0.12.5.7')
def update_config_to_01258(self):
self.update_ft_proxies(to_remove=['proxy65.talkonaut.com',
'proxy.jabber.org', 'proxy.netlab.cz', 'transfer.jabber.freenet.de',
'proxy.jabber.cd.chalmers.se'], to_add=['proxy.eu.jabber.org',
'proxy.jabber.ru', 'proxy.jabbim.cz'])
gajim.config.set('version', '0.12.5.8')
# vim: se ts=3: # vim: se ts=3:

View File

@ -84,8 +84,8 @@ class NonBlockingBOSH(NonBlockingTransport):
self.proxy_dict['type'] = 'http' self.proxy_dict['type'] = 'http'
# with SSL over proxy, we do HTTP CONNECT to proxy to open a channel to # with SSL over proxy, we do HTTP CONNECT to proxy to open a channel to
# BOSH Connection Manager # BOSH Connection Manager
host, port = urisplit(self.bosh_uri)[1].split(':', 1) host, port = urisplit(self.bosh_uri)[1:3]
self.proxy_dict['xmpp_server'] = (host, int(port)) self.proxy_dict['xmpp_server'] = (host, port)
self.proxy_dict['credentials'] = self.proxy_creds self.proxy_dict['credentials'] = self.proxy_creds

View File

@ -35,30 +35,39 @@ import errno
import time import time
import traceback import traceback
import base64 import base64
import urlparse
import logging import logging
log = logging.getLogger('gajim.c.x.transports_nb') log = logging.getLogger('gajim.c.x.transports_nb')
def urisplit(uri): def urisplit(uri):
''' '''
Function for splitting URI string to tuple (protocol, host, path). Function for splitting URI string to tuple (protocol, host, port, path).
e.g. urisplit('http://httpcm.jabber.org/webclient') returns e.g. urisplit('http://httpcm.jabber.org:123/webclient') returns
('http', 'httpcm.jabber.org', '/webclient') ('http', 'httpcm.jabber.org', 123, '/webclient')
return 443 as default port if proto is https else 80
''' '''
import re splitted = urlparse.urlsplit(uri)
regex = '(([^:/]+)(://))?([^/]*)(/?.*)' proto, host, path = splitted.scheme, splitted.hostname, splitted.path
grouped = re.match(regex, uri).groups() try:
proto, host, path = grouped[1], grouped[3], grouped[4] port = splitted.port
return proto, host, path except ValueError:
log.warn('port cannot be extracted from BOSH URL %s, using default port' \
% uri)
port = ''
if not port:
if proto == 'https':
port = 443
else:
port = 80
return proto, host, port, path
def get_proxy_data_from_dict(proxy): def get_proxy_data_from_dict(proxy):
tcp_host, tcp_port, proxy_user, proxy_pass = None, None, None, None tcp_host, tcp_port, proxy_user, proxy_pass = None, None, None, None
proxy_type = proxy['type'] proxy_type = proxy['type']
if proxy_type == 'bosh' and not proxy['bosh_useproxy']: if proxy_type == 'bosh' and not proxy['bosh_useproxy']:
# with BOSH not over proxy we have to parse the hostname from BOSH URI # with BOSH not over proxy we have to parse the hostname from BOSH URI
tcp_host = urisplit(proxy['bosh_uri'])[1] proto, tcp_host, tcp_port, path = urisplit(proxy['bosh_uri'])
tcp_host, tcp_port = tcp_host.split(':', 1)
tcp_port = int(tcp_port)
else: else:
# with proxy!=bosh or with bosh over HTTP proxy we're connecting to proxy # with proxy!=bosh or with bosh over HTTP proxy we're connecting to proxy
# machine # machine
@ -602,10 +611,8 @@ class NonBlockingHTTP(NonBlockingTCP):
NonBlockingTCP.__init__(self, raise_event, on_disconnect, idlequeue, NonBlockingTCP.__init__(self, raise_event, on_disconnect, idlequeue,
estabilish_tls, certs, proxy_dict) estabilish_tls, certs, proxy_dict)
self.http_protocol, self.http_host, self.http_path = urisplit( self.http_protocol, self.http_host, self.http_port, self.http_path = \
http_dict['http_uri']) urisplit(http_dict['http_uri'])
self.http_host, self.http_port = self.http_host.split(':', 1)
self.http_port = int(self.http_port)
self.http_protocol = self.http_protocol or 'http' self.http_protocol = self.http_protocol or 'http'
self.http_path = self.http_path or '/' self.http_path = self.http_path or '/'
self.http_version = http_dict['http_version'] self.http_version = http_dict['http_version']

View File

@ -228,25 +228,8 @@ 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)
# Color for incoming messages # Color widgets
colSt = gajim.config.get('inmsgcolor') self.draw_color_widgets()
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 for messages
font = gajim.config.get('conversation_font') font = gajim.config.get('conversation_font')
@ -823,12 +806,18 @@ class PreferencesWindow:
for win in gajim.interface.msg_win_mgr.windows(): for win in gajim.interface.msg_win_mgr.windows():
win.update_font() win.update_font()
def on_incoming_msg_colorbutton_color_set(self, widget): def on_incoming_nick_colorbutton_color_set(self, widget):
self.on_preference_widget_color_set(widget, 'inmsgcolor') self.on_preference_widget_color_set(widget, 'inmsgcolor')
def on_outgoing_msg_colorbutton_color_set(self, widget): def on_outgoing_nick_colorbutton_color_set(self, widget):
self.on_preference_widget_color_set(widget, 'outmsgcolor') self.on_preference_widget_color_set(widget, 'outmsgcolor')
def on_incoming_msg_colorbutton_color_set(self, widget):
self.on_preference_widget_color_set(widget, 'inmsgtxtcolor')
def on_outgoing_msg_colorbutton_color_set(self, widget):
self.on_preference_widget_color_set(widget, 'outmsgtxtcolor')
def on_url_msg_colorbutton_color_set(self, widget): def on_url_msg_colorbutton_color_set(self, widget):
self.on_preference_widget_color_set(widget, 'urlmsgcolor') self.on_preference_widget_color_set(widget, 'urlmsgcolor')
@ -847,21 +836,70 @@ class PreferencesWindow:
font_widget.set_sensitive(True) font_widget.set_sensitive(True)
self.on_preference_widget_font_set(font_widget, 'conversation_font') self.on_preference_widget_font_set(font_widget, 'conversation_font')
def on_reset_colors_button_clicked(self, widget): def draw_color_widgets(self):
for i in ('inmsgcolor', 'outmsgcolor', 'statusmsgcolor', 'urlmsgcolor'): col_to_widget = {'inmsgcolor': 'incoming_nick_colorbutton',
gajim.config.set(i, gajim.interface.default_colors[i]) 'outmsgcolor': 'outgoing_nick_colorbutton',
'inmsgtxtcolor': ['incoming_msg_colorbutton',
'incoming_msg_checkbutton'],
'outmsgtxtcolor': ['outgoing_msg_colorbutton',
'outgoing_msg_checkbutton'],
'statusmsgcolor': 'status_msg_colorbutton',
'urlmsgcolor': 'url_msg_colorbutton'}
for c in col_to_widget:
col = gajim.config.get(c)
if col:
if isinstance(col_to_widget[c], list):
self.xml.get_widget(col_to_widget[c][0]).set_color(
gtk.gdk.color_parse(col))
self.xml.get_widget(col_to_widget[c][0]).set_sensitive(True)
self.xml.get_widget(col_to_widget[c][1]).set_active(True)
else:
self.xml.get_widget(col_to_widget[c]).set_color(
gtk.gdk.color_parse(col))
else:
if isinstance(col_to_widget[c], list):
self.xml.get_widget(col_to_widget[c][0]).set_color(
gtk.gdk.color_parse('#000000'))
self.xml.get_widget(col_to_widget[c][0]).set_sensitive(False)
self.xml.get_widget(col_to_widget[c][1]).set_active(False)
else:
self.xml.get_widget(col_to_widget[c]).set_color(
gtk.gdk.color_parse('#000000'))
def on_reset_colors_button_clicked(self, widget):
col_to_widget = {'inmsgcolor': 'incoming_nick_colorbutton',
'outmsgcolor': 'outgoing_nick_colorbutton',
'inmsgtxtcolor': 'incoming_msg_colorbutton',
'outmsgtxtcolor': 'outgoing_msg_colorbutton',
'statusmsgcolor': 'status_msg_colorbutton',
'urlmsgcolor': 'url_msg_colorbutton'}
for c in col_to_widget:
gajim.config.set(c, gajim.interface.default_colors[c])
self.draw_color_widgets()
self.xml.get_widget('incoming_msg_colorbutton').set_color(\
gtk.gdk.color_parse(gajim.config.get('inmsgcolor')))
self.xml.get_widget('outgoing_msg_colorbutton').set_color(\
gtk.gdk.color_parse(gajim.config.get('outmsgcolor')))
self.xml.get_widget('status_msg_colorbutton').set_color(\
gtk.gdk.color_parse(gajim.config.get('statusmsgcolor')))
self.xml.get_widget('url_msg_colorbutton').set_color(\
gtk.gdk.color_parse(gajim.config.get('urlmsgcolor')))
self.update_text_tags() self.update_text_tags()
gajim.interface.save_config() gajim.interface.save_config()
def _set_color(self, state, widget_name, option):
''' set color value in prefs and update the UI '''
if state:
color = self.xml.get_widget(widget_name).get_color()
color_string = gtkgui_helpers.make_color_string(color)
else:
color_string = ''
gajim.config.set(option, color_string)
gajim.interface.save_config()
def on_incoming_msg_checkbutton_toggled(self, widget):
state = widget.get_active()
self.xml.get_widget('incoming_msg_colorbutton').set_sensitive(state)
self._set_color(state, 'incoming_msg_colorbutton', 'inmsgtxtcolor')
def on_outgoing_msg_checkbutton_toggled(self, widget):
state = widget.get_active()
self.xml.get_widget('outgoing_msg_colorbutton').set_sensitive(state)
self._set_color(state, 'outgoing_msg_colorbutton', 'outmsgtxtcolor')
def on_auto_away_checkbutton_toggled(self, widget): def on_auto_away_checkbutton_toggled(self, widget):
self.on_checkbutton_toggled(widget, 'autoaway', self.on_checkbutton_toggled(widget, 'autoaway',
[self.auto_away_time_spinbutton, self.auto_away_message_entry]) [self.auto_away_time_spinbutton, self.auto_away_message_entry])

View File

@ -853,7 +853,7 @@ class ConversationTextview(gobject.GObject):
gajim.interface.instances[self.account]['join_gc'].window.present() gajim.interface.instances[self.account]['join_gc'].window.present()
else: else:
try: try:
dialogs.JoinGroupchatWindow(account=None, room_jid=room_jid) dialogs.JoinGroupchatWindow(account=self.account, room_jid=room_jid)
except GajimGeneralException: except GajimGeneralException:
pass pass

View File

@ -1922,7 +1922,7 @@ class JoinGroupchatWindow:
'''automatic is a dict like {'invities': []} '''automatic is a dict like {'invities': []}
If automatic is not empty, this means room must be automaticaly configured If automatic is not empty, this means room must be automaticaly configured
and when done, invities must be automatically invited''' and when done, invities must be automatically invited'''
self.xml = gtkgui_helpers.get_glade('join_groupchat_window.glade')
if account: if account:
if room_jid != '' and room_jid in gajim.gc_connected[account] and\ if room_jid != '' and room_jid in gajim.gc_connected[account] and\
gajim.gc_connected[account][room_jid]: gajim.gc_connected[account][room_jid]:
@ -1934,7 +1934,9 @@ class JoinGroupchatWindow:
ErrorDialog(_('You are not connected to the server'), ErrorDialog(_('You are not connected to the server'),
_('You can not join a group chat unless you are connected.')) _('You can not join a group chat unless you are connected.'))
raise GajimGeneralException, 'You must be connected to join a groupchat' raise GajimGeneralException, 'You must be connected to join a groupchat'
else:
self.xml = gtkgui_helpers.get_glade('join_groupchat_window.glade')
account_label = self.xml.get_widget('account_label') account_label = self.xml.get_widget('account_label')
account_combobox = self.xml.get_widget('account_combobox') account_combobox = self.xml.get_widget('account_combobox')
account_label.set_no_show_all(False) account_label.set_no_show_all(False)
@ -1944,10 +1946,14 @@ class JoinGroupchatWindow:
cell = gtk.CellRendererText() cell = gtk.CellRendererText()
account_combobox.pack_start(cell, True) account_combobox.pack_start(cell, True)
account_combobox.add_attribute(cell, 'text', 0) account_combobox.add_attribute(cell, 'text', 0)
account_combobox.set_active(-1)
# Add accounts, set current as active if it matches 'account'
for acct in [a for a in gajim.connections if \ for acct in [a for a in gajim.connections if \
gajim.account_is_connected(a)]: gajim.account_is_connected(a)]:
account_combobox.append_text(acct) account_combobox.append_text(acct)
account_combobox.set_active(-1) if account and account == acct:
account_combobox.set_active(liststore.iter_n_children(None)-1)
self.account = account self.account = account
self.automatic = automatic self.automatic = automatic
@ -2064,7 +2070,7 @@ class JoinGroupchatWindow:
user, server, resource = helpers.decompose_jid(room_jid) user, server, resource = helpers.decompose_jid(room_jid)
if not user or not server or resource: if not user or not server or resource:
ErrorDialog(_('Invalid group chat Jabber ID'), ErrorDialog(_('Invalid group chat Jabber ID'),
_('The group chat Jabber ID has not allowed characters.')) _('Please enter the group chat Jabber ID as room@server.'))
return return
try: try:
room_jid = helpers.parse_jid(room_jid) room_jid = helpers.parse_jid(room_jid)

File diff suppressed because it is too large Load Diff

View File

@ -647,7 +647,7 @@ class GroupchatControl(ChatControlBase):
bookmark_separator = xml.get_widget('bookmark_separator') bookmark_separator = xml.get_widget('bookmark_separator')
separatormenuitem2 = xml.get_widget('separatormenuitem2') separatormenuitem2 = xml.get_widget('separatormenuitem2')
if hide_buttonbar_entries: if hide_buttonbar_items:
change_nick_menuitem.hide() change_nick_menuitem.hide()
change_subject_menuitem.hide() change_subject_menuitem.hide()
bookmark_room_menuitem.hide() bookmark_room_menuitem.hide()

3475
src/gui_interface.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -83,15 +83,15 @@ common.configpaths.gajimpaths.init(config_path)
del config_path del config_path
common.configpaths.gajimpaths.init_profile() common.configpaths.gajimpaths.init_profile()
from common import exceptions from common import exceptions
import dialogs from common import gajim
import gtkgui_helpers import gtkgui_helpers
from common.logger import LOG_DB_PATH, constants from common.logger import LOG_DB_PATH, constants
#FIXME: constants should implement 2 way mappings #FIXME: constants should implement 2 way mappings
status = dict((constants.__dict__[i], i[5:].lower()) for i in \ status = dict((constants.__dict__[i], i[5:].lower()) for i in \
constants.__dict__.keys() if i.startswith('SHOW_')) constants.__dict__.keys() if i.startswith('SHOW_'))
from common import gajim
from common import helpers from common import helpers
import dialogs
# time, message, subject # time, message, subject
( (

View File

@ -1234,6 +1234,9 @@ class RosterWindow:
child_path = self.model.get_path(child_iter) child_path = self.model.get_path(child_iter)
path = self.modelfilter.convert_child_path_to_path(child_path) path = self.modelfilter.convert_child_path_to_path(child_path)
if not path:
continue
if not self.tree.row_expanded(path) and icon_name != 'event': if not self.tree.row_expanded(path) and icon_name != 'event':
iterC = self.model.iter_children(child_iter) iterC = self.model.iter_children(child_iter)
while iterC: while iterC:

View File

@ -0,0 +1,6 @@
'''
This package contains integration tests. Integration tests are tests
which require or include UI, network or both.
'''

View File

@ -14,34 +14,6 @@ gajim.logger = MockLogger()
Interface() Interface()
class TestMiscInterface(unittest.TestCase):
def test_links_regexp_entire(self):
def assert_matches_all(str_):
m = gajim.interface.basic_pattern_re.match(str_)
# the match should equal the string
str_span = (0, len(str_))
self.assertEqual(m.span(), str_span)
# these entire strings should be parsed as links
assert_matches_all('http://google.com/')
assert_matches_all('http://google.com')
assert_matches_all('http://www.google.ca/search?q=xmpp')
assert_matches_all('http://tools.ietf.org/html/draft-saintandre-rfc3920bis-05#section-12.3')
assert_matches_all('http://en.wikipedia.org/wiki/Protocol_(computing)')
assert_matches_all(
'http://en.wikipedia.org/wiki/Protocol_%28computing%29')
assert_matches_all('mailto:test@example.org')
assert_matches_all('xmpp:example-node@example.com')
assert_matches_all('xmpp:example-node@example.com/some-resource')
assert_matches_all('xmpp:example-node@example.com?message')
assert_matches_all('xmpp://guest@example.com/support@example.com?message')
import time import time
from data import * from data import *

View File

@ -1,5 +1,6 @@
''' '''
Unit test for tranports classes. Integration test for tranports classes. See unit for the ordinary
unit tests of this module.
''' '''
import unittest import unittest
@ -12,62 +13,6 @@ from xmpp_mocks import IdleQueueThread, IdleMock
from common.xmpp import transports_nb from common.xmpp import transports_nb
class TestModuleLevelFunctions(unittest.TestCase):
'''
Test class for functions defined at module level
'''
def test_urisplit(self):
def check_uri(uri, proto, host, path):
_proto, _host, _path = transports_nb.urisplit(uri)
self.assertEqual(proto, _proto)
self.assertEqual(host, _host)
self.assertEqual(path, _path)
check_uri('http://httpcm.jabber.org/webclient',
proto='http', host='httpcm.jabber.org', path='/webclient')
def test_get_proxy_data_from_dict(self):
def check_dict(proxy_dict, host, port, user, passwd):
_host, _port, _user, _passwd = transports_nb.get_proxy_data_from_dict(
proxy_dict)
self.assertEqual(_host, host)
self.assertEqual(_port, port)
self.assertEqual(_user, user)
self.assertEqual(_passwd, passwd)
bosh_dict = {'bosh_content': u'text/xml; charset=utf-8',
'bosh_hold': 2,
'bosh_http_pipelining': False,
'bosh_uri': u'http://gajim.org:5280/http-bind',
'bosh_useproxy': False,
'bosh_wait': 30,
'bosh_wait_for_restart_response': False,
'host': u'172.16.99.11',
'pass': u'pass',
'port': 3128,
'type': u'bosh',
'useauth': True,
'user': u'user'}
check_dict(bosh_dict, host=u'gajim.org', port=5280, user=u'user',
passwd=u'pass')
proxy_dict = {'bosh_content': u'text/xml; charset=utf-8',
'bosh_hold': 2,
'bosh_http_pipelining': False,
'bosh_port': 5280,
'bosh_uri': u'',
'bosh_useproxy': True,
'bosh_wait': 30,
'bosh_wait_for_restart_response': False,
'host': u'172.16.99.11',
'pass': u'pass',
'port': 3128,
'type': 'socks5',
'useauth': True,
'user': u'user'}
check_dict(proxy_dict, host=u'172.16.99.11', port=3128, user=u'user',
passwd=u'pass')
class AbstractTransportTest(unittest.TestCase): class AbstractTransportTest(unittest.TestCase):
''' Encapsulates Idlequeue instantiation for transports and more...''' ''' Encapsulates Idlequeue instantiation for transports and more...'''

View File

@ -91,6 +91,7 @@ class MockChatControl(Mock):
def __eq__(self, other): def __eq__(self, other):
return self is other return self is other
class MockInterface(Mock): class MockInterface(Mock):
def __init__(self, *args): def __init__(self, *args):
Mock.__init__(self, *args) Mock.__init__(self, *args)
@ -113,14 +114,17 @@ class MockInterface(Mock):
self.jabber_state_images = {'16': Mock(), '32': Mock(), self.jabber_state_images = {'16': Mock(), '32': Mock(),
'opened': Mock(), 'closed': Mock()} 'opened': Mock(), 'closed': Mock()}
class MockLogger(Mock): class MockLogger(Mock):
def __init__(self): def __init__(self):
Mock.__init__(self, {'write': None, 'get_transports_type': {}}) Mock.__init__(self, {'write': None, 'get_transports_type': {}})
class MockContact(Mock): class MockContact(Mock):
def __nonzero__(self): def __nonzero__(self):
return True return True
import random import random
class MockSession(Mock): class MockSession(Mock):

View File

@ -4,7 +4,7 @@
''' '''
Runs Gajim's Test Suite Runs Gajim's Test Suite
Non GUI related tests will be run on each commit. Unit tests tests will be run on each commit.
''' '''
import sys import sys
@ -35,19 +35,21 @@ for o, a in opts:
sys.exit(2) sys.exit(2)
# new test modules need to be added manually # new test modules need to be added manually
modules = ( 'test_xmpp_dispatcher_nb', modules = ( 'unit.test_xmpp_dispatcher_nb',
'test_xmpp_client_nb', 'unit.test_xmpp_transports_nb',
'test_xmpp_transports_nb', 'unit.test_caps',
'test_resolver', 'unit.test_contacts',
'test_caps', 'unit.test_gui_interface',
'test_contacts', 'unit.test_sessions',
) )
#modules = () #modules = ()
if use_x: if use_x:
modules += ('test_misc_interface', modules += ('integration.test_gui_event_integration',
'test_roster', 'integration.test_roster',
'test_sessions', 'integration.test_resolver',
'integration.test_xmpp_client_nb',
'integration.test_xmpp_transports_nb'
) )
nb_errors = 0 nb_errors = 0

5
test/unit/__init__.py Normal file
View File

@ -0,0 +1,5 @@
'''
This package just contains plain unit tests
'''

View File

@ -0,0 +1,112 @@
import unittest
import lib
lib.setup_env()
from common import logging_helpers
logging_helpers.set_quiet()
from common import gajim
from gajim_mocks import MockLogger
gajim.logger = MockLogger()
from gui_interface import Interface
class Test(unittest.TestCase):
def test_instantiation(self):
''' Test that we can proper initialize and do not fail on globals '''
interface = Interface()
interface.run()
def test_dispatch(self):
''' Test dispatcher forwarding network events to handler_* methods '''
sut = Interface()
success = sut.dispatch('No Such Event', None, None)
self.assertFalse(success, msg="Unexisting event handled")
success = sut.dispatch('STANZA_ARRIVED', None, None)
self.assertTrue(success, msg="Existing event must be handled")
def test_register_unregister_single_handler(self):
''' Register / Unregister a custom event handler '''
sut = Interface()
event = 'TESTS_ARE_COOL_EVENT'
self.called = False
def handler(account, data):
self.assertEqual(account, 'account')
self.assertEqual(data, 'data')
self.called = True
self.assertFalse(self.called)
sut.register_handler('TESTS_ARE_COOL_EVENT', handler)
sut.dispatch(event, 'account', 'data')
self.assertTrue(self.called, msg="Handler should have been called")
self.called = False
sut.unregister_handler('TESTS_ARE_COOL_EVENT', handler)
sut.dispatch(event, 'account', 'data')
self.assertFalse(self.called, msg="Handler should no longer be called")
def test_dispatch_to_multiple_handlers(self):
''' Register and dispatch a single event to multiple handlers '''
sut = Interface()
event = 'SINGLE_EVENT'
self.called_a = False
self.called_b = False
def handler_a(account, data):
self.assertFalse(self.called_a, msg="One must only be notified once")
self.called_a = True
def handler_b(account, data):
self.assertFalse(self.called_b, msg="One must only be notified once")
self.called_b = True
sut.register_handler(event, handler_a)
sut.register_handler(event, handler_b)
# register again
sut.register_handler('SOME_OTHER_EVENT', handler_b)
sut.register_handler(event, handler_a)
sut.dispatch(event, 'account', 'data')
self.assertTrue(self.called_a and self.called_b,
msg="Both handlers should have been called")
def test_links_regexp_entire(self):
sut = Interface()
def assert_matches_all(str_):
m = sut.basic_pattern_re.match(str_)
# the match should equal the string
str_span = (0, len(str_))
self.assertEqual(m.span(), str_span)
# these entire strings should be parsed as links
assert_matches_all('http://google.com/')
assert_matches_all('http://google.com')
assert_matches_all('http://www.google.ca/search?q=xmpp')
assert_matches_all('http://tools.ietf.org/html/draft-saintandre-rfc3920bis-05#section-12.3')
assert_matches_all('http://en.wikipedia.org/wiki/Protocol_(computing)')
assert_matches_all(
'http://en.wikipedia.org/wiki/Protocol_%28computing%29')
assert_matches_all('mailto:test@example.org')
assert_matches_all('xmpp:example-node@example.com')
assert_matches_all('xmpp:example-node@example.com/some-resource')
assert_matches_all('xmpp:example-node@example.com?message')
assert_matches_all('xmpp://guest@example.com/support@example.com?message')
if __name__ == "__main__":
#import sys;sys.argv = ['', 'Test.test']
unittest.main()

View File

@ -5,19 +5,27 @@ import time
import lib import lib
lib.setup_env() lib.setup_env()
import notify
from common import gajim from common import gajim
from common import xmpp from common import xmpp
from common.stanza_session import StanzaSession
from session import ChatControlSession
from mock import Mock, expectParams from mock import Mock, expectParams
from gajim_mocks import * from gajim_mocks import *
from common.stanza_session import StanzaSession gajim.interface = MockInterface()
# name to use for the test account # name to use for the test account
account_name = 'test' account_name = 'test'
class TestStanzaSession(unittest.TestCase): class TestStanzaSession(unittest.TestCase):
''' Testclass for common/stanzasession.py ''' ''' Testclass for common/stanzasession.py '''
def setUp(self): def setUp(self):
self.jid = 'test@example.org/Gajim' self.jid = 'test@example.org/Gajim'
self.conn = MockConnection(account_name, {'send_stanza': None}) self.conn = MockConnection(account_name, {'send_stanza': None})
@ -68,14 +76,10 @@ class TestStanzaSession(unittest.TestCase):
calls = self.conn.mockGetNamedCalls('send_stanza') calls = self.conn.mockGetNamedCalls('send_stanza')
self.assertEqual(0, len(calls)) self.assertEqual(0, len(calls))
from session import ChatControlSession
gajim.interface = MockInterface()
import notify
class TestChatControlSession(unittest.TestCase): class TestChatControlSession(unittest.TestCase):
''' Testclass for session.py ''' ''' Testclass for session.py '''
def setUp(self): def setUp(self):
self.jid = 'test@example.org/Gajim' self.jid = 'test@example.org/Gajim'
self.conn = MockConnection(account_name, {'send_stanza': None}) self.conn = MockConnection(account_name, {'send_stanza': None})

View File

@ -0,0 +1,80 @@
'''
Unit test for tranports classes.
'''
import unittest
import lib
lib.setup_env()
from common.xmpp import transports_nb
class TestModuleLevelFunctions(unittest.TestCase):
'''
Test class for functions defined at module level
'''
def test_urisplit(self):
def check_uri(uri, proto, host, port, path):
_proto, _host, _port, _path = transports_nb.urisplit(uri)
self.assertEqual(proto, _proto)
self.assertEqual(host, _host)
self.assertEqual(path, _path)
self.assertEqual(port, _port)
check_uri('http://httpcm.jabber.org:5280/webclient', proto='http',
host='httpcm.jabber.org', port=5280, path='/webclient')
check_uri('http://httpcm.jabber.org/webclient', proto='http',
host='httpcm.jabber.org', port=80, path='/webclient')
check_uri('https://httpcm.jabber.org/webclient', proto='https',
host='httpcm.jabber.org', port=443, path='/webclient')
def test_get_proxy_data_from_dict(self):
def check_dict(proxy_dict, host, port, user, passwd):
_host, _port, _user, _passwd = transports_nb.get_proxy_data_from_dict(
proxy_dict)
self.assertEqual(_host, host)
self.assertEqual(_port, port)
self.assertEqual(_user, user)
self.assertEqual(_passwd, passwd)
bosh_dict = {'bosh_content': u'text/xml; charset=utf-8',
'bosh_hold': 2,
'bosh_http_pipelining': False,
'bosh_uri': u'http://gajim.org:5280/http-bind',
'bosh_useproxy': False,
'bosh_wait': 30,
'bosh_wait_for_restart_response': False,
'host': u'172.16.99.11',
'pass': u'pass',
'port': 3128,
'type': u'bosh',
'useauth': True,
'user': u'user'}
check_dict(bosh_dict, host=u'gajim.org', port=5280, user=u'user',
passwd=u'pass')
proxy_dict = {'bosh_content': u'text/xml; charset=utf-8',
'bosh_hold': 2,
'bosh_http_pipelining': False,
'bosh_port': 5280,
'bosh_uri': u'',
'bosh_useproxy': True,
'bosh_wait': 30,
'bosh_wait_for_restart_response': False,
'host': u'172.16.99.11',
'pass': u'pass',
'port': 3128,
'type': 'socks5',
'useauth': True,
'user': u'user'}
check_dict(proxy_dict, host=u'172.16.99.11', port=3128, user=u'user',
passwd=u'pass')
if __name__ == '__main__':
unittest.main()
# vim: se ts=3: