2008-08-15 17:31:51 +00:00
# -*- coding:utf-8 -*-
2008-08-15 03:20:23 +00:00
## src/common/connection_handlers.py
2006-03-19 14:54:00 +00:00
##
2008-08-15 03:20:23 +00:00
## Copyright (C) 2006 Dimitur Kirov <dkirov AT gmail.com>
2008-08-15 17:31:51 +00:00
## Junglecow J <junglecow AT gmail.com>
2008-08-15 03:20:23 +00:00
## Copyright (C) 2006-2007 Tomasz Melcer <liori AT exroot.org>
## Travis Shirk <travis AT pobox.com>
## Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2006-2008 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2007 Julien Pivotto <roidelapluie AT gmail.com>
## Copyright (C) 2007-2008 Brendan Taylor <whateley AT gmail.com>
## Jean-Marie Traissard <jim AT lapin.org>
## Stephan Erb <steve-e AT h3c.de>
## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
2006-03-19 14:54:00 +00:00
##
2007-12-12 08:44:46 +00:00
## This file is part of Gajim.
##
## Gajim is free software; you can redistribute it and/or modify
2006-03-19 14:54:00 +00:00
## it under the terms of the GNU General Public License as published
2007-12-12 08:44:46 +00:00
## by the Free Software Foundation; version 3 only.
2006-03-19 14:54:00 +00:00
##
2007-12-12 08:44:46 +00:00
## Gajim is distributed in the hope that it will be useful,
2006-03-19 14:54:00 +00:00
## but WITHOUT ANY WARRANTY; without even the implied warranty of
2008-08-15 03:20:23 +00:00
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2006-03-19 14:54:00 +00:00
## GNU General Public License for more details.
##
2007-12-12 08:44:46 +00:00
## You should have received a copy of the GNU General Public License
2008-08-15 03:20:23 +00:00
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
2007-12-12 08:44:46 +00:00
##
2006-03-19 14:54:00 +00:00
import os
2006-03-21 15:57:44 +00:00
import base64
2006-03-19 14:54:00 +00:00
import socket
2006-04-11 18:36:09 +00:00
import sys
2008-12-03 22:07:44 +00:00
import operator
2009-01-08 16:51:26 +00:00
import hashlib
2009-10-13 19:26:56 +02:00
import hmac
2006-03-19 14:54:00 +00:00
2007-08-09 15:39:18 +00:00
from time import ( altzone , daylight , gmtime , localtime , mktime , strftime ,
2007-12-12 08:44:46 +00:00
time as time_time , timezone , tzname )
2006-03-19 14:54:00 +00:00
from calendar import timegm
2009-02-10 21:45:44 +00:00
import datetime
2006-03-19 14:54:00 +00:00
import socks5
import common . xmpp
from common import helpers
from common import gajim
2007-08-09 15:39:18 +00:00
from common import exceptions
2006-07-17 13:40:25 +00:00
from common . commands import ConnectionCommands
2006-08-20 10:18:20 +00:00
from common . pubsub import ConnectionPubSub
2009-11-14 19:56:15 +01:00
from common . pep import ConnectionPEP
2007-08-09 15:39:18 +00:00
from common . caps import ConnectionCaps
2009-09-20 20:46:03 +02:00
if gajim . HAVE_FARSIGHT :
from common . jingle import ConnectionJingle
else :
class ConnectionJingle ( ) :
def __init__ ( self ) :
pass
def _JingleCB ( self , con , stanza ) :
pass
2006-03-19 14:54:00 +00:00
2007-08-10 20:18:32 +00:00
from common import dbus_support
if dbus_support . supported :
import dbus
from music_track_listener import MusicTrackListener
2008-12-24 12:11:02 +00:00
import logging
log = logging . getLogger ( ' gajim.c.connection_handlers ' )
2006-03-19 14:54:00 +00:00
# kind of events we can wait for an answer
VCARD_PUBLISHED = ' vcard_published '
VCARD_ARRIVED = ' vcard_arrived '
2006-05-01 18:29:12 +00:00
AGENT_REMOVED = ' agent_removed '
2006-09-13 16:47:58 +00:00
METACONTACTS_ARRIVED = ' metacontacts_arrived '
2009-06-27 17:56:04 +02:00
ROSTER_ARRIVED = ' roster_arrived '
2006-11-18 20:52:28 +00:00
PRIVACY_ARRIVED = ' privacy_arrived '
2008-02-15 22:55:21 +00:00
PEP_CONFIG = ' pep_config '
2006-03-19 14:54:00 +00:00
HAS_IDLE = True
try :
2006-11-18 20:52:28 +00:00
import idle
2008-10-11 09:37:13 +00:00
except Exception :
2008-12-24 12:11:02 +00:00
log . debug ( _ ( ' Unable to load idle module ' ) )
2006-11-18 20:52:28 +00:00
HAS_IDLE = False
2006-03-19 14:54:00 +00:00
class ConnectionBytestream :
def __init__ ( self ) :
self . files_props = { }
2008-12-03 19:56:37 +00:00
self . awaiting_xmpp_ping_id = None
2007-12-12 08:44:46 +00:00
def is_transfer_stopped ( self , file_props ) :
2008-10-07 20:41:59 +00:00
if ' error ' in file_props and file_props [ ' error ' ] != 0 :
2006-03-23 00:11:50 +00:00
return True
2008-10-07 20:41:59 +00:00
if ' completed ' in file_props and file_props [ ' completed ' ] :
2006-03-23 00:11:50 +00:00
return True
2008-10-07 20:41:59 +00:00
if ' connected ' in file_props and file_props [ ' connected ' ] == False :
2006-03-23 00:11:50 +00:00
return True
2008-10-07 20:41:59 +00:00
if ' stopped ' not in file_props or not file_props [ ' stopped ' ] :
2006-03-23 00:11:50 +00:00
return False
return True
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def send_success_connect_reply ( self , streamhost ) :
''' send reply to the initiator of FT that we
made a connection
'''
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
return
2006-03-19 14:54:00 +00:00
if streamhost is None :
return None
iq = common . xmpp . Iq ( to = streamhost [ ' initiator ' ] , typ = ' result ' ,
frm = streamhost [ ' target ' ] )
iq . setAttr ( ' id ' , streamhost [ ' id ' ] )
query = iq . setTag ( ' query ' )
query . setNamespace ( common . xmpp . NS_BYTESTREAM )
stream_tag = query . setTag ( ' streamhost-used ' )
stream_tag . setAttr ( ' jid ' , streamhost [ ' jid ' ] )
self . connection . send ( iq )
2008-05-17 02:23:46 +00:00
2006-03-21 23:43:26 +00:00
def remove_transfers_for_contact ( self , contact ) :
''' stop all active transfer for contact '''
for file_props in self . files_props . values ( ) :
2007-12-12 08:44:46 +00:00
if self . is_transfer_stopped ( file_props ) :
2006-03-23 00:11:50 +00:00
continue
2009-04-29 07:46:24 +00:00
receiver_jid = unicode ( file_props [ ' receiver ' ] )
if contact . get_full_jid ( ) == receiver_jid :
2006-03-21 23:43:26 +00:00
file_props [ ' error ' ] = - 5
self . remove_transfer ( file_props )
2006-11-18 20:52:28 +00:00
self . dispatch ( ' FILE_REQUEST_ERROR ' , ( contact . jid , file_props , ' ' ) )
2009-04-29 07:46:24 +00:00
sender_jid = unicode ( file_props [ ' sender ' ] )
if contact . get_full_jid ( ) == sender_jid :
2006-03-21 23:43:26 +00:00
file_props [ ' error ' ] = - 3
self . remove_transfer ( file_props )
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def remove_all_transfers ( self ) :
''' stops and removes all active connections from the socks5 pool '''
for file_props in self . files_props . values ( ) :
self . remove_transfer ( file_props , remove_from_list = False )
del ( self . files_props )
self . files_props = { }
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def remove_transfer ( self , file_props , remove_from_list = True ) :
if file_props is None :
return
self . disconnect_transfer ( file_props )
sid = file_props [ ' sid ' ]
gajim . socks5queue . remove_file_props ( self . name , sid )
if remove_from_list :
2008-10-07 20:41:59 +00:00
if ' sid ' in self . files_props :
2006-03-19 14:54:00 +00:00
del ( self . files_props [ ' sid ' ] )
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def disconnect_transfer ( self , file_props ) :
if file_props is None :
return
2008-10-07 20:41:59 +00:00
if ' hash ' in file_props :
2006-03-19 14:54:00 +00:00
gajim . socks5queue . remove_sender ( file_props [ ' hash ' ] )
2008-10-07 20:41:59 +00:00
if ' streamhosts ' in file_props :
2006-03-19 14:54:00 +00:00
for host in file_props [ ' streamhosts ' ] :
2008-10-07 20:41:59 +00:00
if ' idx ' in host and host [ ' idx ' ] > 0 :
2006-03-19 14:54:00 +00:00
gajim . socks5queue . remove_receiver ( host [ ' idx ' ] )
gajim . socks5queue . remove_sender ( host [ ' idx ' ] )
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def send_socks5_info ( self , file_props , fast = True , receiver = None ,
sender = None ) :
''' send iq for the present streamhosts and proxies '''
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
return
2008-10-11 09:59:52 +00:00
if not isinstance ( self . peerhost , tuple ) :
2006-03-19 14:54:00 +00:00
return
port = gajim . config . get ( ' file_transfers_port ' )
2007-01-28 19:11:39 +00:00
ft_add_hosts_to_send = gajim . config . get ( ' ft_add_hosts_to_send ' )
2006-03-19 14:54:00 +00:00
cfg_proxies = gajim . config . get_per ( ' accounts ' , self . name ,
' file_transfer_proxies ' )
if receiver is None :
receiver = file_props [ ' receiver ' ]
if sender is None :
sender = file_props [ ' sender ' ]
proxyhosts = [ ]
if fast and cfg_proxies :
2008-12-03 22:07:44 +00:00
proxies = [ e . strip ( ) for e in cfg_proxies . split ( ' , ' ) ]
2006-03-20 23:17:36 +00:00
default = gajim . proxy65_manager . get_default_for_name ( self . name )
if default :
# add/move default proxy at top of the others
if proxies . __contains__ ( default ) :
proxies . remove ( default )
proxies . insert ( 0 , default )
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
for proxy in proxies :
2006-03-20 23:17:36 +00:00
( host , _port , jid ) = gajim . proxy65_manager . get_proxy ( proxy , self . name )
2006-03-19 14:54:00 +00:00
if host is None :
continue
host_dict = {
' state ' : 0 ,
' target ' : unicode ( receiver ) ,
' id ' : file_props [ ' sid ' ] ,
' sid ' : file_props [ ' sid ' ] ,
' initiator ' : proxy ,
' host ' : host ,
' port ' : unicode ( _port ) ,
' jid ' : jid
}
proxyhosts . append ( host_dict )
sha_str = helpers . get_auth_sha ( file_props [ ' sid ' ] , sender ,
receiver )
file_props [ ' sha_str ' ] = sha_str
2007-01-28 19:11:39 +00:00
ft_add_hosts = [ ]
if ft_add_hosts_to_send :
2008-12-03 22:07:44 +00:00
ft_add_hosts_to_send = [ e . strip ( ) for e in ft_add_hosts_to_send . split ( ' , ' ) ]
2007-01-28 19:11:39 +00:00
for ft_host in ft_add_hosts_to_send :
2007-12-27 18:58:07 +00:00
ft_add_hosts . append ( ft_host )
2006-11-18 20:52:28 +00:00
listener = gajim . socks5queue . start_listener ( port ,
2006-03-19 14:54:00 +00:00
sha_str , self . _result_socks5_sid , file_props [ ' sid ' ] )
2008-04-18 00:02:56 +00:00
if listener is None :
2006-03-19 14:54:00 +00:00
file_props [ ' error ' ] = - 5
2006-11-18 20:52:28 +00:00
self . dispatch ( ' FILE_REQUEST_ERROR ' , ( unicode ( receiver ) , file_props ,
' ' ) )
2006-03-19 14:54:00 +00:00
self . _connect_error ( unicode ( receiver ) , file_props [ ' sid ' ] ,
file_props [ ' sid ' ] , code = 406 )
return
iq = common . xmpp . Protocol ( name = ' iq ' , to = unicode ( receiver ) ,
typ = ' set ' )
file_props [ ' request-id ' ] = ' id_ ' + file_props [ ' sid ' ]
iq . setID ( file_props [ ' request-id ' ] )
query = iq . setTag ( ' query ' )
query . setNamespace ( common . xmpp . NS_BYTESTREAM )
2008-08-05 23:52:35 +00:00
query . setAttr ( ' mode ' , ' plain ' )
2006-03-19 14:54:00 +00:00
query . setAttr ( ' sid ' , file_props [ ' sid ' ] )
2007-01-28 19:11:39 +00:00
for ft_host in ft_add_hosts :
# The streamhost, if set
ostreamhost = common . xmpp . Node ( tag = ' streamhost ' )
query . addChild ( node = ostreamhost )
ostreamhost . setAttr ( ' port ' , unicode ( port ) )
ostreamhost . setAttr ( ' host ' , ft_host )
ostreamhost . setAttr ( ' jid ' , sender )
2007-12-12 08:44:46 +00:00
try :
2009-07-16 15:29:07 +02:00
# The ip we're connected to server with
my_ips = [ self . peerhost [ 0 ] ]
# all IPs from local DNS
for addr in socket . getaddrinfo ( socket . gethostname ( ) , None ) :
2009-07-31 10:57:48 +02:00
if not addr [ 4 ] [ 0 ] in my_ips and not addr [ 4 ] [ 0 ] . startswith ( ' 127 ' ) :
2009-07-16 15:29:07 +02:00
my_ips . append ( addr [ 4 ] [ 0 ] )
for ip in my_ips :
streamhost = common . xmpp . Node ( tag = ' streamhost ' )
query . addChild ( node = streamhost )
streamhost . setAttr ( ' port ' , unicode ( port ) )
streamhost . setAttr ( ' host ' , ip )
streamhost . setAttr ( ' jid ' , sender )
2007-12-12 08:44:46 +00:00
except socket . gaierror :
self . dispatch ( ' ERROR ' , ( _ ( ' Wrong host ' ) ,
_ ( ' Invalid local address? :-O ' ) ) )
2007-01-28 19:11:39 +00:00
2006-03-27 08:28:05 +00:00
if fast and proxyhosts != [ ] and gajim . config . get_per ( ' accounts ' ,
self . name , ' use_ft_proxies ' ) :
2006-03-19 14:54:00 +00:00
file_props [ ' proxy_receiver ' ] = unicode ( receiver )
file_props [ ' proxy_sender ' ] = unicode ( sender )
file_props [ ' proxyhosts ' ] = proxyhosts
for proxyhost in proxyhosts :
streamhost = common . xmpp . Node ( tag = ' streamhost ' )
query . addChild ( node = streamhost )
streamhost . setAttr ( ' port ' , proxyhost [ ' port ' ] )
streamhost . setAttr ( ' host ' , proxyhost [ ' host ' ] )
streamhost . setAttr ( ' jid ' , proxyhost [ ' jid ' ] )
# don't add the proxy child tag for streamhosts, which are proxies
# proxy = streamhost.setTag('proxy')
# proxy.setNamespace(common.xmpp.NS_STREAM)
self . connection . send ( iq )
2008-12-24 12:11:02 +00:00
def send_file_rejection ( self , file_props , code = ' 403 ' , typ = None ) :
''' informs sender that we refuse to download the file
typ is used when code = ' 400 ' , in this case typ can be ' strean ' for
invalid stream or ' profile ' for invalid profile '''
2006-04-08 16:40:43 +00:00
# user response to ConfirmationDialog may come after we've disconneted
if not self . connection or self . connected < 2 :
return
2006-03-19 14:54:00 +00:00
iq = common . xmpp . Protocol ( name = ' iq ' ,
to = unicode ( file_props [ ' sender ' ] ) , typ = ' error ' )
iq . setAttr ( ' id ' , file_props [ ' request-id ' ] )
2008-12-24 12:11:02 +00:00
if code == ' 400 ' and typ in ( ' stream ' , ' profile ' ) :
name = ' bad-request '
text = ' '
else :
name = ' forbidden '
text = ' Offer Declined '
err = common . xmpp . ErrorNode ( code = code , typ = ' cancel ' , name = name , text = text )
if code == ' 400 ' and typ in ( ' stream ' , ' profile ' ) :
if typ == ' stream ' :
err . setTag ( ' no-valid-streams ' , namespace = common . xmpp . NS_SI )
else :
err . setTag ( ' bad-profile ' , namespace = common . xmpp . NS_SI )
2006-03-19 14:54:00 +00:00
iq . addChild ( node = err )
self . connection . send ( iq )
def send_file_approval ( self , file_props ) :
''' send iq, confirming that we want to download the file '''
2006-04-08 16:40:43 +00:00
# user response to ConfirmationDialog may come after we've disconneted
if not self . connection or self . connected < 2 :
return
2006-03-19 14:54:00 +00:00
iq = common . xmpp . Protocol ( name = ' iq ' ,
to = unicode ( file_props [ ' sender ' ] ) , typ = ' result ' )
iq . setAttr ( ' id ' , file_props [ ' request-id ' ] )
si = iq . setTag ( ' si ' )
si . setNamespace ( common . xmpp . NS_SI )
2008-10-07 20:41:59 +00:00
if ' offset ' in file_props and file_props [ ' offset ' ] :
2006-04-04 08:31:36 +00:00
file_tag = si . setTag ( ' file ' )
file_tag . setNamespace ( common . xmpp . NS_FILE )
2006-03-19 14:54:00 +00:00
range_tag = file_tag . setTag ( ' range ' )
range_tag . setAttr ( ' offset ' , file_props [ ' offset ' ] )
feature = si . setTag ( ' feature ' )
feature . setNamespace ( common . xmpp . NS_FEATURE )
_feature = common . xmpp . DataForm ( typ = ' submit ' )
feature . addChild ( node = _feature )
field = _feature . setField ( ' stream-method ' )
field . delAttr ( ' type ' )
field . setValue ( common . xmpp . NS_BYTESTREAM )
self . connection . send ( iq )
def send_file_request ( self , file_props ) :
''' send iq for new FT request '''
2006-04-13 18:00:04 +00:00
if not self . connection or self . connected < 2 :
return
2006-03-19 14:54:00 +00:00
our_jid = gajim . get_jid_from_account ( self . name )
resource = self . server_resource
frm = our_jid + ' / ' + resource
file_props [ ' sender ' ] = frm
fjid = file_props [ ' receiver ' ] . jid + ' / ' + file_props [ ' receiver ' ] . resource
iq = common . xmpp . Protocol ( name = ' iq ' , to = fjid ,
typ = ' set ' )
iq . setID ( file_props [ ' sid ' ] )
self . files_props [ file_props [ ' sid ' ] ] = file_props
si = iq . setTag ( ' si ' )
si . setNamespace ( common . xmpp . NS_SI )
si . setAttr ( ' profile ' , common . xmpp . NS_FILE )
si . setAttr ( ' id ' , file_props [ ' sid ' ] )
file_tag = si . setTag ( ' file ' )
file_tag . setNamespace ( common . xmpp . NS_FILE )
file_tag . setAttr ( ' name ' , file_props [ ' name ' ] )
file_tag . setAttr ( ' size ' , file_props [ ' size ' ] )
desc = file_tag . setTag ( ' desc ' )
2008-10-07 20:41:59 +00:00
if ' desc ' in file_props :
2006-03-19 14:54:00 +00:00
desc . setData ( file_props [ ' desc ' ] )
file_tag . setTag ( ' range ' )
feature = si . setTag ( ' feature ' )
feature . setNamespace ( common . xmpp . NS_FEATURE )
_feature = common . xmpp . DataForm ( typ = ' form ' )
feature . addChild ( node = _feature )
field = _feature . setField ( ' stream-method ' )
field . setAttr ( ' type ' , ' list-single ' )
field . addOption ( common . xmpp . NS_BYTESTREAM )
self . connection . send ( iq )
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def _result_socks5_sid ( self , sid , hash_id ) :
''' store the result of sha message from auth. '''
2008-10-07 20:41:59 +00:00
if sid not in self . files_props :
2006-03-19 14:54:00 +00:00
return
file_props = self . files_props [ sid ]
file_props [ ' hash ' ] = hash_id
return
2008-05-17 02:23:46 +00:00
2009-10-08 17:51:49 +02:00
def _connect_error ( self , to , _id , sid , code = 404 ) :
2008-12-03 21:56:12 +00:00
''' cb, when there is an error establishing BS connection, or
2006-03-19 14:54:00 +00:00
when connection is rejected '''
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
return
2006-03-19 14:54:00 +00:00
msg_dict = {
404 : ' Could not connect to given hosts ' ,
405 : ' Cancel ' ,
406 : ' Not acceptable ' ,
}
msg = msg_dict [ code ]
iq = None
iq = common . xmpp . Protocol ( name = ' iq ' , to = to ,
typ = ' error ' )
iq . setAttr ( ' id ' , _id )
err = iq . setTag ( ' error ' )
err . setAttr ( ' code ' , unicode ( code ) )
err . setData ( msg )
self . connection . send ( iq )
if code == 404 :
file_props = gajim . socks5queue . get_file_props ( self . name , sid )
if file_props is not None :
self . disconnect_transfer ( file_props )
file_props [ ' error ' ] = - 3
2006-11-18 20:52:28 +00:00
self . dispatch ( ' FILE_REQUEST_ERROR ' , ( to , file_props , msg ) )
2006-03-19 14:54:00 +00:00
def _proxy_auth_ok ( self , proxy ) :
''' cb, called after authentication to proxy server '''
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
return
2006-03-19 14:54:00 +00:00
file_props = self . files_props [ proxy [ ' sid ' ] ]
iq = common . xmpp . Protocol ( name = ' iq ' , to = proxy [ ' initiator ' ] ,
typ = ' set ' )
auth_id = " au_ " + proxy [ ' sid ' ]
iq . setID ( auth_id )
query = iq . setTag ( ' query ' )
query . setNamespace ( common . xmpp . NS_BYTESTREAM )
2007-12-12 08:44:46 +00:00
query . setAttr ( ' sid ' , proxy [ ' sid ' ] )
2006-03-19 14:54:00 +00:00
activate = query . setTag ( ' activate ' )
activate . setData ( file_props [ ' proxy_receiver ' ] )
iq . setID ( auth_id )
self . connection . send ( iq )
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
# register xmpppy handlers for bytestream and FT stanzas
def _bytestreamErrorCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' _bytestreamErrorCB ' )
2008-12-03 17:16:04 +00:00
id_ = unicode ( iq_obj . getAttr ( ' id ' ) )
2006-03-20 21:24:10 +00:00
frm = helpers . get_full_jid_from_iq ( iq_obj )
2006-03-19 14:54:00 +00:00
query = iq_obj . getTag ( ' query ' )
2006-03-20 21:24:10 +00:00
gajim . proxy65_manager . error_cb ( frm , query )
2006-03-19 14:54:00 +00:00
jid = helpers . get_jid_from_iq ( iq_obj )
2008-12-03 17:16:04 +00:00
id_ = id_ [ 3 : ]
if id_ not in self . files_props :
2006-03-19 14:54:00 +00:00
return
2008-12-03 17:16:04 +00:00
file_props = self . files_props [ id_ ]
2006-03-19 14:54:00 +00:00
file_props [ ' error ' ] = - 4
2006-11-18 20:52:28 +00:00
self . dispatch ( ' FILE_REQUEST_ERROR ' , ( jid , file_props , ' ' ) )
2006-03-19 14:54:00 +00:00
raise common . xmpp . NodeProcessed
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def _bytestreamSetCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' _bytestreamSetCB ' )
2006-03-19 14:54:00 +00:00
target = unicode ( iq_obj . getAttr ( ' to ' ) )
2008-12-03 17:16:04 +00:00
id_ = unicode ( iq_obj . getAttr ( ' id ' ) )
2006-03-19 14:54:00 +00:00
query = iq_obj . getTag ( ' query ' )
sid = unicode ( query . getAttr ( ' sid ' ) )
file_props = gajim . socks5queue . get_file_props (
self . name , sid )
streamhosts = [ ]
for item in query . getChildren ( ) :
if item . getName ( ) == ' streamhost ' :
host_dict = {
' state ' : 0 ,
' target ' : target ,
2008-12-03 17:16:04 +00:00
' id ' : id_ ,
2006-03-19 14:54:00 +00:00
' sid ' : sid ,
' initiator ' : helpers . get_full_jid_from_iq ( iq_obj )
}
for attr in item . getAttrs ( ) :
host_dict [ attr ] = item . getAttr ( attr )
streamhosts . append ( host_dict )
if file_props is None :
2008-10-07 20:41:59 +00:00
if sid in self . files_props :
2006-03-19 14:54:00 +00:00
file_props = self . files_props [ sid ]
file_props [ ' fast ' ] = streamhosts
if file_props [ ' type ' ] == ' s ' : # FIXME: remove fast xmlns
# only psi do this
2008-10-07 20:41:59 +00:00
if ' streamhosts ' in file_props :
2006-03-19 14:54:00 +00:00
file_props [ ' streamhosts ' ] . extend ( streamhosts )
else :
file_props [ ' streamhosts ' ] = streamhosts
if not gajim . socks5queue . get_file_props ( self . name , sid ) :
gajim . socks5queue . add_file_props ( self . name , file_props )
gajim . socks5queue . connect_to_hosts ( self . name , sid ,
self . send_success_connect_reply , None )
raise common . xmpp . NodeProcessed
file_props [ ' streamhosts ' ] = streamhosts
if file_props [ ' type ' ] == ' r ' :
gajim . socks5queue . connect_to_hosts ( self . name , sid ,
self . send_success_connect_reply , self . _connect_error )
raise common . xmpp . NodeProcessed
2006-04-11 22:23:51 +00:00
def _ResultCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' _ResultCB ' )
2007-08-09 15:39:18 +00:00
# if we want to respect xep-0065 we have to check for proxy
2006-04-11 22:23:51 +00:00
# activation result in any result iq
real_id = unicode ( iq_obj . getAttr ( ' id ' ) )
2008-02-07 23:53:02 +00:00
if real_id == self . awaiting_xmpp_ping_id :
self . awaiting_xmpp_ping_id = None
return
2008-04-21 20:39:55 +00:00
if not real_id . startswith ( ' au_ ' ) :
2008-02-08 07:58:23 +00:00
return
2006-04-11 22:23:51 +00:00
frm = helpers . get_full_jid_from_iq ( iq_obj )
2008-12-03 17:16:04 +00:00
id_ = real_id [ 3 : ]
if id_ in self . files_props :
file_props = self . files_props [ id_ ]
2006-04-11 22:23:51 +00:00
if file_props [ ' streamhost-used ' ] :
for host in file_props [ ' proxyhosts ' ] :
2008-10-07 20:41:59 +00:00
if host [ ' initiator ' ] == frm and ' idx ' in host :
2006-04-11 22:23:51 +00:00
gajim . socks5queue . activate_proxy ( host [ ' idx ' ] )
raise common . xmpp . NodeProcessed
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def _bytestreamResultCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' _bytestreamResultCB ' )
2006-03-19 14:54:00 +00:00
frm = helpers . get_full_jid_from_iq ( iq_obj )
real_id = unicode ( iq_obj . getAttr ( ' id ' ) )
query = iq_obj . getTag ( ' query ' )
2006-03-19 20:43:30 +00:00
gajim . proxy65_manager . resolve_result ( frm , query )
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
try :
2007-12-12 08:44:46 +00:00
streamhost = query . getTag ( ' streamhost-used ' )
2008-10-11 09:37:13 +00:00
except Exception : # this bytestream result is not what we need
2006-03-19 14:54:00 +00:00
pass
2008-12-03 17:16:04 +00:00
id_ = real_id [ 3 : ]
if id_ in self . files_props :
file_props = self . files_props [ id_ ]
2006-03-19 14:54:00 +00:00
else :
raise common . xmpp . NodeProcessed
if streamhost is None :
# proxy approves the activate query
2008-10-11 09:32:59 +00:00
if real_id . startswith ( ' au_ ' ) :
2008-10-07 20:41:59 +00:00
if ' streamhost-used ' not in file_props or \
2008-12-03 17:16:04 +00:00
file_props [ ' streamhost-used ' ] is False :
2006-03-19 14:54:00 +00:00
raise common . xmpp . NodeProcessed
2008-10-07 20:41:59 +00:00
if ' proxyhosts ' not in file_props :
2006-03-19 14:54:00 +00:00
raise common . xmpp . NodeProcessed
for host in file_props [ ' proxyhosts ' ] :
if host [ ' initiator ' ] == frm and \
unicode ( query . getAttr ( ' sid ' ) ) == file_props [ ' sid ' ] :
gajim . socks5queue . activate_proxy ( host [ ' idx ' ] )
break
raise common . xmpp . NodeProcessed
2009-07-07 16:56:04 +02:00
jid = helpers . parse_jid ( streamhost . getAttr ( ' jid ' ) )
2008-10-07 20:41:59 +00:00
if ' streamhost-used ' in file_props and \
2006-03-19 14:54:00 +00:00
file_props [ ' streamhost-used ' ] is True :
raise common . xmpp . NodeProcessed
2008-10-11 09:32:59 +00:00
if real_id . startswith ( ' au_ ' ) :
2008-10-07 20:41:59 +00:00
if ' stopped ' in file and file_props [ ' stopped ' ] :
2007-12-12 08:44:46 +00:00
self . remove_transfer ( file_props )
else :
gajim . socks5queue . send_file ( file_props , self . name )
2006-03-19 14:54:00 +00:00
raise common . xmpp . NodeProcessed
proxy = None
2008-10-07 20:41:59 +00:00
if ' proxyhosts ' in file_props :
2006-03-19 14:54:00 +00:00
for proxyhost in file_props [ ' proxyhosts ' ] :
if proxyhost [ ' jid ' ] == jid :
proxy = proxyhost
2008-04-18 00:26:07 +00:00
if proxy is not None :
2006-03-19 14:54:00 +00:00
file_props [ ' streamhost-used ' ] = True
2008-10-07 20:41:59 +00:00
if ' streamhosts ' not in file_props :
2006-03-19 14:54:00 +00:00
file_props [ ' streamhosts ' ] = [ ]
file_props [ ' streamhosts ' ] . append ( proxy )
file_props [ ' is_a_proxy ' ] = True
2008-12-03 17:16:04 +00:00
receiver = socks5 . Socks5Receiver ( gajim . idlequeue , proxy ,
file_props [ ' sid ' ] , file_props )
2006-03-19 14:54:00 +00:00
gajim . socks5queue . add_receiver ( self . name , receiver )
proxy [ ' idx ' ] = receiver . queue_idx
gajim . socks5queue . on_success = self . _proxy_auth_ok
raise common . xmpp . NodeProcessed
else :
2008-10-07 20:41:59 +00:00
if ' stopped ' in file_props and file_props [ ' stopped ' ] :
2007-12-12 08:44:46 +00:00
self . remove_transfer ( file_props )
else :
gajim . socks5queue . send_file ( file_props , self . name )
2008-10-07 20:41:59 +00:00
if ' fast ' in file_props :
2006-03-19 14:54:00 +00:00
fasts = file_props [ ' fast ' ]
if len ( fasts ) > 0 :
self . _connect_error ( frm , fasts [ 0 ] [ ' id ' ] , file_props [ ' sid ' ] ,
code = 406 )
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
raise common . xmpp . NodeProcessed
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def _siResultCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' _siResultCB ' )
2008-12-03 17:16:04 +00:00
id_ = iq_obj . getAttr ( ' id ' )
if id_ not in self . files_props :
2006-03-19 14:54:00 +00:00
# no such jid
return
2008-12-03 17:16:04 +00:00
file_props = self . files_props [ id_ ]
2006-03-19 14:54:00 +00:00
if file_props is None :
# file properties for jid is none
return
2008-10-07 20:41:59 +00:00
if ' request-id ' in file_props :
2006-04-13 18:00:04 +00:00
# we have already sent streamhosts info
return
2006-03-19 14:54:00 +00:00
file_props [ ' receiver ' ] = helpers . get_full_jid_from_iq ( iq_obj )
si = iq_obj . getTag ( ' si ' )
file_tag = si . getTag ( ' file ' )
range_tag = None
if file_tag :
range_tag = file_tag . getTag ( ' range ' )
if range_tag :
offset = range_tag . getAttr ( ' offset ' )
if offset :
file_props [ ' offset ' ] = int ( offset )
length = range_tag . getAttr ( ' length ' )
if length :
file_props [ ' length ' ] = int ( length )
feature = si . setTag ( ' feature ' )
if feature . getNamespace ( ) != common . xmpp . NS_FEATURE :
return
form_tag = feature . getTag ( ' x ' )
form = common . xmpp . DataForm ( node = form_tag )
field = form . getField ( ' stream-method ' )
if field . getValue ( ) != common . xmpp . NS_BYTESTREAM :
return
self . send_socks5_info ( file_props , fast = True )
raise common . xmpp . NodeProcessed
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def _siSetCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' _siSetCB ' )
2006-03-19 14:54:00 +00:00
jid = helpers . get_jid_from_iq ( iq_obj )
2008-12-24 12:11:02 +00:00
file_props = { ' type ' : ' r ' }
file_props [ ' sender ' ] = helpers . get_full_jid_from_iq ( iq_obj )
file_props [ ' request-id ' ] = unicode ( iq_obj . getAttr ( ' id ' ) )
2006-03-19 14:54:00 +00:00
si = iq_obj . getTag ( ' si ' )
profile = si . getAttr ( ' profile ' )
mime_type = si . getAttr ( ' mime-type ' )
if profile != common . xmpp . NS_FILE :
2008-12-24 12:11:02 +00:00
self . send_file_rejection ( file_props , code = ' 400 ' , typ = ' profile ' )
raise common . xmpp . NodeProcessed
feature_tag = si . getTag ( ' feature ' , namespace = common . xmpp . NS_FEATURE )
if not feature_tag :
2006-03-19 14:54:00 +00:00
return
2008-12-24 12:11:02 +00:00
form_tag = feature_tag . getTag ( ' x ' , namespace = common . xmpp . NS_DATA )
if not form_tag :
return
form = common . dataforms . ExtendForm ( node = form_tag )
for f in form . iter_fields ( ) :
if f . var == ' stream-method ' and f . type == ' list-single ' :
values = [ o [ 1 ] for o in f . options ]
if common . xmpp . NS_BYTESTREAM in values :
break
else :
self . send_file_rejection ( file_props , code = ' 400 ' , typ = ' stream ' )
raise common . xmpp . NodeProcessed
2006-03-19 14:54:00 +00:00
file_tag = si . getTag ( ' file ' )
for attribute in file_tag . getAttrs ( ) :
if attribute in ( ' name ' , ' size ' , ' hash ' , ' date ' ) :
val = file_tag . getAttr ( attribute )
if val is None :
continue
file_props [ attribute ] = val
file_desc_tag = file_tag . getTag ( ' desc ' )
if file_desc_tag is not None :
file_props [ ' desc ' ] = file_desc_tag . getData ( )
if mime_type is not None :
file_props [ ' mime-type ' ] = mime_type
our_jid = gajim . get_jid_from_account ( self . name )
resource = self . server_resource
file_props [ ' receiver ' ] = our_jid + ' / ' + resource
file_props [ ' sid ' ] = unicode ( si . getAttr ( ' id ' ) )
2007-08-09 15:39:18 +00:00
file_props [ ' transfered_size ' ] = [ ]
2006-03-19 14:54:00 +00:00
gajim . socks5queue . add_file_props ( self . name , file_props )
self . dispatch ( ' FILE_REQUEST ' , ( jid , file_props ) )
raise common . xmpp . NodeProcessed
def _siErrorCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' _siErrorCB ' )
2006-03-19 14:54:00 +00:00
si = iq_obj . getTag ( ' si ' )
profile = si . getAttr ( ' profile ' )
if profile != common . xmpp . NS_FILE :
return
2008-12-03 17:16:04 +00:00
id_ = iq_obj . getAttr ( ' id ' )
if id_ not in self . files_props :
2006-03-19 14:54:00 +00:00
# no such jid
return
2008-12-03 17:16:04 +00:00
file_props = self . files_props [ id_ ]
2006-03-19 14:54:00 +00:00
if file_props is None :
# file properties for jid is none
return
jid = helpers . get_jid_from_iq ( iq_obj )
file_props [ ' error ' ] = - 3
2006-11-18 20:52:28 +00:00
self . dispatch ( ' FILE_REQUEST_ERROR ' , ( jid , file_props , ' ' ) )
2006-03-19 14:54:00 +00:00
raise common . xmpp . NodeProcessed
class ConnectionDisco :
''' hold xmpppy handlers and public methods for discover services '''
2006-03-20 23:17:36 +00:00
def discoverItems ( self , jid , node = None , id_prefix = None ) :
2007-08-09 15:39:18 +00:00
''' According to XEP-0030: jid is mandatory,
2006-03-19 14:54:00 +00:00
name , node , action is optional . '''
2006-03-20 23:17:36 +00:00
self . _discover ( common . xmpp . NS_DISCO_ITEMS , jid , node , id_prefix )
2006-03-19 14:54:00 +00:00
2006-03-20 23:17:36 +00:00
def discoverInfo ( self , jid , node = None , id_prefix = None ) :
2007-08-09 15:39:18 +00:00
''' According to XEP-0030:
2006-03-19 14:54:00 +00:00
For identity : category , type is mandatory , name is optional .
For feature : var is mandatory '''
2006-03-20 23:17:36 +00:00
self . _discover ( common . xmpp . NS_DISCO_INFO , jid , node , id_prefix )
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def request_register_agent_info ( self , agent ) :
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
2006-03-19 14:54:00 +00:00
return None
2009-01-26 10:27:46 +00:00
iq = common . xmpp . Iq ( ' get ' , common . xmpp . NS_REGISTER , to = agent )
2008-12-03 17:16:04 +00:00
id_ = self . connection . getAnID ( )
iq . setID ( id_ )
2006-03-19 14:54:00 +00:00
# Wait the answer during 30 secondes
2008-12-03 17:16:04 +00:00
self . awaiting_timeouts [ gajim . idlequeue . current_time ( ) + 30 ] = ( id_ ,
2009-01-26 10:27:46 +00:00
_ ( ' Registration information for transport %s has not arrived in time ' ) \
% agent )
2006-03-19 14:54:00 +00:00
self . connection . SendAndCallForResponse ( iq , self . _ReceivedRegInfo ,
{ ' agent ' : agent } )
2007-02-15 09:18:24 +00:00
2009-01-26 10:27:46 +00:00
def _agent_registered_cb ( self , con , resp , agent ) :
if resp . getType ( ) == ' result ' :
self . dispatch ( ' INFORMATION ' , ( _ ( ' Registration succeeded ' ) ,
2009-02-15 09:28:56 +00:00
_ ( ' Registration with agent %s succeeded ' ) % agent ) )
2009-01-26 10:27:46 +00:00
if resp . getType ( ) == ' error ' :
2009-02-15 09:28:56 +00:00
self . dispatch ( ' ERROR ' , ( _ ( ' Registration failed ' ) , _ ( ' Registration with '
2009-01-26 10:27:46 +00:00
' agent %(agent)s failed with error %(error)s : %(error_msg)s ' ) % {
' agent ' : agent , ' error ' : resp . getError ( ) ,
' error_msg ' : resp . getErrorMsg ( ) } ) )
2006-03-19 14:54:00 +00:00
def register_agent ( self , agent , info , is_form = False ) :
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
2006-03-19 14:54:00 +00:00
return
if is_form :
iq = common . xmpp . Iq ( ' set ' , common . xmpp . NS_REGISTER , to = agent )
query = iq . getTag ( ' query ' )
2007-02-15 09:18:24 +00:00
info . setAttr ( ' type ' , ' submit ' )
query . addChild ( node = info )
2009-01-26 10:27:46 +00:00
self . connection . SendAndCallForResponse ( iq , self . _agent_registered_cb ,
{ ' agent ' : agent } )
2006-03-19 14:54:00 +00:00
else :
# fixed: blocking
common . xmpp . features_nb . register ( self . connection , agent , info , None )
2008-05-17 02:23:46 +00:00
2006-03-20 23:17:36 +00:00
def _discover ( self , ns , jid , node = None , id_prefix = None ) :
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
2006-03-19 14:54:00 +00:00
return
iq = common . xmpp . Iq ( typ = ' get ' , to = jid , queryNS = ns )
2006-03-20 23:17:36 +00:00
if id_prefix :
2008-12-03 17:16:04 +00:00
id_ = self . connection . getAnID ( )
iq . setID ( ' %s %s ' % ( id_prefix , id_ ) )
2006-03-19 14:54:00 +00:00
if node :
iq . setQuerynode ( node )
self . connection . send ( iq )
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def _ReceivedRegInfo ( self , con , resp , agent ) :
common . xmpp . features_nb . _ReceivedRegInfo ( con , resp , agent )
self . _IqCB ( con , resp )
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def _discoGetCB ( self , con , iq_obj ) :
''' get disco info '''
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
return
2006-03-19 14:54:00 +00:00
frm = helpers . get_full_jid_from_iq ( iq_obj )
to = unicode ( iq_obj . getAttr ( ' to ' ) )
2008-12-03 17:16:04 +00:00
id_ = unicode ( iq_obj . getAttr ( ' id ' ) )
2006-03-19 14:54:00 +00:00
iq = common . xmpp . Iq ( to = frm , typ = ' result ' , queryNS = \
common . xmpp . NS_DISCO , frm = to )
2008-12-03 17:16:04 +00:00
iq . setAttr ( ' id ' , id_ )
2006-03-19 14:54:00 +00:00
query = iq . setTag ( ' query ' )
2008-04-20 22:58:47 +00:00
query . setAttr ( ' node ' , ' http://gajim.org# ' + gajim . version . split ( ' - ' ,
2007-12-12 08:44:46 +00:00
1 ) [ 0 ] )
2008-02-07 23:53:02 +00:00
for f in ( common . xmpp . NS_BYTESTREAM , common . xmpp . NS_SI ,
common . xmpp . NS_FILE , common . xmpp . NS_COMMANDS ) :
2007-03-08 08:57:20 +00:00
feature = common . xmpp . Node ( ' feature ' )
feature . setAttr ( ' var ' , f )
query . addChild ( node = feature )
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
self . connection . send ( iq )
raise common . xmpp . NodeProcessed
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def _DiscoverItemsErrorCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' DiscoverItemsErrorCB ' )
2006-03-19 14:54:00 +00:00
jid = helpers . get_full_jid_from_iq ( iq_obj )
self . dispatch ( ' AGENT_ERROR_ITEMS ' , ( jid ) )
def _DiscoverItemsCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' DiscoverItemsCB ' )
2006-03-19 14:54:00 +00:00
q = iq_obj . getTag ( ' query ' )
node = q . getAttr ( ' node ' )
if not node :
node = ' '
qp = iq_obj . getQueryPayload ( )
items = [ ]
if not qp :
qp = [ ]
for i in qp :
# CDATA payload is not processed, only nodes
if not isinstance ( i , common . xmpp . simplexml . Node ) :
continue
attr = { }
for key in i . getAttrs ( ) :
attr [ key ] = i . getAttrs ( ) [ key ]
2006-11-18 20:52:28 +00:00
if ' jid ' not in attr :
continue
try :
2009-07-08 21:41:40 +02:00
attr [ ' jid ' ] = helpers . parse_jid ( attr [ ' jid ' ] )
2006-11-18 20:52:28 +00:00
except common . helpers . InvalidFormat :
# jid is not conform
continue
2006-03-19 14:54:00 +00:00
items . append ( attr )
jid = helpers . get_full_jid_from_iq ( iq_obj )
2008-05-17 02:23:46 +00:00
hostname = gajim . config . get_per ( ' accounts ' , self . name ,
2006-03-20 23:17:36 +00:00
' hostname ' )
2008-12-03 17:16:04 +00:00
id_ = iq_obj . getID ( )
2009-02-07 12:47:13 +00:00
if jid == hostname and id_ [ : 6 ] == ' Gajim_ ' :
2006-03-20 23:17:36 +00:00
for item in items :
2009-02-07 12:47:13 +00:00
self . discoverInfo ( item [ ' jid ' ] , id_prefix = ' Gajim_ ' )
2006-03-20 23:17:36 +00:00
else :
self . dispatch ( ' AGENT_INFO_ITEMS ' , ( jid , node , items ) )
2006-03-19 14:54:00 +00:00
2006-07-15 13:27:57 +00:00
def _DiscoverItemsGetCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' DiscoverItemsGetCB ' )
2008-07-28 12:17:33 +00:00
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
2008-07-28 12:17:33 +00:00
return
2007-12-12 08:44:46 +00:00
if self . commandItemsQuery ( con , iq_obj ) :
raise common . xmpp . NodeProcessed
2006-07-15 13:27:57 +00:00
node = iq_obj . getTagAttr ( ' query ' , ' node ' )
2007-12-12 08:44:46 +00:00
if node is None :
2007-08-09 15:39:18 +00:00
result = iq_obj . buildReply ( ' result ' )
self . connection . send ( result )
raise common . xmpp . NodeProcessed
2006-07-15 13:27:57 +00:00
if node == common . xmpp . NS_COMMANDS :
self . commandListQuery ( con , iq_obj )
raise common . xmpp . NodeProcessed
2006-03-19 14:54:00 +00:00
def _DiscoverInfoGetCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' DiscoverInfoGetCB ' )
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
return
2006-07-15 13:27:57 +00:00
q = iq_obj . getTag ( ' query ' )
node = q . getAttr ( ' node ' )
2007-12-12 08:44:46 +00:00
if self . commandInfoQuery ( con , iq_obj ) :
2006-11-20 19:34:11 +00:00
raise common . xmpp . NodeProcessed
2008-05-17 02:23:46 +00:00
2008-12-03 17:16:04 +00:00
id_ = unicode ( iq_obj . getAttr ( ' id ' ) )
2009-02-07 12:47:13 +00:00
if id_ [ : 6 ] == ' Gajim_ ' :
2008-11-02 15:02:49 +00:00
# We get this request from echo.server
raise common . xmpp . NodeProcessed
iq = iq_obj . buildReply ( ' result ' )
q = iq . getTag ( ' query ' )
if node :
q . setAttr ( ' node ' , node )
q . addChild ( ' identity ' , attrs = gajim . gajim_identity )
client_version = ' http://gajim.org# ' + gajim . caps_hash [ self . name ]
if node in ( None , client_version ) :
for f in gajim . gajim_common_features :
q . addChild ( ' feature ' , attrs = { ' var ' : f } )
for f in gajim . gajim_optional_features [ self . name ] :
q . addChild ( ' feature ' , attrs = { ' var ' : f } )
if q . getChildren ( ) :
self . connection . send ( iq )
raise common . xmpp . NodeProcessed
2006-03-19 14:54:00 +00:00
def _DiscoverInfoErrorCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' DiscoverInfoErrorCB ' )
2006-03-19 14:54:00 +00:00
jid = helpers . get_full_jid_from_iq ( iq_obj )
2009-08-31 21:57:01 +02:00
id_ = iq_obj . getID ( )
if id_ [ : 6 ] == ' Gajim_ ' :
if not self . privacy_rules_requested :
self . privacy_rules_requested = True
self . _request_privacy ( )
2006-03-19 14:54:00 +00:00
self . dispatch ( ' AGENT_ERROR_INFO ' , ( jid ) )
def _DiscoverInfoCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' DiscoverInfoCB ' )
2009-05-21 21:12:11 +02:00
if not self . connection or self . connected < 2 :
return
2007-08-09 15:39:18 +00:00
# According to XEP-0030:
2006-03-19 14:54:00 +00:00
# For identity: category, type is mandatory, name is optional.
# For feature: var is mandatory
identities , features , data = [ ] , [ ] , [ ]
q = iq_obj . getTag ( ' query ' )
node = q . getAttr ( ' node ' )
if not node :
node = ' '
qc = iq_obj . getQueryChildren ( )
if not qc :
qc = [ ]
2006-09-13 16:47:58 +00:00
is_muc = False
transport_type = ' '
2006-03-19 14:54:00 +00:00
for i in qc :
if i . getName ( ) == ' identity ' :
attr = { }
for key in i . getAttrs ( ) . keys ( ) :
attr [ key ] = i . getAttr ( key )
2008-10-07 20:41:59 +00:00
if ' category ' in attr and \
2007-12-12 08:44:46 +00:00
attr [ ' category ' ] in ( ' gateway ' , ' headline ' ) and \
2008-10-07 20:41:59 +00:00
' type ' in attr :
2006-09-13 16:47:58 +00:00
transport_type = attr [ ' type ' ]
2008-10-07 20:41:59 +00:00
if ' category ' in attr and \
2007-12-12 08:44:46 +00:00
attr [ ' category ' ] == ' conference ' and \
2008-10-07 20:41:59 +00:00
' type ' in attr and attr [ ' type ' ] == ' text ' :
2006-09-13 16:47:58 +00:00
is_muc = True
2006-03-19 14:54:00 +00:00
identities . append ( attr )
elif i . getName ( ) == ' feature ' :
2009-10-05 13:46:38 +02:00
var = i . getAttr ( ' var ' )
if var :
features . append ( var )
2006-09-13 16:47:58 +00:00
elif i . getName ( ) == ' x ' and i . getNamespace ( ) == common . xmpp . NS_DATA :
2006-03-19 14:54:00 +00:00
data . append ( common . xmpp . DataForm ( node = i ) )
jid = helpers . get_full_jid_from_iq ( iq_obj )
2006-09-13 16:47:58 +00:00
if transport_type and jid not in gajim . transport_type :
gajim . transport_type [ jid ] = transport_type
gajim . logger . save_transport_type ( jid , transport_type )
2008-12-03 17:16:04 +00:00
id_ = iq_obj . getID ( )
2009-06-29 07:57:10 +02:00
if id_ is None :
log . warn ( ' Invalid IQ received without an ID. Ignoring it: %s ' % iq_obj )
return
2006-03-25 00:46:42 +00:00
if not identities : # ejabberd doesn't send identities when we browse online users
#FIXME: see http://www.jabber.ru/bugzilla/show_bug.cgi?id=225
identities = [ { ' category ' : ' server ' , ' type ' : ' im ' , ' name ' : node } ]
2009-02-07 12:47:13 +00:00
if id_ [ : 6 ] == ' Gajim_ ' :
2007-03-30 19:16:44 +00:00
if jid == gajim . config . get_per ( ' accounts ' , self . name , ' hostname ' ) :
2007-08-09 15:39:18 +00:00
if features . __contains__ ( common . xmpp . NS_GMAILNOTIFY ) :
gajim . gmail_domains . append ( jid )
self . request_gmail_notifications ( )
2007-03-30 19:16:44 +00:00
for identity in identities :
2008-04-22 23:52:04 +00:00
if identity [ ' category ' ] == ' pubsub ' and identity . get ( ' type ' ) == \
2007-03-30 19:16:44 +00:00
' pep ' :
self . pep_supported = True
break
2009-08-28 13:41:36 +02:00
if features . __contains__ ( common . xmpp . NS_VCARD ) :
2009-08-30 12:03:29 +02:00
self . vcard_supported = True
2009-04-22 14:24:04 +00:00
if features . __contains__ ( common . xmpp . NS_PUBSUB ) :
self . pubsub_supported = True
2009-07-31 15:50:11 +02:00
if features . __contains__ ( common . xmpp . NS_PUBSUB_PUBLISH_OPTIONS ) :
self . pubsub_publish_options_supported = True
2006-03-25 00:46:42 +00:00
if features . __contains__ ( common . xmpp . NS_BYTESTREAM ) :
2008-08-27 13:11:46 +00:00
our_jid = helpers . parse_jid ( gajim . get_jid_from_account ( self . name ) + \
' / ' + self . server_resource )
gajim . proxy65_manager . resolve ( jid , self . connection , our_jid ,
self . name )
2006-09-13 16:47:58 +00:00
if features . __contains__ ( common . xmpp . NS_MUC ) and is_muc :
type_ = transport_type or ' jabber '
self . muc_jid [ type_ ] = jid
if transport_type :
2008-10-07 20:41:59 +00:00
if transport_type in self . available_transports :
2006-09-13 16:47:58 +00:00
self . available_transports [ transport_type ] . append ( jid )
else :
self . available_transports [ transport_type ] = [ jid ]
2009-08-04 17:57:12 +02:00
if not self . privacy_rules_requested :
self . privacy_rules_requested = True
self . _request_privacy ( )
2007-08-09 15:39:18 +00:00
2006-03-25 00:46:42 +00:00
self . dispatch ( ' AGENT_INFO_INFO ' , ( jid , node , identities ,
features , data ) )
2007-08-09 15:39:18 +00:00
self . _capsDiscoCB ( jid , node , identities , features , data )
2006-03-19 14:54:00 +00:00
class ConnectionVcard :
def __init__ ( self ) :
self . vcard_sha = None
self . vcard_shas = { } # sha of contacts
self . room_jids = [ ] # list of gc jids so that vcard are saved in a folder
2007-08-09 15:39:18 +00:00
2006-05-01 14:15:28 +00:00
def add_sha ( self , p , send_caps = True ) :
2006-03-19 14:54:00 +00:00
c = p . setTag ( ' x ' , namespace = common . xmpp . NS_VCARD_UPDATE )
if self . vcard_sha is not None :
c . setTagData ( ' photo ' , self . vcard_sha )
2006-05-01 14:15:28 +00:00
if send_caps :
return self . add_caps ( p )
return p
2008-05-17 02:23:46 +00:00
2006-05-01 14:15:28 +00:00
def add_caps ( self , p ) :
2007-08-09 15:39:18 +00:00
''' advertise our capabilities in presence stanza (xep-0115) '''
2006-05-01 14:15:28 +00:00
c = p . setTag ( ' c ' , namespace = common . xmpp . NS_CAPS )
2008-04-20 22:58:47 +00:00
c . setAttr ( ' hash ' , ' sha-1 ' )
c . setAttr ( ' node ' , ' http://gajim.org ' )
2008-05-27 10:24:29 +00:00
c . setAttr ( ' ver ' , gajim . caps_hash [ self . name ] )
2006-03-19 14:54:00 +00:00
return p
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def node_to_dict ( self , node ) :
2008-12-03 17:16:04 +00:00
dict_ = { }
2006-03-19 14:54:00 +00:00
for info in node . getChildren ( ) :
name = info . getName ( )
if name in ( ' ADR ' , ' TEL ' , ' EMAIL ' ) : # we can have several
2008-12-03 17:16:04 +00:00
dict_ . setdefault ( name , [ ] )
2006-03-19 14:54:00 +00:00
entry = { }
for c in info . getChildren ( ) :
2007-02-04 18:57:25 +00:00
entry [ c . getName ( ) ] = c . getData ( )
2008-12-03 17:16:04 +00:00
dict_ [ name ] . append ( entry )
2006-03-19 14:54:00 +00:00
elif info . getChildren ( ) == [ ] :
2008-12-03 17:16:04 +00:00
dict_ [ name ] = info . getData ( )
2006-03-19 14:54:00 +00:00
else :
2008-12-03 17:16:04 +00:00
dict_ [ name ] = { }
2006-03-19 14:54:00 +00:00
for c in info . getChildren ( ) :
2008-12-03 17:16:04 +00:00
dict_ [ name ] [ c . getName ( ) ] = c . getData ( )
return dict_
2006-03-19 14:54:00 +00:00
def save_vcard_to_hd ( self , full_jid , card ) :
jid , nick = gajim . get_room_and_nick_from_fjid ( full_jid )
2006-03-26 11:46:04 +00:00
puny_jid = helpers . sanitize_filename ( jid )
2006-03-19 14:54:00 +00:00
path = os . path . join ( gajim . VCARD_PATH , puny_jid )
2006-04-26 08:11:16 +00:00
if jid in self . room_jids or os . path . isdir ( path ) :
2006-11-18 20:52:28 +00:00
if not nick :
return
2006-03-19 14:54:00 +00:00
# remove room_jid file if needed
if os . path . isfile ( path ) :
os . remove ( path )
# create folder if needed
if not os . path . isdir ( path ) :
os . mkdir ( path , 0700 )
2006-03-26 11:46:04 +00:00
puny_nick = helpers . sanitize_filename ( nick )
2006-03-19 14:54:00 +00:00
path_to_file = os . path . join ( gajim . VCARD_PATH , puny_jid , puny_nick )
else :
path_to_file = path
2007-08-09 15:39:18 +00:00
try :
fil = open ( path_to_file , ' w ' )
fil . write ( str ( card ) )
fil . close ( )
except IOError , e :
self . dispatch ( ' ERROR ' , ( _ ( ' Disk Write Error ' ) , str ( e ) ) )
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def get_cached_vcard ( self , fjid , is_fake_jid = False ) :
''' return the vcard as a dict
return { } if vcard was too old
return None if we don ' t have cached vcard ' ' '
jid , nick = gajim . get_room_and_nick_from_fjid ( fjid )
2006-03-26 11:46:04 +00:00
puny_jid = helpers . sanitize_filename ( jid )
2006-03-19 14:54:00 +00:00
if is_fake_jid :
2006-03-26 11:46:04 +00:00
puny_nick = helpers . sanitize_filename ( nick )
2006-03-19 14:54:00 +00:00
path_to_file = os . path . join ( gajim . VCARD_PATH , puny_jid , puny_nick )
else :
path_to_file = os . path . join ( gajim . VCARD_PATH , puny_jid )
if not os . path . isfile ( path_to_file ) :
return None
# We have the vcard cached
f = open ( path_to_file )
c = f . read ( )
f . close ( )
2007-01-12 10:10:01 +00:00
try :
card = common . xmpp . Node ( node = c )
2008-10-11 09:37:13 +00:00
except Exception :
2007-01-12 10:10:01 +00:00
# We are unable to parse it. Remove it
os . remove ( path_to_file )
return None
2006-03-19 14:54:00 +00:00
vcard = self . node_to_dict ( card )
2008-10-07 20:41:59 +00:00
if ' PHOTO ' in vcard :
2006-03-19 14:54:00 +00:00
if not isinstance ( vcard [ ' PHOTO ' ] , dict ) :
del vcard [ ' PHOTO ' ]
2008-10-07 20:41:59 +00:00
elif ' SHA ' in vcard [ ' PHOTO ' ] :
2008-05-17 02:23:46 +00:00
cached_sha = vcard [ ' PHOTO ' ] [ ' SHA ' ]
2008-10-07 20:41:59 +00:00
if jid in self . vcard_shas and self . vcard_shas [ jid ] != \
2008-05-17 02:23:46 +00:00
cached_sha :
# user change his vcard so don't use the cached one
return { }
2006-03-19 14:54:00 +00:00
vcard [ ' jid ' ] = jid
vcard [ ' resource ' ] = gajim . get_resource_from_jid ( fjid )
return vcard
2007-06-03 10:04:20 +00:00
def request_vcard ( self , jid = None , groupchat_jid = None ) :
''' request the VCARD. If groupchat_jid is not nul, it means we request a vcard
to a fake jid , like in private messages in groupchat . jid can be the
real jid of the contact , but we want to consider it comes from a fake jid '''
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
2006-03-19 14:54:00 +00:00
return
iq = common . xmpp . Iq ( typ = ' get ' )
if jid :
iq . setTo ( jid )
iq . setTag ( common . xmpp . NS_VCARD + ' vCard ' )
2008-12-03 17:16:04 +00:00
id_ = self . connection . getAnID ( )
iq . setID ( id_ )
2006-09-13 16:47:58 +00:00
j = jid
if not j :
j = gajim . get_jid_from_account ( self . name )
2008-12-03 17:16:04 +00:00
self . awaiting_answers [ id_ ] = ( VCARD_ARRIVED , j , groupchat_jid )
2007-06-03 10:04:20 +00:00
if groupchat_jid :
2008-12-02 15:53:23 +00:00
room_jid = gajim . get_room_and_nick_from_fjid ( groupchat_jid ) [ 0 ]
2006-03-19 14:54:00 +00:00
if not room_jid in self . room_jids :
self . room_jids . append ( room_jid )
2008-12-03 17:16:04 +00:00
self . groupchat_jids [ id_ ] = groupchat_jid
2006-03-19 14:54:00 +00:00
self . connection . send ( iq )
def send_vcard ( self , vcard ) :
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
2006-03-19 14:54:00 +00:00
return
iq = common . xmpp . Iq ( typ = ' set ' )
iq2 = iq . setTag ( common . xmpp . NS_VCARD + ' vCard ' )
for i in vcard :
if i == ' jid ' :
continue
if isinstance ( vcard [ i ] , dict ) :
iq3 = iq2 . addChild ( i )
for j in vcard [ i ] :
iq3 . addChild ( j ) . setData ( vcard [ i ] [ j ] )
2008-10-11 09:59:52 +00:00
elif isinstance ( vcard [ i ] , list ) :
2006-03-19 14:54:00 +00:00
for j in vcard [ i ] :
iq3 = iq2 . addChild ( i )
for k in j :
iq3 . addChild ( k ) . setData ( j [ k ] )
else :
iq2 . addChild ( i ) . setData ( vcard [ i ] )
2008-12-03 17:16:04 +00:00
id_ = self . connection . getAnID ( )
iq . setID ( id_ )
2006-03-19 14:54:00 +00:00
self . connection . send ( iq )
2006-11-28 15:40:08 +00:00
our_jid = gajim . get_jid_from_account ( self . name )
2006-03-19 14:54:00 +00:00
# Add the sha of the avatar
2008-10-07 20:41:59 +00:00
if ' PHOTO ' in vcard and isinstance ( vcard [ ' PHOTO ' ] , dict ) and \
' BINVAL ' in vcard [ ' PHOTO ' ] :
2006-03-19 14:54:00 +00:00
photo = vcard [ ' PHOTO ' ] [ ' BINVAL ' ]
photo_decoded = base64 . decodestring ( photo )
2006-04-11 18:28:31 +00:00
gajim . interface . save_avatar_files ( our_jid , photo_decoded )
2009-01-08 16:51:26 +00:00
avatar_sha = hashlib . sha1 ( photo_decoded ) . hexdigest ( )
2006-03-19 14:54:00 +00:00
iq2 . getTag ( ' PHOTO ' ) . setTagData ( ' SHA ' , avatar_sha )
2006-11-28 15:40:08 +00:00
else :
gajim . interface . remove_avatar_files ( our_jid )
2006-03-19 14:54:00 +00:00
2008-12-03 17:16:04 +00:00
self . awaiting_answers [ id_ ] = ( VCARD_PUBLISHED , iq2 )
2008-05-03 00:10:17 +00:00
2006-03-19 14:54:00 +00:00
def _IqCB ( self , con , iq_obj ) :
2008-12-03 17:16:04 +00:00
id_ = iq_obj . getID ( )
2006-03-19 14:54:00 +00:00
# Check if we were waiting a timeout for this id
found_tim = None
for tim in self . awaiting_timeouts :
2008-12-03 17:16:04 +00:00
if id_ == self . awaiting_timeouts [ tim ] [ 0 ] :
2006-03-19 14:54:00 +00:00
found_tim = tim
break
if found_tim :
del self . awaiting_timeouts [ found_tim ]
2008-12-03 17:16:04 +00:00
if id_ not in self . awaiting_answers :
2006-03-19 14:54:00 +00:00
return
2008-12-03 17:16:04 +00:00
if self . awaiting_answers [ id_ ] [ 0 ] == VCARD_PUBLISHED :
2006-03-19 14:54:00 +00:00
if iq_obj . getType ( ) == ' result ' :
2008-12-03 17:16:04 +00:00
vcard_iq = self . awaiting_answers [ id_ ] [ 1 ]
2006-03-19 14:54:00 +00:00
# Save vcard to HD
if vcard_iq . getTag ( ' PHOTO ' ) and vcard_iq . getTag ( ' PHOTO ' ) . getTag ( ' SHA ' ) :
new_sha = vcard_iq . getTag ( ' PHOTO ' ) . getTagData ( ' SHA ' )
else :
new_sha = ' '
# Save it to file
our_jid = gajim . get_jid_from_account ( self . name )
self . save_vcard_to_hd ( our_jid , vcard_iq )
# Send new presence if sha changed and we are not invisible
2009-01-10 16:45:52 +00:00
if self . vcard_sha != new_sha and gajim . SHOW_LIST [ self . connected ] != \
2008-08-30 17:14:27 +00:00
' invisible ' :
if not self . connection or self . connected < 2 :
return
2006-03-19 14:54:00 +00:00
self . vcard_sha = new_sha
2009-01-10 16:45:52 +00:00
sshow = helpers . get_xmpp_show ( gajim . SHOW_LIST [ self . connected ] )
2006-11-18 20:52:28 +00:00
p = common . xmpp . Presence ( typ = None , priority = self . priority ,
2006-03-19 14:54:00 +00:00
show = sshow , status = self . status )
p = self . add_sha ( p )
self . connection . send ( p )
2006-04-12 12:55:06 +00:00
self . dispatch ( ' VCARD_PUBLISHED ' , ( ) )
2006-03-19 14:54:00 +00:00
elif iq_obj . getType ( ) == ' error ' :
self . dispatch ( ' VCARD_NOT_PUBLISHED ' , ( ) )
2008-12-03 17:16:04 +00:00
elif self . awaiting_answers [ id_ ] [ 0 ] == VCARD_ARRIVED :
2006-03-19 14:54:00 +00:00
# If vcard is empty, we send to the interface an empty vcard so that
# it knows it arrived
2008-12-03 17:16:04 +00:00
jid = self . awaiting_answers [ id_ ] [ 1 ]
groupchat_jid = self . awaiting_answers [ id_ ] [ 2 ]
2007-06-03 10:04:20 +00:00
frm = jid
if groupchat_jid :
# We do as if it comes from the fake_jid
frm = groupchat_jid
2006-09-13 16:47:58 +00:00
our_jid = gajim . get_jid_from_account ( self . name )
if not iq_obj . getTag ( ' vCard ' ) or iq_obj . getType ( ) == ' error ' :
2007-06-03 10:04:20 +00:00
if frm and frm != our_jid :
2006-03-19 14:54:00 +00:00
# Write an empty file
2007-06-03 10:04:20 +00:00
self . save_vcard_to_hd ( frm , ' ' )
2008-04-09 21:30:12 +00:00
jid , resource = gajim . get_room_and_nick_from_fjid ( frm )
self . dispatch ( ' VCARD ' , { ' jid ' : jid , ' resource ' : resource } )
2007-06-03 10:04:20 +00:00
elif frm == our_jid :
self . dispatch ( ' MYVCARD ' , { ' jid ' : frm } )
2008-12-03 17:16:04 +00:00
elif self . awaiting_answers [ id_ ] [ 0 ] == AGENT_REMOVED :
jid = self . awaiting_answers [ id_ ] [ 1 ]
2006-05-01 18:29:12 +00:00
self . dispatch ( ' AGENT_REMOVED ' , jid )
2008-12-03 17:16:04 +00:00
elif self . awaiting_answers [ id_ ] [ 0 ] == METACONTACTS_ARRIVED :
2008-08-30 17:14:27 +00:00
if not self . connection :
return
2006-09-13 16:47:58 +00:00
if iq_obj . getType ( ) == ' result ' :
# Metacontact tags
2007-08-09 15:39:18 +00:00
# http://www.xmpp.org/extensions/xep-0209.html
2006-09-13 16:47:58 +00:00
meta_list = { }
query = iq_obj . getTag ( ' query ' )
storage = query . getTag ( ' storage ' )
metas = storage . getTags ( ' meta ' )
for meta in metas :
2009-07-08 21:41:40 +02:00
try :
jid = helpers . parse_jid ( meta . getAttr ( ' jid ' ) )
except common . helpers . InvalidFormat :
continue
2006-09-13 16:47:58 +00:00
tag = meta . getAttr ( ' tag ' )
data = { ' jid ' : jid }
order = meta . getAttr ( ' order ' )
2007-12-12 08:44:46 +00:00
try :
order = int ( order )
2008-10-11 09:37:13 +00:00
except Exception :
2007-12-12 08:44:46 +00:00
order = 0
2008-04-18 00:26:07 +00:00
if order is not None :
2006-09-13 16:47:58 +00:00
data [ ' order ' ] = order
2008-10-07 20:41:59 +00:00
if tag in meta_list :
2006-09-13 16:47:58 +00:00
meta_list [ tag ] . append ( data )
else :
meta_list [ tag ] = [ data ]
self . dispatch ( ' METACONTACTS ' , meta_list )
2006-11-18 20:52:28 +00:00
else :
2007-12-12 08:44:46 +00:00
if iq_obj . getErrorCode ( ) not in ( ' 403 ' , ' 406 ' , ' 404 ' ) :
self . private_storage_supported = False
2006-09-13 16:47:58 +00:00
# We can now continue connection by requesting the roster
2009-06-02 22:48:32 +02:00
version = gajim . config . get_per ( ' accounts ' , self . name ,
' roster_version ' )
2009-06-27 17:56:04 +02:00
iq_id = self . connection . initRoster ( version = version )
self . awaiting_answers [ iq_id ] = ( ROSTER_ARRIVED , )
elif self . awaiting_answers [ id_ ] [ 0 ] == ROSTER_ARRIVED :
if iq_obj . getType ( ) == ' result ' :
if not iq_obj . getTag ( ' query ' ) :
account_jid = gajim . get_jid_from_account ( self . name )
roster_data = gajim . logger . get_roster ( account_jid )
roster = self . connection . getRoster ( force = True )
roster . setRaw ( roster_data )
self . _getRoster ( )
2008-12-03 17:16:04 +00:00
elif self . awaiting_answers [ id_ ] [ 0 ] == PRIVACY_ARRIVED :
2006-11-18 20:52:28 +00:00
if iq_obj . getType ( ) != ' error ' :
self . privacy_rules_supported = True
2007-06-03 10:04:20 +00:00
self . get_privacy_list ( ' block ' )
2008-06-25 09:25:43 +00:00
elif self . continue_connect_info :
if self . continue_connect_info [ 0 ] == ' invisible ' :
# Trying to login as invisible but privacy list not supported
self . disconnect ( on_purpose = True )
self . dispatch ( ' STATUS ' , ' offline ' )
self . dispatch ( ' ERROR ' , ( _ ( ' Invisibility not supported ' ) ,
_ ( ' Account %s doesn \' t support invisibility. ' ) % self . name ) )
return
2006-11-18 20:52:28 +00:00
# Ask metacontacts before roster
self . get_metacontacts ( )
2008-12-03 17:16:04 +00:00
elif self . awaiting_answers [ id_ ] [ 0 ] == PEP_CONFIG :
2007-06-03 10:30:34 +00:00
conf = iq_obj . getTag ( ' pubsub ' ) . getTag ( ' configure ' )
node = conf . getAttr ( ' node ' )
form_tag = conf . getTag ( ' x ' , namespace = common . xmpp . NS_DATA )
2007-12-13 20:44:30 +00:00
if form_tag :
form = common . dataforms . ExtendForm ( node = form_tag )
2008-02-15 22:55:21 +00:00
self . dispatch ( ' PEP_CONFIG ' , ( node , form ) )
2006-09-13 16:47:58 +00:00
2008-12-03 17:16:04 +00:00
del self . awaiting_answers [ id_ ]
2007-01-31 11:31:07 +00:00
2006-03-19 14:54:00 +00:00
def _vCardCB ( self , con , vc ) :
''' Called when we receive a vCard
Parse the vCard and send it to plugins '''
if not vc . getTag ( ' vCard ' ) :
return
2007-01-31 11:31:07 +00:00
if not vc . getTag ( ' vCard ' ) . getNamespace ( ) == common . xmpp . NS_VCARD :
return
2008-12-03 17:16:04 +00:00
id_ = vc . getID ( )
2006-03-19 14:54:00 +00:00
frm_iq = vc . getFrom ( )
our_jid = gajim . get_jid_from_account ( self . name )
resource = ' '
2008-12-03 17:16:04 +00:00
if id_ in self . groupchat_jids :
who = self . groupchat_jids [ id_ ]
2007-06-03 10:04:20 +00:00
frm , resource = gajim . get_room_and_nick_from_fjid ( who )
2008-12-03 17:16:04 +00:00
del self . groupchat_jids [ id_ ]
2007-06-03 10:04:20 +00:00
elif frm_iq :
2006-03-19 14:54:00 +00:00
who = helpers . get_full_jid_from_iq ( vc )
frm , resource = gajim . get_room_and_nick_from_fjid ( who )
else :
who = frm = our_jid
2007-01-31 11:31:07 +00:00
card = vc . getChildren ( ) [ 0 ]
vcard = self . node_to_dict ( card )
photo_decoded = None
2008-10-07 20:41:59 +00:00
if ' PHOTO ' in vcard and isinstance ( vcard [ ' PHOTO ' ] , dict ) and \
' BINVAL ' in vcard [ ' PHOTO ' ] :
2007-01-31 11:31:07 +00:00
photo = vcard [ ' PHOTO ' ] [ ' BINVAL ' ]
try :
photo_decoded = base64 . decodestring ( photo )
2009-01-08 16:51:26 +00:00
avatar_sha = hashlib . sha1 ( photo_decoded ) . hexdigest ( )
2008-10-11 09:37:13 +00:00
except Exception :
2006-03-19 14:54:00 +00:00
avatar_sha = ' '
2007-01-31 11:31:07 +00:00
else :
avatar_sha = ' '
if avatar_sha :
card . getTag ( ' PHOTO ' ) . setTagData ( ' SHA ' , avatar_sha )
# Save it to file
self . save_vcard_to_hd ( who , card )
# Save the decoded avatar to a separate file too, and generate files for dbus notifications
puny_jid = helpers . sanitize_filename ( frm )
puny_nick = None
begin_path = os . path . join ( gajim . AVATAR_PATH , puny_jid )
2007-02-03 23:56:40 +00:00
frm_jid = frm
2007-01-31 11:31:07 +00:00
if frm in self . room_jids :
puny_nick = helpers . sanitize_filename ( resource )
# create folder if needed
if not os . path . isdir ( begin_path ) :
os . mkdir ( begin_path , 0700 )
begin_path = os . path . join ( begin_path , puny_nick )
2007-02-03 23:56:40 +00:00
frm_jid + = ' / ' + resource
2007-01-31 11:31:07 +00:00
if photo_decoded :
avatar_file = begin_path + ' _notif_size_colored.png '
2007-02-03 23:56:40 +00:00
if frm_jid == our_jid and avatar_sha != self . vcard_sha :
2007-01-31 11:31:07 +00:00
gajim . interface . save_avatar_files ( frm , photo_decoded , puny_nick )
2007-02-03 23:56:40 +00:00
elif frm_jid != our_jid and ( not os . path . exists ( avatar_file ) or \
2008-10-07 20:41:59 +00:00
frm_jid not in self . vcard_shas or \
2007-02-03 23:56:40 +00:00
avatar_sha != self . vcard_shas [ frm_jid ] ) :
2007-01-31 11:31:07 +00:00
gajim . interface . save_avatar_files ( frm , photo_decoded , puny_nick )
2007-02-03 23:56:40 +00:00
if avatar_sha :
self . vcard_shas [ frm_jid ] = avatar_sha
2008-10-07 20:41:59 +00:00
elif frm in self . vcard_shas :
2007-02-03 23:56:40 +00:00
del self . vcard_shas [ frm ]
2007-01-31 11:31:07 +00:00
else :
for ext in ( ' .jpeg ' , ' .png ' , ' _notif_size_bw.png ' ,
' _notif_size_colored.png ' ) :
path = begin_path + ext
if os . path . isfile ( path ) :
os . remove ( path )
2006-03-19 14:54:00 +00:00
2007-01-31 11:31:07 +00:00
vcard [ ' jid ' ] = frm
vcard [ ' resource ' ] = resource
2007-02-03 23:56:40 +00:00
if frm_jid == our_jid :
2007-01-31 11:31:07 +00:00
self . dispatch ( ' MYVCARD ' , vcard )
# we re-send our presence with sha if has changed and if we are
# not invisible
if self . vcard_sha == avatar_sha :
return
self . vcard_sha = avatar_sha
2009-01-10 16:45:52 +00:00
if gajim . SHOW_LIST [ self . connected ] == ' invisible ' :
2007-01-31 11:31:07 +00:00
return
2008-08-30 17:14:27 +00:00
if not self . connection :
return
2009-01-10 16:45:52 +00:00
sshow = helpers . get_xmpp_show ( gajim . SHOW_LIST [ self . connected ] )
2007-01-31 11:31:07 +00:00
p = common . xmpp . Presence ( typ = None , priority = self . priority ,
show = sshow , status = self . status )
p = self . add_sha ( p )
self . connection . send ( p )
else :
2007-06-03 10:04:20 +00:00
#('VCARD', {entry1: data, entry2: {entry21: data, ...}, ...})
2007-01-31 11:31:07 +00:00
self . dispatch ( ' VCARD ' , vcard )
2006-03-19 14:54:00 +00:00
2008-05-17 02:23:46 +00:00
# basic connection handlers used here and in zeroconf
class ConnectionHandlersBase :
2006-03-19 14:54:00 +00:00
def __init__ ( self ) :
# List of IDs we are waiting answers for {id: (type_of_request, data), }
self . awaiting_answers = { }
# List of IDs that will produce a timeout is answer doesn't arrive
# {time_of_the_timeout: (id, message to send to gui), }
2006-04-29 09:44:47 +00:00
self . awaiting_timeouts = { }
# keep the jids we auto added (transports contacts) to not send the
# SUBSCRIBED event to gui
2006-04-18 14:30:00 +00:00
self . automatically_added = [ ]
2008-05-17 02:23:46 +00:00
# keep track of sessions this connection has with other JIDs
self . sessions = { }
2008-07-26 05:28:15 +00:00
def get_sessions ( self , jid ) :
''' get all sessions for the given full jid '''
2008-05-17 02:23:46 +00:00
if not gajim . interface . is_pm_contact ( jid , self . name ) :
jid = gajim . get_jid_without_resource ( jid )
2008-07-26 05:28:15 +00:00
try :
return self . sessions [ jid ] . values ( )
except KeyError :
return [ ]
def get_or_create_session ( self , fjid , thread_id ) :
''' returns an existing session between this connection and ' jid ' , returns a
new one if none exist . '''
pm = True
jid = fjid
if not gajim . interface . is_pm_contact ( fjid , self . name ) :
pm = False
jid = gajim . get_jid_without_resource ( fjid )
2008-05-17 02:23:46 +00:00
session = self . find_session ( jid , thread_id )
if session :
return session
if pm :
2008-10-11 10:22:04 +00:00
return self . make_new_session ( fjid , thread_id , type_ = ' pm ' )
2008-05-17 02:23:46 +00:00
else :
2008-07-26 05:28:15 +00:00
return self . make_new_session ( fjid , thread_id )
2008-05-17 02:23:46 +00:00
def find_session ( self , jid , thread_id ) :
try :
if not thread_id :
return self . find_null_session ( jid )
else :
return self . sessions [ jid ] [ thread_id ]
except KeyError :
return None
2008-12-15 21:06:08 +00:00
def terminate_sessions ( self , send_termination = False ) :
2008-05-17 02:23:46 +00:00
''' send termination messages and delete all active sessions '''
for jid in self . sessions :
for thread_id in self . sessions [ jid ] :
2008-12-13 18:10:37 +00:00
self . sessions [ jid ] [ thread_id ] . terminate ( send_termination )
2008-05-17 02:23:46 +00:00
self . sessions = { }
def delete_session ( self , jid , thread_id ) :
2008-05-23 23:27:08 +00:00
if not jid in self . sessions :
jid = gajim . get_jid_without_resource ( jid )
2008-09-30 10:22:55 +00:00
if not jid in self . sessions :
return
2008-05-17 02:23:46 +00:00
2008-05-23 23:27:08 +00:00
del self . sessions [ jid ] [ thread_id ]
if not self . sessions [ jid ] :
del self . sessions [ jid ]
2008-05-17 02:23:46 +00:00
def find_null_session ( self , jid ) :
''' finds all of the sessions between us and a remote jid in which we
haven ' t received a thread_id yet and returns the session that we last
sent a message to . '''
sessions = self . sessions [ jid ] . values ( )
# sessions that we haven't received a thread ID in
2008-12-03 22:04:42 +00:00
idless = [ s for s in sessions if not s . received_thread_id ]
2008-05-17 02:23:46 +00:00
2008-06-02 23:26:40 +00:00
# filter out everything except the default session type
2008-12-03 22:07:44 +00:00
chat_sessions = [ s for s in idless if isinstance ( s ,
gajim . default_session_type ) ]
2008-05-17 02:23:46 +00:00
if chat_sessions :
# return the session that we last sent a message in
2009-10-06 17:35:25 +02:00
return sorted ( chat_sessions , key = operator . attrgetter ( " last_send " ) ) [ - 1 ]
2008-05-17 02:23:46 +00:00
else :
return None
2009-10-06 17:35:25 +02:00
def find_controlless_session ( self , jid , resource = None ) :
2008-06-02 23:26:40 +00:00
''' find an active session that doesn ' t have a control attached '''
try :
sessions = self . sessions [ jid ] . values ( )
# filter out everything except the default session type
2008-12-03 22:07:44 +00:00
chat_sessions = [ s for s in sessions if isinstance ( s ,
gajim . default_session_type ) ]
2008-06-02 23:26:40 +00:00
2008-12-03 22:04:42 +00:00
orphaned = [ s for s in chat_sessions if not s . control ]
2008-06-02 23:26:40 +00:00
2009-10-06 17:35:25 +02:00
if resource :
orphaned = [ s for s in orphaned if s . resource == resource ]
2008-06-02 23:26:40 +00:00
return orphaned [ 0 ]
2008-06-10 02:58:17 +00:00
except ( KeyError , IndexError ) :
2008-06-02 23:26:40 +00:00
return None
2008-10-11 10:22:04 +00:00
def make_new_session ( self , jid , thread_id = None , type_ = ' chat ' , cls = None ) :
2008-10-25 19:48:01 +00:00
''' create and register a new session. thread_id=None to generate one.
type_ should be ' chat ' or ' pm ' . '''
2008-05-23 23:26:53 +00:00
if not cls :
2008-06-02 23:26:40 +00:00
cls = gajim . default_session_type
2008-05-17 02:23:46 +00:00
2008-10-11 10:22:04 +00:00
sess = cls ( self , common . xmpp . JID ( jid ) , thread_id , type_ )
2008-07-26 05:28:15 +00:00
2008-05-17 02:23:46 +00:00
# determine if this session is a pm session
2008-07-26 05:28:15 +00:00
# if not, discard the resource so that all sessions are stored bare
2008-10-11 10:22:04 +00:00
if not type_ == ' pm ' :
2008-05-17 02:23:46 +00:00
jid = gajim . get_jid_without_resource ( jid )
if not jid in self . sessions :
self . sessions [ jid ] = { }
self . sessions [ jid ] [ sess . thread_id ] = sess
return sess
2009-11-14 19:56:15 +01:00
class ConnectionHandlers ( ConnectionVcard , ConnectionBytestream , ConnectionDisco , ConnectionCommands , ConnectionPubSub , ConnectionPEP , ConnectionCaps , ConnectionHandlersBase , ConnectionJingle ) :
2008-05-17 02:23:46 +00:00
def __init__ ( self ) :
ConnectionVcard . __init__ ( self )
ConnectionBytestream . __init__ ( self )
ConnectionCommands . __init__ ( self )
ConnectionPubSub . __init__ ( self )
2009-09-08 12:01:09 +02:00
ConnectionJingle . __init__ ( self )
2008-05-17 02:23:46 +00:00
ConnectionHandlersBase . __init__ ( self )
self . gmail_url = None
2007-12-12 08:44:46 +00:00
# keep the latest subscribed event for each jid to prevent loop when we
2008-05-17 02:23:46 +00:00
# acknowledge presences
2006-09-13 16:47:58 +00:00
self . subscribed_events = { }
2008-02-05 14:50:21 +00:00
# IDs of jabber:iq:last requests
self . last_ids = [ ]
# IDs of jabber:iq:version requests
self . version_ids = [ ]
2009-02-10 21:45:44 +00:00
# IDs of urn:xmpp:time requests
self . entity_time_ids = [ ]
2008-02-07 23:53:02 +00:00
# ID of urn:xmpp:ping requests
self . awaiting_xmpp_ping_id = None
2008-12-03 19:56:37 +00:00
self . continue_connect_info = None
2007-12-12 08:44:46 +00:00
2006-03-19 14:54:00 +00:00
try :
idle . init ( )
2008-10-11 09:37:13 +00:00
except Exception :
2008-12-02 15:53:23 +00:00
global HAS_IDLE
2006-03-19 14:54:00 +00:00
HAS_IDLE = False
2007-12-12 08:44:46 +00:00
2008-06-03 14:15:57 +00:00
self . gmail_last_tid = None
self . gmail_last_time = None
2006-03-19 14:54:00 +00:00
def build_http_auth_answer ( self , iq_obj , answer ) :
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
return
2006-03-19 14:54:00 +00:00
if answer == ' yes ' :
2006-11-18 20:52:28 +00:00
self . connection . send ( iq_obj . buildReply ( ' result ' ) )
2006-03-19 14:54:00 +00:00
elif answer == ' no ' :
2006-11-18 20:52:28 +00:00
err = common . xmpp . Error ( iq_obj ,
common . xmpp . protocol . ERR_NOT_AUTHORIZED )
self . connection . send ( err )
2008-05-17 02:23:46 +00:00
2006-03-19 14:54:00 +00:00
def _HttpAuthCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' HttpAuthCB ' )
2006-03-19 14:54:00 +00:00
opt = gajim . config . get_per ( ' accounts ' , self . name , ' http_auth ' )
if opt in ( ' yes ' , ' no ' ) :
self . build_http_auth_answer ( iq_obj , opt )
else :
2008-12-03 17:16:04 +00:00
id_ = iq_obj . getTagAttr ( ' confirm ' , ' id ' )
2006-03-19 14:54:00 +00:00
method = iq_obj . getTagAttr ( ' confirm ' , ' method ' )
url = iq_obj . getTagAttr ( ' confirm ' , ' url ' )
2007-06-03 10:04:20 +00:00
msg = iq_obj . getTagData ( ' body ' ) # In case it's a message with a body
2008-12-03 17:16:04 +00:00
self . dispatch ( ' HTTP_AUTH ' , ( method , url , id_ , iq_obj , msg ) )
2006-03-19 14:54:00 +00:00
raise common . xmpp . NodeProcessed
def _ErrorCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' ErrorCB ' )
2008-02-05 14:50:21 +00:00
jid_from = helpers . get_full_jid_from_iq ( iq_obj )
jid_stripped , resource = gajim . get_room_and_nick_from_fjid ( jid_from )
2008-12-03 17:16:04 +00:00
id_ = unicode ( iq_obj . getID ( ) )
if id_ in self . version_ids :
2006-11-18 20:52:28 +00:00
self . dispatch ( ' OS_INFO ' , ( jid_stripped , resource , ' ' , ' ' ) )
2008-12-03 17:16:04 +00:00
self . version_ids . remove ( id_ )
2008-02-05 14:50:21 +00:00
return
2008-12-03 17:16:04 +00:00
if id_ in self . last_ids :
2008-02-05 14:50:21 +00:00
self . dispatch ( ' LAST_STATUS_TIME ' , ( jid_stripped , resource , - 1 , ' ' ) )
2008-12-03 17:16:04 +00:00
self . last_ids . remove ( id_ )
2006-11-18 20:52:28 +00:00
return
2009-02-10 21:45:44 +00:00
if id_ in self . entity_time_ids :
self . dispatch ( ' ENTITY_TIME ' , ( jid_stripped , resource , ' ' ) )
self . entity_time_ids . remove ( id_ )
return
2008-12-03 17:16:04 +00:00
if id_ == self . awaiting_xmpp_ping_id :
2008-02-07 23:53:02 +00:00
self . awaiting_xmpp_ping_id = None
2006-11-18 20:52:28 +00:00
errmsg = iq_obj . getErrorMsg ( )
2006-03-19 14:54:00 +00:00
errcode = iq_obj . getErrorCode ( )
2008-12-03 17:16:04 +00:00
self . dispatch ( ' ERROR_ANSWER ' , ( id_ , jid_from , errmsg , errcode ) )
2008-05-02 02:32:28 +00:00
2006-03-19 14:54:00 +00:00
def _PrivateCB ( self , con , iq_obj ) :
'''
2007-08-09 15:39:18 +00:00
Private Data ( XEP 048 and 049 )
2006-03-19 14:54:00 +00:00
'''
2008-12-24 12:11:02 +00:00
log . debug ( ' PrivateCB ' )
2006-03-19 14:54:00 +00:00
query = iq_obj . getTag ( ' query ' )
storage = query . getTag ( ' storage ' )
if storage :
ns = storage . getNamespace ( )
if ns == ' storage:bookmarks ' :
2009-07-31 17:11:55 +02:00
self . _parse_bookmarks ( storage , ' xml ' )
2006-03-19 14:54:00 +00:00
elif ns == ' gajim:prefs ' :
# Preferences data
2007-08-09 15:39:18 +00:00
# http://www.xmpp.org/extensions/xep-0049.html
2006-03-19 14:54:00 +00:00
#TODO: implement this
pass
2006-11-18 20:52:28 +00:00
elif ns == ' storage:rosternotes ' :
# Annotations
# http://www.xmpp.org/extensions/xep-0145.html
notes = storage . getTags ( ' note ' )
for note in notes :
2009-07-08 21:41:40 +02:00
try :
jid = helpers . parse_jid ( note . getAttr ( ' jid ' ) )
except common . helpers . InvalidFormat :
log . warn ( ' Invalid JID: %s , ignoring it ' % note . getAttr ( ' jid ' ) )
continue
2006-11-18 20:52:28 +00:00
annotation = note . getData ( )
self . annotations [ jid ] = annotation
2006-03-19 14:54:00 +00:00
2009-07-31 17:11:55 +02:00
def _parse_bookmarks ( self , storage , storage_type ) :
''' storage_type can be ' pubsub ' or ' xml ' to tell from where we got
bookmarks '''
2009-07-31 14:52:01 +02:00
# Bookmarked URLs and Conferences
# http://www.xmpp.org/extensions/xep-0048.html
2009-07-31 17:11:55 +02:00
resend_to_pubsub = False
2009-07-31 14:52:01 +02:00
confs = storage . getTags ( ' conference ' )
for conf in confs :
autojoin_val = conf . getAttr ( ' autojoin ' )
if autojoin_val is None : # not there (it's optional)
autojoin_val = False
minimize_val = conf . getAttr ( ' minimize ' )
if minimize_val is None : # not there (it's optional)
minimize_val = False
print_status = conf . getTagData ( ' print_status ' )
if not print_status :
print_status = conf . getTagData ( ' show_status ' )
try :
bm = { ' name ' : conf . getAttr ( ' name ' ) ,
' jid ' : helpers . parse_jid ( conf . getAttr ( ' jid ' ) ) ,
' autojoin ' : autojoin_val ,
' minimize ' : minimize_val ,
' password ' : conf . getTagData ( ' password ' ) ,
' nick ' : conf . getTagData ( ' nick ' ) ,
' print_status ' : print_status }
except common . helpers . InvalidFormat :
log . warn ( ' Invalid JID: %s , ignoring it ' % conf . getAttr ( ' jid ' ) )
continue
2009-07-31 17:11:55 +02:00
if bm not in self . bookmarks :
self . bookmarks . append ( bm )
if storage_type == ' xml ' :
# We got a bookmark that was not in pubsub
resend_to_pubsub = True
2009-07-31 14:52:01 +02:00
self . dispatch ( ' BOOKMARKS ' , self . bookmarks )
2009-07-31 17:11:55 +02:00
if storage_type == ' pubsub ' :
# We gor bookmarks from pubsub, now get those from xml to merge them
self . get_bookmarks ( storage_type = ' xml ' )
if self . pubsub_supported and resend_to_pubsub :
self . store_bookmarks ( ' pubsub ' )
2009-07-31 14:52:01 +02:00
2006-03-19 14:54:00 +00:00
def _rosterSetCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' rosterSetCB ' )
2009-06-23 19:29:25 +02:00
version = iq_obj . getTagAttr ( ' query ' , ' ver ' )
2006-03-19 14:54:00 +00:00
for item in iq_obj . getTag ( ' query ' ) . getChildren ( ) :
2009-07-08 21:41:40 +02:00
try :
jid = helpers . parse_jid ( item . getAttr ( ' jid ' ) )
except common . helpers . InvalidFormat :
log . warn ( ' Invalid JID: %s , ignoring it ' % item . getAttr ( ' jid ' ) )
continue
2006-03-19 14:54:00 +00:00
name = item . getAttr ( ' name ' )
2007-12-12 08:44:46 +00:00
sub = item . getAttr ( ' subscription ' )
ask = item . getAttr ( ' ask ' )
2006-03-19 14:54:00 +00:00
groups = [ ]
for group in item . getTags ( ' group ' ) :
groups . append ( group . getData ( ) )
self . dispatch ( ' ROSTER_INFO ' , ( jid , name , sub , ask , groups ) )
2009-06-29 15:49:46 +02:00
account_jid = gajim . get_jid_from_account ( self . name )
gajim . logger . add_or_update_contact ( account_jid , jid , name , sub , ask ,
groups )
2009-06-23 19:29:25 +02:00
if version :
gajim . config . set_per ( ' accounts ' , self . name , ' roster_version ' ,
version )
2009-02-19 09:52:23 +00:00
if not self . connection or self . connected < 2 :
raise common . xmpp . NodeProcessed
reply = common . xmpp . Iq ( typ = ' result ' , attrs = { ' id ' : iq_obj . getID ( ) } ,
2009-04-22 08:39:10 +00:00
to = iq_obj . getFrom ( ) , frm = iq_obj . getTo ( ) , xmlns = None )
2009-02-19 09:52:23 +00:00
self . connection . send ( reply )
2006-03-19 14:54:00 +00:00
raise common . xmpp . NodeProcessed
2008-12-03 21:56:12 +00:00
2006-03-19 14:54:00 +00:00
def _VersionCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' VersionCB ' )
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
return
2006-03-19 14:54:00 +00:00
iq_obj = iq_obj . buildReply ( ' result ' )
qp = iq_obj . getTag ( ' query ' )
qp . setTagData ( ' name ' , ' Gajim ' )
qp . setTagData ( ' version ' , gajim . version )
2009-01-29 20:16:34 +00:00
send_os = gajim . config . get_per ( ' accounts ' , self . name , ' send_os_info ' )
2006-03-19 14:54:00 +00:00
if send_os :
qp . setTagData ( ' os ' , helpers . get_os_info ( ) )
self . connection . send ( iq_obj )
raise common . xmpp . NodeProcessed
2008-02-07 23:53:02 +00:00
2006-03-19 14:54:00 +00:00
def _LastCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' LastCB ' )
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
return
2006-03-19 14:54:00 +00:00
iq_obj = iq_obj . buildReply ( ' result ' )
qp = iq_obj . getTag ( ' query ' )
if not HAS_IDLE :
2008-12-02 13:58:54 +00:00
qp . attrs [ ' seconds ' ] = ' 0 '
2006-03-19 14:54:00 +00:00
else :
qp . attrs [ ' seconds ' ] = idle . getIdleSec ( )
2008-12-03 21:56:12 +00:00
2006-03-19 14:54:00 +00:00
self . connection . send ( iq_obj )
raise common . xmpp . NodeProcessed
2008-02-07 23:53:02 +00:00
2006-03-19 14:54:00 +00:00
def _LastResultCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' LastResultCB ' )
2006-03-19 14:54:00 +00:00
qp = iq_obj . getTag ( ' query ' )
seconds = qp . getAttr ( ' seconds ' )
status = qp . getData ( )
try :
seconds = int ( seconds )
2008-10-11 09:37:13 +00:00
except Exception :
2006-03-19 14:54:00 +00:00
return
2008-12-03 17:16:04 +00:00
id_ = iq_obj . getID ( )
if id_ in self . groupchat_jids :
who = self . groupchat_jids [ id_ ]
del self . groupchat_jids [ id_ ]
2007-08-09 15:39:18 +00:00
else :
who = helpers . get_full_jid_from_iq ( iq_obj )
2008-12-03 17:16:04 +00:00
if id_ in self . last_ids :
self . last_ids . remove ( id_ )
2006-03-19 14:54:00 +00:00
jid_stripped , resource = gajim . get_room_and_nick_from_fjid ( who )
self . dispatch ( ' LAST_STATUS_TIME ' , ( jid_stripped , resource , seconds , status ) )
2008-02-07 23:53:02 +00:00
2006-03-19 14:54:00 +00:00
def _VersionResultCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' VersionResultCB ' )
2006-03-19 14:54:00 +00:00
client_info = ' '
os_info = ' '
qp = iq_obj . getTag ( ' query ' )
if qp . getTag ( ' name ' ) :
client_info + = qp . getTag ( ' name ' ) . getData ( )
if qp . getTag ( ' version ' ) :
client_info + = ' ' + qp . getTag ( ' version ' ) . getData ( )
if qp . getTag ( ' os ' ) :
os_info + = qp . getTag ( ' os ' ) . getData ( )
2008-12-03 17:16:04 +00:00
id_ = iq_obj . getID ( )
if id_ in self . groupchat_jids :
who = self . groupchat_jids [ id_ ]
del self . groupchat_jids [ id_ ]
2007-08-09 15:39:18 +00:00
else :
who = helpers . get_full_jid_from_iq ( iq_obj )
2006-03-19 14:54:00 +00:00
jid_stripped , resource = gajim . get_room_and_nick_from_fjid ( who )
2008-12-03 17:16:04 +00:00
if id_ in self . version_ids :
self . version_ids . remove ( id_ )
2006-03-19 14:54:00 +00:00
self . dispatch ( ' OS_INFO ' , ( jid_stripped , resource , client_info , os_info ) )
2006-09-13 16:47:58 +00:00
def _TimeCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' TimeCB ' )
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
return
2006-09-13 16:47:58 +00:00
iq_obj = iq_obj . buildReply ( ' result ' )
qp = iq_obj . getTag ( ' query ' )
2008-12-01 10:56:14 +00:00
qp . setTagData ( ' utc ' , strftime ( ' % Y % m %d T % H: % M: % S ' , gmtime ( ) ) )
2007-12-13 08:37:20 +00:00
qp . setTagData ( ' tz ' , helpers . decode_string ( tzname [ daylight ] ) )
2007-12-12 08:44:46 +00:00
qp . setTagData ( ' display ' , helpers . decode_string ( strftime ( ' %c ' ,
localtime ( ) ) ) )
2006-09-13 16:47:58 +00:00
self . connection . send ( iq_obj )
raise common . xmpp . NodeProcessed
2006-12-28 16:27:41 +00:00
def _TimeRevisedCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' TimeRevisedCB ' )
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
return
2006-12-28 16:27:41 +00:00
iq_obj = iq_obj . buildReply ( ' result ' )
2007-08-09 15:39:18 +00:00
qp = iq_obj . setTag ( ' time ' ,
2007-12-12 08:44:46 +00:00
namespace = common . xmpp . NS_TIME_REVISED )
2008-12-01 10:56:14 +00:00
qp . setTagData ( ' utc ' , strftime ( ' % Y- % m- %d T % H: % M: % SZ ' , gmtime ( ) ) )
2009-02-11 10:58:57 +00:00
isdst = localtime ( ) . tm_isdst
2009-02-10 22:25:04 +00:00
zone = - ( timezone , altzone ) [ isdst ] / 60
2007-08-09 15:39:18 +00:00
tzo = ( zone / 60 , abs ( zone % 60 ) )
qp . setTagData ( ' tzo ' , ' %+03d : %02d ' % ( tzo ) )
2006-12-28 16:27:41 +00:00
self . connection . send ( iq_obj )
raise common . xmpp . NodeProcessed
2009-02-10 21:45:44 +00:00
def _TimeRevisedResultCB ( self , con , iq_obj ) :
log . debug ( ' TimeRevisedResultCB ' )
time_info = ' '
qp = iq_obj . getTag ( ' time ' )
2009-02-14 18:56:17 +00:00
if not qp :
# wrong answer
return
2009-02-10 21:45:44 +00:00
tzo = qp . getTag ( ' tzo ' ) . getData ( )
if tzo == ' Z ' :
tzo = ' 0:0 '
tzoh , tzom = tzo . split ( ' : ' )
utc_time = qp . getTag ( ' utc ' ) . getData ( )
ZERO = datetime . timedelta ( 0 )
class UTC ( datetime . tzinfo ) :
def utcoffset ( self , dt ) :
return ZERO
def tzname ( self , dt ) :
return " UTC "
def dst ( self , dt ) :
return ZERO
class contact_tz ( datetime . tzinfo ) :
def utcoffset ( self , dt ) :
return datetime . timedelta ( hours = int ( tzoh ) , minutes = int ( tzom ) )
def tzname ( self , dt ) :
return " remote timezone "
def dst ( self , dt ) :
return ZERO
2009-03-18 11:04:25 +00:00
try :
t = datetime . datetime . strptime ( utc_time , ' % Y- % m- %d T % H: % M: % SZ ' )
t = t . replace ( tzinfo = UTC ( ) )
time_info = t . astimezone ( contact_tz ( ) ) . strftime ( ' %c ' )
except ValueError , e :
log . info ( ' Wrong time format: %s ' % str ( e ) )
2009-02-10 21:45:44 +00:00
id_ = iq_obj . getID ( )
if id_ in self . groupchat_jids :
who = self . groupchat_jids [ id_ ]
del self . groupchat_jids [ id_ ]
else :
who = helpers . get_full_jid_from_iq ( iq_obj )
jid_stripped , resource = gajim . get_room_and_nick_from_fjid ( who )
if id_ in self . entity_time_ids :
self . entity_time_ids . remove ( id_ )
self . dispatch ( ' ENTITY_TIME ' , ( jid_stripped , resource , time_info ) )
2006-03-19 14:54:00 +00:00
def _gMailNewMailCB ( self , con , gm ) :
''' Called when we get notified of new mail messages in gmail account '''
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
return
2006-03-19 14:54:00 +00:00
if not gm . getTag ( ' new-mail ' ) :
return
if gm . getTag ( ' new-mail ' ) . getNamespace ( ) == common . xmpp . NS_GMAILNOTIFY :
# we'll now ask the server for the exact number of new messages
jid = gajim . get_jid_from_account ( self . name )
2008-12-24 12:11:02 +00:00
log . debug ( ' Got notification of new gmail e-mail on %s . Asking the server for more info. ' % jid )
2006-03-19 14:54:00 +00:00
iq = common . xmpp . Iq ( typ = ' get ' )
2008-06-03 14:15:57 +00:00
iq . setID ( self . connection . getAnID ( ) )
2006-03-19 14:54:00 +00:00
query = iq . setTag ( ' query ' )
query . setNamespace ( common . xmpp . NS_GMAILNOTIFY )
2008-06-03 14:15:57 +00:00
# we want only be notified about newer mails
if self . gmail_last_tid :
query . setAttr ( ' newer-than-tid ' , self . gmail_last_tid )
if self . gmail_last_time :
query . setAttr ( ' newer-than-time ' , self . gmail_last_time )
2006-03-19 14:54:00 +00:00
self . connection . send ( iq )
raise common . xmpp . NodeProcessed
def _gMailQueryCB ( self , con , gm ) :
''' Called when we receive results from Querying the server for mail messages in gmail account '''
if not gm . getTag ( ' mailbox ' ) :
return
2007-08-09 15:39:18 +00:00
self . gmail_url = gm . getTag ( ' mailbox ' ) . getAttr ( ' url ' )
2006-03-19 14:54:00 +00:00
if gm . getTag ( ' mailbox ' ) . getNamespace ( ) == common . xmpp . NS_GMAILNOTIFY :
newmsgs = gm . getTag ( ' mailbox ' ) . getAttr ( ' total-matched ' )
if newmsgs != ' 0 ' :
# there are new messages
2006-07-17 19:30:53 +00:00
gmail_messages_list = [ ]
if gm . getTag ( ' mailbox ' ) . getTag ( ' mail-thread-info ' ) :
gmail_messages = gm . getTag ( ' mailbox ' ) . getTags ( ' mail-thread-info ' )
for gmessage in gmail_messages :
2008-06-03 14:15:57 +00:00
unread_senders = [ ]
for sender in gmessage . getTag ( ' senders ' ) . getTags ( ' sender ' ) :
if sender . getAttr ( ' unread ' ) != ' 1 ' :
continue
if sender . getAttr ( ' name ' ) :
unread_senders . append ( sender . getAttr ( ' name ' ) + ' < ' + \
sender . getAttr ( ' address ' ) + ' > ' )
else :
unread_senders . append ( sender . getAttr ( ' address ' ) )
if not unread_senders :
2006-11-18 20:52:28 +00:00
continue
2006-07-17 19:30:53 +00:00
gmail_subject = gmessage . getTag ( ' subject ' ) . getData ( )
gmail_snippet = gmessage . getTag ( ' snippet ' ) . getData ( )
2008-06-03 14:15:57 +00:00
tid = int ( gmessage . getAttr ( ' tid ' ) )
if not self . gmail_last_tid or tid > self . gmail_last_tid :
self . gmail_last_tid = tid
2006-07-17 19:30:53 +00:00
gmail_messages_list . append ( { \
2008-06-03 14:15:57 +00:00
' From ' : unread_senders , \
2006-07-17 19:30:53 +00:00
' Subject ' : gmail_subject , \
2008-06-03 14:15:57 +00:00
' Snippet ' : gmail_snippet , \
' url ' : gmessage . getAttr ( ' url ' ) , \
' participation ' : gmessage . getAttr ( ' participation ' ) , \
' messages ' : gmessage . getAttr ( ' messages ' ) , \
' date ' : gmessage . getAttr ( ' date ' ) } )
self . gmail_last_time = int ( gm . getTag ( ' mailbox ' ) . getAttr (
' result-time ' ) )
2006-03-19 14:54:00 +00:00
jid = gajim . get_jid_from_account ( self . name )
2008-12-24 12:11:02 +00:00
log . debug ( ( ' You have %s new gmail e-mails on %s . ' ) % ( newmsgs , jid ) )
2006-07-17 19:30:53 +00:00
self . dispatch ( ' GMAIL_NOTIFY ' , ( jid , newmsgs , gmail_messages_list ) )
2006-03-19 14:54:00 +00:00
raise common . xmpp . NodeProcessed
2009-06-21 03:43:57 +02:00
def _rosterItemExchangeCB ( self , con , msg ) :
''' XEP-0144 Roster Item Echange '''
exchange_items_list = { }
2009-07-07 19:17:28 +02:00
jid_from = helpers . get_full_jid_from_iq ( msg )
2009-06-21 03:43:57 +02:00
items_list = msg . getTag ( ' x ' ) . getChildren ( )
2009-07-22 10:48:28 +02:00
if not items_list :
return
2009-06-21 03:43:57 +02:00
action = items_list [ 0 ] . getAttr ( ' action ' )
if action == None :
action = ' add '
2009-07-07 16:28:26 +02:00
for item in msg . getTag ( ' x ' ,
namespace = common . xmpp . NS_ROSTERX ) . getChildren ( ) :
2009-07-08 21:41:40 +02:00
try :
jid = helpers . parse_jid ( item . getAttr ( ' jid ' ) )
except common . helpers . InvalidFormat :
log . warn ( ' Invalid JID: %s , ignoring it ' % item . getAttr ( ' jid ' ) )
continue
2009-06-21 03:43:57 +02:00
name = item . getAttr ( ' name ' )
2009-11-19 22:13:16 +01:00
contact = gajim . contact . get_contact ( self . name , jid )
groups = [ ]
same_groups = True
2009-07-07 16:28:26 +02:00
for group in item . getTags ( ' group ' ) :
2009-06-21 03:43:57 +02:00
groups . append ( group . getData ( ) )
2009-11-19 22:13:16 +01:00
# check that all suggested groups are in the groups we have for this
# contact
if not contact or group not in contact . groups :
same_groups = False
if contact :
# check that all groups we have for this contact are in the
# suggested groups
for group in contact . groups :
if group not in groups :
same_groups = False
if contact . subscription in ( ' both ' , ' to ' ) and same_groups :
continue
2009-06-21 03:43:57 +02:00
exchange_items_list [ jid ] = [ ]
exchange_items_list [ jid ] . append ( name )
exchange_items_list [ jid ] . append ( groups )
2009-10-02 14:58:47 +02:00
if exchange_items_list :
self . dispatch ( ' ROSTERX ' , ( action , exchange_items_list , jid_from ) )
2009-10-02 16:54:33 +02:00
raise common . xmpp . NodeProcessed
2009-06-21 03:43:57 +02:00
2006-03-19 14:54:00 +00:00
def _messageCB ( self , con , msg ) :
''' Called when we receive a message '''
2008-12-24 12:11:02 +00:00
log . debug ( ' MessageCB ' )
2009-07-07 13:41:05 +02:00
mtype = msg . getType ( )
2009-07-31 14:52:01 +02:00
2009-06-21 03:43:57 +02:00
# check if the message is a roster item exchange (XEP-0144)
2009-07-07 16:28:26 +02:00
if msg . getTag ( ' x ' , namespace = common . xmpp . NS_ROSTERX ) :
self . _rosterItemExchangeCB ( con , msg )
return
2008-05-18 17:35:00 +00:00
# check if the message is a XEP-0070 confirmation request
if msg . getTag ( ' confirm ' , namespace = common . xmpp . NS_HTTP_AUTH ) :
self . _HttpAuthCB ( con , msg )
return
2008-12-13 14:43:46 +00:00
try :
frm = helpers . get_full_jid_from_iq ( msg )
jid = helpers . get_jid_from_iq ( msg )
except helpers . InvalidFormat :
self . dispatch ( ' ERROR ' , ( _ ( ' Invalid Jabber ID ' ) ,
_ ( ' A message from a non-valid JID arrived, it has been ignored. ' ) ) )
2008-08-28 12:24:31 +00:00
addressTag = msg . getTag ( ' addresses ' , namespace = common . xmpp . NS_ADDRESS )
# Be sure it comes from one of our resource, else ignore address element
if addressTag and jid == gajim . get_jid_from_account ( self . name ) :
address = addressTag . getTag ( ' address ' , attrs = { ' type ' : ' ofrom ' } )
if address :
2009-07-08 21:41:40 +02:00
try :
frm = helpers . parse_jid ( address . getAttr ( ' jid ' ) )
except common . helpers . InvalidFormat :
log . warn ( ' Invalid JID: %s , ignoring it ' % address . getAttr ( ' jid ' ) )
return
2008-08-28 12:24:31 +00:00
jid = gajim . get_jid_without_resource ( frm )
2008-05-18 17:35:00 +00:00
# invitations
invite = None
encTag = msg . getTag ( ' x ' , namespace = common . xmpp . NS_ENCRYPTED )
if not encTag :
invite = msg . getTag ( ' x ' , namespace = common . xmpp . NS_MUC_USER )
if invite and not invite . getTag ( ' invite ' ) :
invite = None
# FIXME: Msn transport (CMSN1.2.1 and PyMSN0.10) do NOT RECOMMENDED
# invitation
# stanza (MUC XEP) remove in 2007, as we do not do NOT RECOMMENDED
xtags = msg . getTags ( ' x ' )
for xtag in xtags :
if xtag . getNamespace ( ) == common . xmpp . NS_CONFERENCE and not invite :
2009-07-08 21:41:40 +02:00
try :
room_jid = helpers . parse_jid ( xtag . getAttr ( ' jid ' ) )
except common . helpers . InvalidFormat :
log . warn ( ' Invalid JID: %s , ignoring it ' % xtag . getAttr ( ' jid ' ) )
continue
2008-05-18 17:35:00 +00:00
is_continued = False
if xtag . getTag ( ' continue ' ) :
is_continued = True
self . dispatch ( ' GC_INVITATION ' , ( room_jid , frm , ' ' , None ,
is_continued ) )
return
2007-12-12 08:44:46 +00:00
thread_id = msg . getThread ( )
if not mtype :
mtype = ' normal '
2006-03-19 14:54:00 +00:00
msgtxt = msg . getBody ( )
2008-04-06 22:21:46 +00:00
2008-05-23 23:26:53 +00:00
encrypted = False
2008-05-23 23:27:08 +00:00
xep_200_encrypted = msg . getTag ( ' c ' , namespace = common . xmpp . NS_STANZA_CRYPTO )
2008-06-24 01:17:02 +00:00
2009-02-06 19:01:36 +00:00
session = None
2008-06-03 01:13:30 +00:00
if mtype != ' groupchat ' :
2008-05-23 23:26:53 +00:00
session = self . get_or_create_session ( frm , thread_id )
if thread_id and not session . received_thread_id :
session . received_thread_id = True
2008-05-25 21:28:32 +00:00
session . last_receive = time_time ( )
2008-05-23 23:26:53 +00:00
# check if the message is a XEP-0020 feature negotiation request
if msg . getTag ( ' feature ' , namespace = common . xmpp . NS_FEATURE ) :
if gajim . HAVE_PYCRYPTO :
2008-06-21 19:12:47 +00:00
feature = msg . getTag ( name = ' feature ' , namespace = common . xmpp . NS_FEATURE )
form = common . xmpp . DataForm ( node = feature . getTag ( ' x ' ) )
if form [ ' FORM_TYPE ' ] == ' urn:xmpp:ssn ' :
session . handle_negotiation ( form )
else :
reply = msg . buildReply ( )
reply . setType ( ' error ' )
reply . addChild ( feature )
err = common . xmpp . ErrorNode ( ' service-unavailable ' , typ = ' cancel ' )
reply . addChild ( node = err )
con . send ( reply )
raise common . xmpp . NodeProcessed
2008-05-23 23:26:53 +00:00
return
2008-06-21 19:12:47 +00:00
2008-05-23 23:26:53 +00:00
if msg . getTag ( ' init ' , namespace = common . xmpp . NS_ESESSION_INIT ) :
2008-06-21 19:12:47 +00:00
init = msg . getTag ( name = ' init ' , namespace = common . xmpp . NS_ESESSION_INIT )
form = common . xmpp . DataForm ( node = init . getTag ( ' x ' ) )
session . handle_negotiation ( form )
raise common . xmpp . NodeProcessed
2008-05-23 23:26:53 +00:00
tim = msg . getTimestamp ( )
tim = helpers . datetime_tuple ( tim )
tim = localtime ( timegm ( tim ) )
2008-05-23 23:27:08 +00:00
if xep_200_encrypted :
2008-08-30 02:50:10 +00:00
encrypted = ' xep200 '
2008-05-23 23:26:53 +00:00
try :
msg = session . decrypt_stanza ( msg )
2008-05-23 23:27:08 +00:00
msgtxt = msg . getBody ( )
2008-10-11 09:37:13 +00:00
except Exception :
2008-05-23 23:26:53 +00:00
self . dispatch ( ' FAILED_DECRYPT ' , ( frm , tim , session ) )
2008-07-14 00:25:53 +00:00
# Receipt requested
# TODO: We shouldn't answer if we're invisible!
2008-09-27 18:04:29 +00:00
contact = gajim . contacts . get_contact ( self . name , jid )
nick = gajim . get_room_and_nick_from_fjid ( frm ) [ 1 ]
gc_contact = gajim . contacts . get_gc_contact ( self . name , jid , nick )
2008-07-14 00:25:53 +00:00
if msg . getTag ( ' request ' , namespace = common . xmpp . NS_RECEIPTS ) \
and gajim . config . get_per ( ' accounts ' , self . name ,
2008-09-27 18:04:29 +00:00
' answer_receipts ' ) and ( ( contact and contact . sub \
2009-10-01 09:41:46 +02:00
not in ( u ' to ' , u ' none ' ) ) or gc_contact ) and mtype != ' error ' :
2008-09-27 18:04:29 +00:00
receipt = common . xmpp . Message ( to = frm , typ = ' chat ' )
2008-07-14 00:25:53 +00:00
receipt . setID ( msg . getID ( ) )
receipt . setTag ( ' received ' ,
namespace = ' urn:xmpp:receipts ' )
if thread_id :
receipt . setThread ( thread_id )
con . send ( receipt )
2008-07-18 20:24:34 +00:00
# We got our message's receipt
if msg . getTag ( ' received ' , namespace = common . xmpp . NS_RECEIPTS ) \
and session . control and gajim . config . get_per ( ' accounts ' ,
self . name , ' request_receipt ' ) :
session . control . conv_textview . hide_xep0184_warning (
msg . getID ( ) )
2007-12-28 18:49:28 +00:00
if encTag and self . USE_GPG :
2006-03-19 14:54:00 +00:00
encmsg = encTag . getData ( )
2007-12-12 08:44:46 +00:00
2006-03-19 14:54:00 +00:00
keyID = gajim . config . get_per ( ' accounts ' , self . name , ' keyid ' )
if keyID :
2009-02-06 19:01:36 +00:00
def decrypt_thread ( encmsg , keyID ) :
decmsg = self . gpg . decrypt ( encmsg , keyID )
# \x00 chars are not allowed in C (so in GTK)
2009-02-08 09:56:38 +00:00
msgtxt = helpers . decode_string ( decmsg . replace ( ' \x00 ' , ' ' ) )
2009-02-06 19:01:36 +00:00
encrypted = ' xep27 '
return ( msgtxt , encrypted )
gajim . thread_interface ( decrypt_thread , [ encmsg , keyID ] ,
self . _on_message_decrypted , [ mtype , msg , session , frm , jid ,
invite , tim ] )
return
self . _on_message_decrypted ( ( msgtxt , encrypted ) , mtype , msg , session , frm ,
jid , invite , tim )
def _on_message_decrypted ( self , output , mtype , msg , session , frm , jid ,
invite , tim ) :
msgtxt , encrypted = output
2006-03-19 14:54:00 +00:00
if mtype == ' error ' :
2008-05-23 23:27:08 +00:00
self . dispatch_error_message ( msg , msgtxt , session , frm , tim )
2006-03-19 14:54:00 +00:00
elif mtype == ' groupchat ' :
2008-05-23 23:27:08 +00:00
self . dispatch_gc_message ( msg , frm , msgtxt , jid , tim )
2008-04-06 22:21:46 +00:00
elif invite is not None :
self . dispatch_invite_message ( invite , frm )
2008-04-11 03:52:45 +00:00
else :
2008-08-27 07:53:12 +00:00
if isinstance ( session , gajim . default_session_type ) :
2008-05-23 23:27:08 +00:00
session . received ( frm , msgtxt , tim , encrypted , msg )
2006-03-19 14:54:00 +00:00
else :
2008-04-15 05:32:45 +00:00
session . received ( msg )
2008-05-11 13:17:28 +00:00
# END messageCB
2008-05-11 01:19:59 +00:00
2008-04-06 22:21:46 +00:00
# process and dispatch an error message
2008-05-23 23:27:08 +00:00
def dispatch_error_message ( self , msg , msgtxt , session , frm , tim ) :
2008-05-13 01:59:10 +00:00
error_msg = msg . getErrorMsg ( )
2008-04-06 22:21:46 +00:00
if not error_msg :
error_msg = msgtxt
msgtxt = None
2008-05-23 23:27:08 +00:00
subject = msg . getSubject ( )
2008-04-06 22:21:46 +00:00
if session . is_loggable ( ) :
try :
2008-05-13 01:59:10 +00:00
gajim . logger . write ( ' error ' , frm , error_msg , tim = tim ,
subject = subject )
2008-04-06 22:21:46 +00:00
except exceptions . PysqliteOperationalError , e :
self . dispatch ( ' ERROR ' , ( _ ( ' Disk Write Error ' ) , str ( e ) ) )
2008-10-22 15:48:35 +00:00
except exceptions . DatabaseMalformed :
pritext = _ ( ' Database Error ' )
sectext = _ ( ' The database file ( %s ) cannot be read. Try to repair '
2008-10-22 17:31:45 +00:00
' it (see http://trac.gajim.org/wiki/DatabaseBackup) or remove '
' it (all history will be lost). ' ) % common . logger . LOG_DB_PATH
2008-10-22 15:48:35 +00:00
self . dispatch ( ' ERROR ' , ( pritext , sectext ) )
2008-05-13 01:59:10 +00:00
self . dispatch ( ' MSGERROR ' , ( frm , msg . getErrorCode ( ) , error_msg , msgtxt ,
tim , session ) )
2008-04-06 22:21:46 +00:00
# process and dispatch a groupchat message
2008-05-23 23:27:08 +00:00
def dispatch_gc_message ( self , msg , frm , msgtxt , jid , tim ) :
2008-04-06 22:21:46 +00:00
has_timestamp = bool ( msg . timestamp )
2008-05-23 23:27:08 +00:00
subject = msg . getSubject ( )
2008-05-13 01:59:10 +00:00
if subject is not None :
2008-04-06 22:21:46 +00:00
self . dispatch ( ' GC_SUBJECT ' , ( frm , subject , msgtxt , has_timestamp ) )
2008-05-13 01:59:10 +00:00
return
2008-04-06 22:21:46 +00:00
2008-05-13 01:59:10 +00:00
statusCode = msg . getStatusCode ( )
2008-04-06 22:21:46 +00:00
2008-05-13 01:59:10 +00:00
if not msg . getTag ( ' body ' ) : # no <body>
# It could be a config change. See
# http://www.xmpp.org/extensions/xep-0045.html#roomconfig-notify
if msg . getTag ( ' x ' ) :
if statusCode != [ ] :
self . dispatch ( ' GC_CONFIG_CHANGE ' , ( jid , statusCode ) )
return
2008-04-06 22:21:46 +00:00
2008-05-13 01:59:10 +00:00
# Ignore message from room in which we are not
2008-10-07 20:41:59 +00:00
if jid not in self . last_history_time :
2008-05-13 01:59:10 +00:00
return
2008-04-06 22:21:46 +00:00
2008-05-13 01:59:10 +00:00
self . dispatch ( ' GC_MSG ' , ( frm , msgtxt , tim , has_timestamp , msg . getXHTML ( ) ,
statusCode ) )
2008-04-06 22:21:46 +00:00
2008-05-13 01:59:10 +00:00
tim_int = int ( float ( mktime ( tim ) ) )
2008-08-30 01:31:25 +00:00
if gajim . config . should_log ( self . name , jid ) and not \
2008-05-13 01:59:10 +00:00
tim_int < = self . last_history_time [ jid ] and msgtxt and frm . find ( ' / ' ) > = 0 :
# if frm.find('/') < 0, it means message comes from room itself
# usually it hold description and can be send at each connection
# so don't store it in logs
try :
gajim . logger . write ( ' gc_msg ' , frm , msgtxt , tim = tim )
except exceptions . PysqliteOperationalError , e :
self . dispatch ( ' ERROR ' , ( _ ( ' Disk Write Error ' ) , str ( e ) ) )
2008-10-22 15:48:35 +00:00
except exceptions . DatabaseMalformed :
pritext = _ ( ' Database Error ' )
sectext = _ ( ' The database file ( %s ) cannot be read. Try to repair '
2008-10-22 17:31:45 +00:00
' it (see http://trac.gajim.org/wiki/DatabaseBackup) or remove '
' it (all history will be lost). ' ) % common . logger . LOG_DB_PATH
2008-10-22 15:48:35 +00:00
self . dispatch ( ' ERROR ' , ( pritext , sectext ) )
2008-04-06 22:21:46 +00:00
2008-04-11 03:52:45 +00:00
def dispatch_invite_message ( self , invite , frm ) :
2008-04-06 22:21:46 +00:00
item = invite . getTag ( ' invite ' )
2009-07-08 21:41:40 +02:00
try :
jid_from = helpers . parse_jid ( item . getAttr ( ' from ' ) )
except common . helpers . InvalidFormat :
log . warn ( ' Invalid JID: %s , ignoring it ' % item . getAttr ( ' from ' ) )
return
2008-04-06 22:21:46 +00:00
reason = item . getTagData ( ' reason ' )
item = invite . getTag ( ' password ' )
password = invite . getTagData ( ' password ' )
is_continued = False
if invite . getTag ( ' invite ' ) . getTag ( ' continue ' ) :
is_continued = True
self . dispatch ( ' GC_INVITATION ' , ( frm , jid_from , reason , password ,
is_continued ) )
2006-03-19 14:54:00 +00:00
def _presenceCB ( self , con , prs ) :
''' Called when we receive a presence '''
ptype = prs . getType ( )
if ptype == ' available ' :
ptype = None
2009-10-06 17:35:25 +02:00
rfc_types = ( ' unavailable ' , ' error ' , ' subscribe ' , ' subscribed ' ,
' unsubscribe ' , ' unsubscribed ' )
2007-06-03 10:04:20 +00:00
if ptype and not ptype in rfc_types :
ptype = None
2008-12-24 12:11:02 +00:00
log . debug ( ' PresenceCB: %s ' % ptype )
2009-05-20 10:33:19 +02:00
if not self . connection or self . connected < 2 :
log . debug ( ' account is no more connected ' )
return
2006-09-13 16:47:58 +00:00
try :
who = helpers . get_full_jid_from_iq ( prs )
2008-10-11 09:37:13 +00:00
except Exception :
2009-04-29 17:34:27 +00:00
if prs . getTag ( ' error ' ) and prs . getTag ( ' error ' ) . getTag ( ' jid-malformed ' ) :
2007-12-12 08:44:46 +00:00
# wrong jid, we probably tried to change our nick in a room to a non
# valid one
2006-09-13 16:47:58 +00:00
who = str ( prs . getFrom ( ) )
jid_stripped , resource = gajim . get_room_and_nick_from_fjid ( who )
2006-11-18 20:52:28 +00:00
self . dispatch ( ' GC_MSG ' , ( jid_stripped ,
2007-12-12 08:44:46 +00:00
_ ( ' Nickname not allowed: %s ' ) % resource , None , False , None , [ ] ) )
2006-09-13 16:47:58 +00:00
return
2006-04-18 14:30:00 +00:00
jid_stripped , resource = gajim . get_room_and_nick_from_fjid ( who )
2006-04-01 18:16:06 +00:00
timestamp = None
2009-10-13 19:26:56 +02:00
id_ = prs . getID ( )
2006-03-19 14:54:00 +00:00
is_gc = False # is it a GC presence ?
sigTag = None
2007-03-11 20:14:53 +00:00
ns_muc_user_x = None
2006-04-29 09:44:47 +00:00
avatar_sha = None
2007-08-09 15:39:18 +00:00
# XEP-0172 User Nickname
2006-09-13 16:47:58 +00:00
user_nick = prs . getTagData ( ' nick ' )
if not user_nick :
user_nick = ' '
2007-06-03 10:04:20 +00:00
contact_nickname = None
2006-04-18 14:30:00 +00:00
transport_auto_auth = False
2008-09-26 11:11:38 +00:00
# XEP-0203
delay_tag = prs . getTag ( ' delay ' , namespace = common . xmpp . NS_DELAY2 )
if delay_tag :
tim = prs . getTimestamp2 ( )
tim = helpers . datetime_tuple ( tim )
timestamp = localtime ( timegm ( tim ) )
2006-03-19 14:54:00 +00:00
xtags = prs . getTags ( ' x ' )
for x in xtags :
2006-06-01 15:23:38 +00:00
namespace = x . getNamespace ( )
if namespace . startswith ( common . xmpp . NS_MUC ) :
2006-03-19 14:54:00 +00:00
is_gc = True
2007-03-11 20:14:53 +00:00
if namespace == common . xmpp . NS_MUC_USER and x . getTag ( ' destroy ' ) :
ns_muc_user_x = x
elif namespace == common . xmpp . NS_SIGNED :
2006-03-19 14:54:00 +00:00
sigTag = x
2007-03-11 20:14:53 +00:00
elif namespace == common . xmpp . NS_VCARD_UPDATE :
2006-03-19 14:54:00 +00:00
avatar_sha = x . getTagData ( ' photo ' )
2007-06-03 10:04:20 +00:00
contact_nickname = x . getTagData ( ' nickname ' )
2008-09-26 11:11:38 +00:00
elif namespace == common . xmpp . NS_DELAY and not timestamp :
2007-08-09 15:39:18 +00:00
# XEP-0091
2006-04-01 18:16:06 +00:00
tim = prs . getTimestamp ( )
2007-08-09 15:39:18 +00:00
tim = helpers . datetime_tuple ( tim )
timestamp = localtime ( timegm ( tim ) )
2007-03-11 20:14:53 +00:00
elif namespace == ' http://delx.cjb.net/protocol/roster-subsync ' :
2006-04-29 09:44:47 +00:00
# see http://trac.gajim.org/ticket/326
agent = gajim . get_server_from_jid ( jid_stripped )
if self . connection . getRoster ( ) . getItem ( agent ) : # to be sure it's a transport contact
2006-04-18 14:30:00 +00:00
transport_auto_auth = True
2006-03-19 14:54:00 +00:00
2009-10-13 19:26:56 +02:00
if not is_gc and id_ and id_ . startswith ( ' gajim_muc_ ' ) and \
ptype == ' error ' :
# Error presences may not include sent stanza, so we don't detect it's
# a muc preence. So detect it by ID
h = hmac . new ( self . secret_hmac , jid_stripped ) . hexdigest ( ) [ : 6 ]
2009-10-13 19:31:07 +02:00
if id_ . split ( ' _ ' ) [ - 1 ] == h :
2009-10-13 19:26:56 +02:00
is_gc = True
2006-09-13 16:47:58 +00:00
status = prs . getStatus ( ) or ' '
2006-03-19 14:54:00 +00:00
show = prs . getShow ( )
2009-10-31 23:22:12 +01:00
if show not in ( ' chat ' , ' away ' , ' xa ' , ' dnd ' ) :
2006-03-19 14:54:00 +00:00
show = ' ' # We ignore unknown show
if not ptype and not show :
show = ' online '
elif ptype == ' unavailable ' :
show = ' offline '
prio = prs . getPriority ( )
try :
prio = int ( prio )
2008-10-11 09:37:13 +00:00
except Exception :
2006-03-19 14:54:00 +00:00
prio = 0
keyID = ' '
2008-08-11 15:30:24 +00:00
if sigTag and self . USE_GPG and ptype != ' error ' :
# error presences contain our own signature
2007-12-12 08:44:46 +00:00
# verify
2006-03-19 14:54:00 +00:00
sigmsg = sigTag . getData ( )
keyID = self . gpg . verify ( status , sigmsg )
if is_gc :
if ptype == ' error ' :
2009-09-30 17:21:58 +02:00
errcon = prs . getError ( )
errmsg = prs . getErrorMsg ( )
2006-03-19 14:54:00 +00:00
errcode = prs . getErrorCode ( )
2007-08-09 15:39:18 +00:00
room_jid , nick = gajim . get_room_and_nick_from_fjid ( who )
2009-10-13 00:46:06 +03:00
gc_control = gajim . interface . msg_win_mgr . get_gc_control ( room_jid ,
self . name )
2009-10-13 17:38:42 +03:00
# If gc_control is missing - it may be minimized. Try to get it from
# there. If it's not there - then it's missing anyway and will
# remain set to None.
if gc_control is None :
minimized = gajim . interface . minimized_controls [ self . name ]
gc_control = minimized . get ( room_jid )
2009-10-13 00:46:06 +03:00
2009-09-30 17:21:58 +02:00
if errcode == ' 502 ' :
# Internal Timeout:
2006-03-19 14:54:00 +00:00
self . dispatch ( ' NOTIFY ' , ( jid_stripped , ' error ' , errmsg , resource ,
2007-06-03 10:04:20 +00:00
prio , keyID , timestamp , None ) )
2009-09-30 17:21:58 +02:00
elif ( errcode == ' 503 ' ) :
# maximum user number reached
self . dispatch ( ' ERROR ' , ( _ ( ' Unable to join group chat ' ) ,
_ ( ' Maximum number of users for %s has been reached ' ) % \
room_jid ) )
elif ( errcode == ' 401 ' ) or ( errcon == ' not-authorized ' ) :
# password required to join
2007-08-09 15:39:18 +00:00
self . dispatch ( ' GC_PASSWORD_REQUIRED ' , ( room_jid , nick ) )
2009-09-30 17:21:58 +02:00
elif ( errcode == ' 403 ' ) or ( errcon == ' forbidden ' ) :
# we are banned
2006-11-18 20:52:28 +00:00
self . dispatch ( ' ERROR ' , ( _ ( ' Unable to join group chat ' ) ,
2007-08-09 15:39:18 +00:00
_ ( ' You are banned from group chat %s . ' ) % room_jid ) )
2009-10-23 16:49:33 +02:00
elif ( errcode == ' 404 ' ) or ( errcon in ( ' item-not-found ' ,
' remote-server-not-found ' ) ) :
2009-10-13 00:46:06 +03:00
if gc_control is None or gc_control . autorejoin is None :
# group chat does not exist
self . dispatch ( ' ERROR ' , ( _ ( ' Unable to join group chat ' ) ,
_ ( ' Group chat %s does not exist. ' ) % room_jid ) )
2009-09-30 17:21:58 +02:00
elif ( errcode == ' 405 ' ) or ( errcon == ' not-allowed ' ) :
2006-11-18 20:52:28 +00:00
self . dispatch ( ' ERROR ' , ( _ ( ' Unable to join group chat ' ) ,
_ ( ' Group chat creation is restricted. ' ) ) )
2009-09-30 17:21:58 +02:00
elif ( errcode == ' 406 ' ) or ( errcon == ' not-acceptable ' ) :
2006-11-18 20:52:28 +00:00
self . dispatch ( ' ERROR ' , ( _ ( ' Unable to join group chat ' ) ,
2007-08-09 15:39:18 +00:00
_ ( ' Your registered nickname must be used in group chat %s . ' ) \
% room_jid ) )
2009-09-30 17:21:58 +02:00
elif ( errcode == ' 407 ' ) or ( errcon == ' registration-required ' ) :
2006-11-18 20:52:28 +00:00
self . dispatch ( ' ERROR ' , ( _ ( ' Unable to join group chat ' ) ,
2007-08-09 15:39:18 +00:00
_ ( ' You are not in the members list in groupchat %s . ' ) % \
room_jid ) )
2009-09-30 17:21:58 +02:00
elif ( errcode == ' 409 ' ) or ( errcon == ' conflict ' ) :
# nick conflict
2006-03-19 14:54:00 +00:00
room_jid = gajim . get_room_from_fjid ( who )
2008-08-29 08:06:28 +00:00
self . dispatch ( ' ASK_NEW_NICK ' , ( room_jid , ) )
2006-03-19 14:54:00 +00:00
else : # print in the window the error
self . dispatch ( ' ERROR_ANSWER ' , ( ' ' , jid_stripped ,
errmsg , errcode ) )
if not ptype or ptype == ' unavailable ' :
2008-08-30 01:31:25 +00:00
if gajim . config . get ( ' log_contact_status_changes ' ) and \
gajim . config . should_log ( self . name , jid_stripped ) :
2007-06-03 10:04:20 +00:00
gc_c = gajim . contacts . get_gc_contact ( self . name , jid_stripped ,
resource )
2006-09-13 16:47:58 +00:00
st = status or ' '
if gc_c :
jid = gc_c . jid
else :
jid = prs . getJid ( )
if jid :
# we know real jid, save it in db
st + = ' ( %s ) ' % jid
2007-08-09 15:39:18 +00:00
try :
gajim . logger . write ( ' gcstatus ' , who , st , show )
except exceptions . PysqliteOperationalError , e :
self . dispatch ( ' ERROR ' , ( _ ( ' Disk Write Error ' ) , str ( e ) ) )
2008-10-22 15:48:35 +00:00
except exceptions . DatabaseMalformed :
pritext = _ ( ' Database Error ' )
sectext = _ ( ' The database file ( %s ) cannot be read. Try to '
2008-10-22 17:31:45 +00:00
' repair it (see http://trac.gajim.org/wiki/DatabaseBackup) '
' or remove it (all history will be lost). ' ) % \
2008-10-22 15:48:35 +00:00
common . logger . LOG_DB_PATH
self . dispatch ( ' ERROR ' , ( pritext , sectext ) )
2006-11-28 16:41:31 +00:00
if avatar_sha or avatar_sha == ' ' :
if avatar_sha == ' ' :
# contact has no avatar
puny_nick = helpers . sanitize_filename ( resource )
gajim . interface . remove_avatar_files ( jid_stripped , puny_nick )
2007-06-03 10:04:20 +00:00
# if it's a gc presence, don't ask vcard here. We may ask it to
# real jid in gui part.
2007-03-11 20:14:53 +00:00
if ns_muc_user_x :
# Room has been destroyed. see
# http://www.xmpp.org/extensions/xep-0045.html#destroyroom
reason = _ ( ' Room has been destroyed ' )
destroy = ns_muc_user_x . getTag ( ' destroy ' )
r = destroy . getTagData ( ' reason ' )
if r :
reason + = ' ( %s ) ' % r
2009-08-01 18:28:25 +02:00
if destroy . getAttr ( ' jid ' ) :
try :
jid = helpers . parse_jid ( destroy . getAttr ( ' jid ' ) )
reason + = ' \n ' + _ ( ' You can join this room instead: %s ' ) \
% jid
except common . helpers . InvalidFormat :
pass
2007-08-09 15:39:18 +00:00
statusCode = [ ' destroyed ' ]
2007-03-11 20:14:53 +00:00
else :
reason = prs . getReason ( )
statusCode = prs . getStatusCode ( )
2006-03-19 14:54:00 +00:00
self . dispatch ( ' GC_NOTIFY ' , ( jid_stripped , show , status , resource ,
prs . getRole ( ) , prs . getAffiliation ( ) , prs . getJid ( ) ,
2007-06-03 10:04:20 +00:00
reason , prs . getActor ( ) , statusCode , prs . getNewNick ( ) ,
avatar_sha ) )
2006-03-19 14:54:00 +00:00
return
if ptype == ' subscribe ' :
2008-12-24 12:11:02 +00:00
log . debug ( ' subscribe request from %s ' % who )
2009-09-15 22:26:42 +02:00
if gajim . config . get_per ( ' accounts ' , self . name , ' autoauth ' ) or \
who . find ( ' @ ' ) < = 0 or jid_stripped in self . jids_for_auto_auth or \
transport_auto_auth :
2006-03-19 14:54:00 +00:00
if self . connection :
p = common . xmpp . Presence ( who , ' subscribed ' )
p = self . add_sha ( p )
self . connection . send ( p )
2009-09-15 22:26:42 +02:00
if who . find ( ' @ ' ) < = 0 or transport_auto_auth :
2006-04-01 18:16:06 +00:00
self . dispatch ( ' NOTIFY ' , ( jid_stripped , ' offline ' , ' offline ' ,
2007-06-03 10:04:20 +00:00
resource , prio , keyID , timestamp , None ) )
2006-04-19 10:06:59 +00:00
if transport_auto_auth :
self . automatically_added . append ( jid_stripped )
2006-06-01 15:23:38 +00:00
self . request_subscription ( jid_stripped , name = user_nick )
2006-03-19 14:54:00 +00:00
else :
if not status :
status = _ ( ' I would like to add you to my roster. ' )
2007-12-12 08:44:46 +00:00
self . dispatch ( ' SUBSCRIBE ' , ( jid_stripped , status , user_nick ) )
2006-04-19 10:06:59 +00:00
elif ptype == ' subscribed ' :
if jid_stripped in self . automatically_added :
self . automatically_added . remove ( jid_stripped )
2006-04-18 14:30:00 +00:00
else :
2006-09-13 16:47:58 +00:00
# detect a subscription loop
2008-10-07 20:41:59 +00:00
if jid_stripped not in self . subscribed_events :
2006-09-13 16:47:58 +00:00
self . subscribed_events [ jid_stripped ] = [ ]
2007-08-09 15:39:18 +00:00
self . subscribed_events [ jid_stripped ] . append ( time_time ( ) )
2006-09-13 16:47:58 +00:00
block = False
if len ( self . subscribed_events [ jid_stripped ] ) > 5 :
2007-08-09 15:39:18 +00:00
if time_time ( ) - self . subscribed_events [ jid_stripped ] [ 0 ] < 5 :
2006-09-13 16:47:58 +00:00
block = True
self . subscribed_events [ jid_stripped ] = self . subscribed_events [ jid_stripped ] [ 1 : ]
if block :
gajim . config . set_per ( ' account ' , self . name ,
' dont_ack_subscription ' , True )
else :
self . dispatch ( ' SUBSCRIBED ' , ( jid_stripped , resource ) )
2006-03-19 14:54:00 +00:00
# BE CAREFUL: no con.updateRosterItem() in a callback
2008-12-24 12:11:02 +00:00
log . debug ( _ ( ' we are now subscribed to %s ' ) % who )
2006-03-19 14:54:00 +00:00
elif ptype == ' unsubscribe ' :
2008-12-24 12:11:02 +00:00
log . debug ( _ ( ' unsubscribe request from %s ' ) % who )
2006-03-19 14:54:00 +00:00
elif ptype == ' unsubscribed ' :
2008-12-24 12:11:02 +00:00
log . debug ( _ ( ' we are now unsubscribed from %s ' ) % who )
2006-09-13 16:47:58 +00:00
# detect a unsubscription loop
2008-10-07 20:41:59 +00:00
if jid_stripped not in self . subscribed_events :
2006-09-13 16:47:58 +00:00
self . subscribed_events [ jid_stripped ] = [ ]
2007-08-09 15:39:18 +00:00
self . subscribed_events [ jid_stripped ] . append ( time_time ( ) )
2006-09-13 16:47:58 +00:00
block = False
if len ( self . subscribed_events [ jid_stripped ] ) > 5 :
2007-08-09 15:39:18 +00:00
if time_time ( ) - self . subscribed_events [ jid_stripped ] [ 0 ] < 5 :
2006-09-13 16:47:58 +00:00
block = True
self . subscribed_events [ jid_stripped ] = self . subscribed_events [ jid_stripped ] [ 1 : ]
if block :
gajim . config . set_per ( ' account ' , self . name , ' dont_ack_subscription ' ,
True )
else :
self . dispatch ( ' UNSUBSCRIBED ' , jid_stripped )
2006-03-19 14:54:00 +00:00
elif ptype == ' error ' :
errmsg = prs . getError ( )
errcode = prs . getErrorCode ( )
2008-08-03 19:11:03 +00:00
if errcode != ' 502 ' : # Internal Timeout:
# print in the window the error
2006-03-19 14:54:00 +00:00
self . dispatch ( ' ERROR_ANSWER ' , ( ' ' , jid_stripped ,
errmsg , errcode ) )
2009-07-16 14:53:14 +02:00
if errcode != ' 409 ' : # conflict # See #5120
self . dispatch ( ' NOTIFY ' , ( jid_stripped , ' error ' , errmsg , resource ,
prio , keyID , timestamp , None ) )
2006-03-19 14:54:00 +00:00
2009-10-06 17:35:25 +02:00
if ptype == ' unavailable ' :
for jid in [ jid_stripped , who ] :
if jid not in self . sessions :
continue
# automatically terminate sessions that they haven't sent a thread
# ID in, only if other part support thread ID
for sess in self . sessions [ jid ] . values ( ) :
if not sess . received_thread_id :
contact = gajim . contacts . get_contact ( self . name , jid )
2009-11-09 22:03:14 +01:00
# FIXME: I don't know if this is the correct behavior here.
# Anyway, it is the old behavior when we assumed that
# not-existing contacts don't support anything
contact_exists = bool ( contact )
session_supported = contact_exists and \
contact . supports ( common . xmpp . NS_SSN ) or \
2009-10-27 22:41:39 +01:00
contact . supports ( common . xmpp . NS_ESESSION )
2009-10-06 17:35:25 +02:00
if session_supported :
sess . terminate ( )
del self . sessions [ jid ] [ sess . thread_id ]
2008-06-10 02:58:17 +00:00
2008-10-01 16:07:58 +00:00
if avatar_sha is not None and ptype != ' error ' :
2008-10-07 20:41:59 +00:00
if jid_stripped not in self . vcard_shas :
2006-04-19 15:16:51 +00:00
cached_vcard = self . get_cached_vcard ( jid_stripped )
2008-10-07 20:41:59 +00:00
if cached_vcard and ' PHOTO ' in cached_vcard and \
' SHA ' in cached_vcard [ ' PHOTO ' ] :
2006-04-19 15:16:51 +00:00
self . vcard_shas [ jid_stripped ] = cached_vcard [ ' PHOTO ' ] [ ' SHA ' ]
else :
self . vcard_shas [ jid_stripped ] = ' '
if avatar_sha != self . vcard_shas [ jid_stripped ] :
# avatar has been updated
self . request_vcard ( jid_stripped )
2006-03-19 14:54:00 +00:00
if not ptype or ptype == ' unavailable ' :
2008-08-30 01:31:25 +00:00
if gajim . config . get ( ' log_contact_status_changes ' ) and \
gajim . config . should_log ( self . name , jid_stripped ) :
2007-08-09 15:39:18 +00:00
try :
gajim . logger . write ( ' status ' , jid_stripped , status , show )
except exceptions . PysqliteOperationalError , e :
self . dispatch ( ' ERROR ' , ( _ ( ' Disk Write Error ' ) , str ( e ) ) )
2008-10-22 15:48:35 +00:00
except exceptions . DatabaseMalformed :
pritext = _ ( ' Database Error ' )
sectext = _ ( ' The database file ( %s ) cannot be read. Try to '
2008-10-22 17:31:45 +00:00
' repair it (see http://trac.gajim.org/wiki/DatabaseBackup) '
' or remove it (all history will be lost). ' ) % \
2008-10-22 15:48:35 +00:00
common . logger . LOG_DB_PATH
self . dispatch ( ' ERROR ' , ( pritext , sectext ) )
2007-12-12 08:44:46 +00:00
our_jid = gajim . get_jid_from_account ( self . name )
if jid_stripped == our_jid and resource == self . server_resource :
# We got our own presence
self . dispatch ( ' STATUS ' , show )
else :
self . dispatch ( ' NOTIFY ' , ( jid_stripped , show , status , resource , prio ,
keyID , timestamp , contact_nickname ) )
2006-03-19 14:54:00 +00:00
# END presenceCB
2007-02-15 09:18:24 +00:00
2006-03-19 14:54:00 +00:00
def _StanzaArrivedCB ( self , con , obj ) :
self . last_io = gajim . idlequeue . current_time ( )
def _MucOwnerCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' MucOwnerCB ' )
2006-03-19 14:54:00 +00:00
qp = iq_obj . getQueryPayload ( )
node = None
for q in qp :
if q . getNamespace ( ) == common . xmpp . NS_DATA :
node = q
if not node :
return
2007-02-14 16:48:25 +00:00
self . dispatch ( ' GC_CONFIG ' , ( helpers . get_full_jid_from_iq ( iq_obj ) , node ) )
2006-03-19 14:54:00 +00:00
def _MucAdminCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' MucAdminCB ' )
2009-08-31 23:04:54 +02:00
items = iq_obj . getTag ( ' query ' , namespace = common . xmpp . NS_MUC_ADMIN ) . \
getTags ( ' item ' )
2008-05-05 03:18:09 +00:00
users_dict = { }
2006-03-19 14:54:00 +00:00
for item in items :
if item . has_attr ( ' jid ' ) and item . has_attr ( ' affiliation ' ) :
2009-07-08 21:41:40 +02:00
try :
jid = helpers . parse_jid ( item . getAttr ( ' jid ' ) )
except common . helpers . InvalidFormat :
log . warn ( ' Invalid JID: %s , ignoring it ' % item . getAttr ( ' jid ' ) )
2009-08-31 23:04:54 +02:00
continue
2006-03-19 14:54:00 +00:00
affiliation = item . getAttr ( ' affiliation ' )
2008-05-05 03:18:09 +00:00
users_dict [ jid ] = { ' affiliation ' : affiliation }
2006-03-19 14:54:00 +00:00
if item . has_attr ( ' nick ' ) :
2008-05-05 03:18:09 +00:00
users_dict [ jid ] [ ' nick ' ] = item . getAttr ( ' nick ' )
2006-03-19 14:54:00 +00:00
if item . has_attr ( ' role ' ) :
2008-05-05 03:18:09 +00:00
users_dict [ jid ] [ ' role ' ] = item . getAttr ( ' role ' )
2006-03-19 14:54:00 +00:00
reason = item . getTagData ( ' reason ' )
if reason :
2008-05-05 03:18:09 +00:00
users_dict [ jid ] [ ' reason ' ] = reason
2006-03-19 14:54:00 +00:00
2008-12-03 21:56:12 +00:00
self . dispatch ( ' GC_AFFILIATION ' , ( helpers . get_full_jid_from_iq ( iq_obj ) ,
2009-08-31 23:04:54 +02:00
users_dict ) )
2006-03-19 14:54:00 +00:00
def _MucErrorCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' MucErrorCB ' )
2006-03-19 14:54:00 +00:00
jid = helpers . get_full_jid_from_iq ( iq_obj )
errmsg = iq_obj . getError ( )
errcode = iq_obj . getErrorCode ( )
self . dispatch ( ' MSGERROR ' , ( jid , errcode , errmsg ) )
2007-01-27 10:19:53 +00:00
def _IqPingCB ( self , con , iq_obj ) :
2008-12-24 12:11:02 +00:00
log . debug ( ' IqPingCB ' )
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
return
2007-01-27 10:19:53 +00:00
iq_obj = iq_obj . buildReply ( ' result ' )
self . connection . send ( iq_obj )
raise common . xmpp . NodeProcessed
2008-06-25 07:35:35 +00:00
def _PrivacySetCB ( self , con , iq_obj ) :
'''
Privacy lists ( XEP 016 )
A list has been set
'''
2008-12-24 12:11:02 +00:00
log . debug ( ' PrivacySetCB ' )
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
return
2008-06-25 07:35:35 +00:00
result = iq_obj . buildReply ( ' result ' )
q = result . getTag ( ' query ' )
if q :
result . delChild ( q )
self . connection . send ( result )
raise common . xmpp . NodeProcessed
2009-06-27 17:56:04 +02:00
def _getRoster ( self ) :
2009-02-19 09:52:23 +00:00
log . debug ( ' getRosterCB ' )
2006-03-19 14:54:00 +00:00
if not self . connection :
return
self . connection . getRoster ( self . _on_roster_set )
2008-12-03 21:56:12 +00:00
self . discoverItems ( gajim . config . get_per ( ' accounts ' , self . name ,
2009-02-07 12:47:13 +00:00
' hostname ' ) , id_prefix = ' Gajim_ ' )
2006-03-27 08:28:05 +00:00
if gajim . config . get_per ( ' accounts ' , self . name , ' use_ft_proxies ' ) :
self . discover_ft_proxies ( )
2008-12-03 21:56:12 +00:00
2006-03-27 08:28:05 +00:00
def discover_ft_proxies ( self ) :
2006-03-19 20:43:30 +00:00
cfg_proxies = gajim . config . get_per ( ' accounts ' , self . name ,
2006-03-27 08:28:05 +00:00
' file_transfer_proxies ' )
2008-08-27 13:11:46 +00:00
our_jid = helpers . parse_jid ( gajim . get_jid_from_account ( self . name ) + ' / ' + \
self . server_resource )
2006-03-19 20:43:30 +00:00
if cfg_proxies :
2008-12-03 22:07:44 +00:00
proxies = [ e . strip ( ) for e in cfg_proxies . split ( ' , ' ) ]
2006-03-19 20:43:30 +00:00
for proxy in proxies :
2008-08-27 13:11:46 +00:00
gajim . proxy65_manager . resolve ( proxy , self . connection , our_jid )
2008-12-03 21:56:12 +00:00
2006-03-19 14:54:00 +00:00
def _on_roster_set ( self , roster ) :
2009-06-27 17:56:04 +02:00
roster_version = roster . version
2009-06-30 11:46:27 +02:00
received_from_server = roster . received_from_server
2006-03-19 14:54:00 +00:00
raw_roster = roster . getRaw ( )
roster = { }
2006-04-10 08:24:55 +00:00
our_jid = helpers . parse_jid ( gajim . get_jid_from_account ( self . name ) )
2007-12-27 17:06:30 +00:00
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 )
2006-03-19 14:54:00 +00:00
for jid in raw_roster :
try :
j = helpers . parse_jid ( jid )
2008-12-03 21:37:05 +00:00
except Exception :
2006-03-19 14:54:00 +00:00
print >> sys . stderr , _ ( ' JID %s is not RFC compliant. It will not be added to your roster. Use roster management tools such as http://jru.jabberstudio.org/ to remove it ' ) % jid
else :
2006-04-10 08:24:55 +00:00
infos = raw_roster [ jid ]
2006-09-13 16:47:58 +00:00
if jid != our_jid and ( not infos [ ' subscription ' ] or \
infos [ ' subscription ' ] == ' none ' ) and ( not infos [ ' ask ' ] or \
infos [ ' ask ' ] == ' none ' ) and not infos [ ' name ' ] and \
not infos [ ' groups ' ] :
2006-04-10 08:24:55 +00:00
# remove this useless item, it won't be shown in roster anyway
self . connection . getRoster ( ) . delItem ( jid )
elif jid != our_jid : # don't add our jid
roster [ j ] = raw_roster [ jid ]
2006-09-13 16:47:58 +00:00
if gajim . jid_is_transport ( jid ) and \
not gajim . get_transport_name_from_jid ( jid ) :
# we can't determine which iconset to use
self . discoverInfo ( jid )
2006-03-19 14:54:00 +00:00
2009-06-30 11:46:27 +02:00
gajim . logger . replace_roster ( self . name , roster_version , roster )
if received_from_server :
2009-06-30 17:06:17 +02:00
for contact in gajim . contacts . iter_contacts ( self . name ) :
2009-10-16 19:51:29 +02:00
if not contact . is_groupchat ( ) and contact . jid not in roster and \
contact . jid != gajim . get_jid_from_account ( self . name ) :
2009-07-20 20:09:39 +02:00
self . dispatch ( ' ROSTER_INFO ' , ( contact . jid , None , None , None ,
( ) ) )
2009-06-30 17:06:17 +02:00
for jid in roster :
self . dispatch ( ' ROSTER_INFO ' , ( jid , roster [ jid ] [ ' name ' ] ,
roster [ jid ] [ ' subscription ' ] , roster [ jid ] [ ' ask ' ] ,
roster [ jid ] [ ' groups ' ] ) )
2006-03-19 14:54:00 +00:00
2007-12-12 08:44:46 +00:00
def _send_first_presence ( self , signed = ' ' ) :
show = self . continue_connect_info [ 0 ]
msg = self . continue_connect_info [ 1 ]
sign_msg = self . continue_connect_info [ 2 ]
if sign_msg and not signed :
signed = self . get_signed_presence ( msg )
if signed is None :
2009-09-10 18:30:26 +02:00
self . dispatch ( ' BAD_PASSPHRASE ' , ( ) )
2007-12-29 23:28:27 +00:00
self . USE_GPG = False
2007-12-12 08:44:46 +00:00
signed = ' '
2009-01-10 16:45:52 +00:00
self . connected = gajim . SHOW_LIST . index ( show )
2007-12-12 08:44:46 +00:00
sshow = helpers . get_xmpp_show ( show )
# send our presence
if show == ' invisible ' :
self . send_invisible_presence ( msg , signed , True )
return
priority = gajim . get_priority ( self . name , sshow )
our_jid = helpers . parse_jid ( gajim . get_jid_from_account ( self . name ) )
vcard = self . get_cached_vcard ( our_jid )
2008-10-07 20:41:59 +00:00
if vcard and ' PHOTO ' in vcard and ' SHA ' in vcard [ ' PHOTO ' ] :
2007-12-12 08:44:46 +00:00
self . vcard_sha = vcard [ ' PHOTO ' ] [ ' SHA ' ]
p = common . xmpp . Presence ( typ = None , priority = priority , show = sshow )
p = self . add_sha ( p )
if msg :
p . setStatus ( msg )
if signed :
p . setTag ( common . xmpp . NS_SIGNED + ' x ' ) . setData ( signed )
if self . connection :
self . connection . send ( p )
self . priority = priority
self . dispatch ( ' STATUS ' , show )
2009-08-28 13:41:36 +02:00
if self . vcard_supported :
# ask our VCard
self . request_vcard ( None )
2007-12-12 08:44:46 +00:00
# Get bookmarks from private namespace
self . get_bookmarks ( )
# Get annotations from private namespace
self . get_annotations ( )
# Inform GUI we just signed in
self . dispatch ( ' SIGNED_IN ' , ( ) )
2006-03-19 14:54:00 +00:00
self . continue_connect_info = None
2008-12-03 21:56:12 +00:00
2007-08-09 15:39:18 +00:00
def request_gmail_notifications ( self ) :
2008-08-30 17:14:27 +00:00
if not self . connection or self . connected < 2 :
return
2007-08-09 15:39:18 +00:00
# It's a gmail account,
# inform the server that we want e-mail notifications
our_jid = helpers . parse_jid ( gajim . get_jid_from_account ( self . name ) )
2008-12-24 12:11:02 +00:00
log . debug ( ( ' %s is a gmail account. Setting option '
2007-08-09 15:39:18 +00:00
' to get e-mail notifications on the server. ' ) % ( our_jid ) )
iq = common . xmpp . Iq ( typ = ' set ' , to = our_jid )
iq . setAttr ( ' id ' , ' MailNotify ' )
query = iq . setTag ( ' usersetting ' )
query . setNamespace ( common . xmpp . NS_GTALKSETTING )
query = query . setTag ( ' mailnotifications ' )
query . setAttr ( ' value ' , ' true ' )
self . connection . send ( iq )
# Ask how many messages there are now
iq = common . xmpp . Iq ( typ = ' get ' )
iq . setID ( self . connection . getAnID ( ) )
query = iq . setTag ( ' query ' )
query . setNamespace ( common . xmpp . NS_GMAILNOTIFY )
self . connection . send ( iq )
2008-12-03 21:56:12 +00:00
2007-06-03 10:04:20 +00:00
def _search_fields_received ( self , con , iq_obj ) :
jid = jid = helpers . get_jid_from_iq ( iq_obj )
tag = iq_obj . getTag ( ' query ' , namespace = common . xmpp . NS_SEARCH )
if not tag :
self . dispatch ( ' SEARCH_FORM ' , ( jid , None , False ) )
return
df = tag . getTag ( ' x ' , namespace = common . xmpp . NS_DATA )
if df :
self . dispatch ( ' SEARCH_FORM ' , ( jid , df , True ) )
return
df = { }
for i in iq_obj . getQueryPayload ( ) :
df [ i . getName ( ) ] = i . getData ( )
self . dispatch ( ' SEARCH_FORM ' , ( jid , df , False ) )
def _StreamCB ( self , con , obj ) :
if obj . getTag ( ' conflict ' ) :
# disconnected because of a resource conflict
self . dispatch ( ' RESOURCE_CONFLICT ' , ( ) )
2006-03-19 14:54:00 +00:00
def _register_handlers ( self , con , con_type ) :
2008-05-13 01:59:10 +00:00
# try to find another way to register handlers in each class
2006-03-19 14:54:00 +00:00
# that defines handlers
con . RegisterHandler ( ' message ' , self . _messageCB )
con . RegisterHandler ( ' presence ' , self . _presenceCB )
2007-08-09 15:39:18 +00:00
con . RegisterHandler ( ' presence ' , self . _capsPresenceCB )
2009-11-14 19:56:15 +01:00
con . RegisterHandler ( ' message ' , self . _pubsubEventCB ,
ns = common . xmpp . NS_PUBSUB_EVENT )
2006-03-19 14:54:00 +00:00
con . RegisterHandler ( ' iq ' , self . _vCardCB , ' result ' ,
common . xmpp . NS_VCARD )
con . RegisterHandler ( ' iq ' , self . _rosterSetCB , ' set ' ,
common . xmpp . NS_ROSTER )
con . RegisterHandler ( ' iq ' , self . _siSetCB , ' set ' ,
common . xmpp . NS_SI )
2009-06-21 03:43:57 +02:00
con . RegisterHandler ( ' iq ' , self . _rosterItemExchangeCB , ' set ' ,
common . xmpp . NS_ROSTERX )
2006-03-19 14:54:00 +00:00
con . RegisterHandler ( ' iq ' , self . _siErrorCB , ' error ' ,
common . xmpp . NS_SI )
con . RegisterHandler ( ' iq ' , self . _siResultCB , ' result ' ,
common . xmpp . NS_SI )
con . RegisterHandler ( ' iq ' , self . _discoGetCB , ' get ' ,
common . xmpp . NS_DISCO )
con . RegisterHandler ( ' iq ' , self . _bytestreamSetCB , ' set ' ,
common . xmpp . NS_BYTESTREAM )
con . RegisterHandler ( ' iq ' , self . _bytestreamResultCB , ' result ' ,
common . xmpp . NS_BYTESTREAM )
con . RegisterHandler ( ' iq ' , self . _bytestreamErrorCB , ' error ' ,
common . xmpp . NS_BYTESTREAM )
con . RegisterHandler ( ' iq ' , self . _DiscoverItemsCB , ' result ' ,
common . xmpp . NS_DISCO_ITEMS )
con . RegisterHandler ( ' iq ' , self . _DiscoverItemsErrorCB , ' error ' ,
common . xmpp . NS_DISCO_ITEMS )
con . RegisterHandler ( ' iq ' , self . _DiscoverInfoCB , ' result ' ,
common . xmpp . NS_DISCO_INFO )
con . RegisterHandler ( ' iq ' , self . _DiscoverInfoErrorCB , ' error ' ,
common . xmpp . NS_DISCO_INFO )
con . RegisterHandler ( ' iq ' , self . _VersionCB , ' get ' ,
common . xmpp . NS_VERSION )
2006-09-13 16:47:58 +00:00
con . RegisterHandler ( ' iq ' , self . _TimeCB , ' get ' ,
common . xmpp . NS_TIME )
2006-12-28 16:27:41 +00:00
con . RegisterHandler ( ' iq ' , self . _TimeRevisedCB , ' get ' ,
common . xmpp . NS_TIME_REVISED )
2006-03-19 14:54:00 +00:00
con . RegisterHandler ( ' iq ' , self . _LastCB , ' get ' ,
common . xmpp . NS_LAST )
con . RegisterHandler ( ' iq ' , self . _LastResultCB , ' result ' ,
common . xmpp . NS_LAST )
con . RegisterHandler ( ' iq ' , self . _VersionResultCB , ' result ' ,
common . xmpp . NS_VERSION )
2009-02-10 21:45:44 +00:00
con . RegisterHandler ( ' iq ' , self . _TimeRevisedResultCB , ' result ' ,
common . xmpp . NS_TIME_REVISED )
2006-03-19 14:54:00 +00:00
con . RegisterHandler ( ' iq ' , self . _MucOwnerCB , ' result ' ,
common . xmpp . NS_MUC_OWNER )
con . RegisterHandler ( ' iq ' , self . _MucAdminCB , ' result ' ,
common . xmpp . NS_MUC_ADMIN )
con . RegisterHandler ( ' iq ' , self . _PrivateCB , ' result ' ,
common . xmpp . NS_PRIVATE )
con . RegisterHandler ( ' iq ' , self . _HttpAuthCB , ' get ' ,
common . xmpp . NS_HTTP_AUTH )
2006-07-15 13:27:57 +00:00
con . RegisterHandler ( ' iq ' , self . _CommandExecuteCB , ' set ' ,
common . xmpp . NS_COMMANDS )
2006-03-19 14:54:00 +00:00
con . RegisterHandler ( ' iq ' , self . _gMailNewMailCB , ' set ' ,
common . xmpp . NS_GMAILNOTIFY )
con . RegisterHandler ( ' iq ' , self . _gMailQueryCB , ' result ' ,
common . xmpp . NS_GMAILNOTIFY )
con . RegisterHandler ( ' iq ' , self . _DiscoverInfoGetCB , ' get ' ,
common . xmpp . NS_DISCO_INFO )
2006-07-15 13:27:57 +00:00
con . RegisterHandler ( ' iq ' , self . _DiscoverItemsGetCB , ' get ' ,
common . xmpp . NS_DISCO_ITEMS )
2007-01-27 10:19:53 +00:00
con . RegisterHandler ( ' iq ' , self . _IqPingCB , ' get ' ,
common . xmpp . NS_PING )
2007-06-03 10:04:20 +00:00
con . RegisterHandler ( ' iq ' , self . _search_fields_received , ' result ' ,
common . xmpp . NS_SEARCH )
2008-06-25 07:35:35 +00:00
con . RegisterHandler ( ' iq ' , self . _PrivacySetCB , ' set ' ,
common . xmpp . NS_PRIVACY )
2006-08-20 10:18:20 +00:00
con . RegisterHandler ( ' iq ' , self . _PubSubCB , ' result ' )
2009-08-04 00:36:28 +02:00
con . RegisterHandler ( ' iq ' , self . _PubSubErrorCB , ' error ' )
2007-08-06 23:19:57 +00:00
con . RegisterHandler ( ' iq ' , self . _JingleCB , ' result ' )
con . RegisterHandler ( ' iq ' , self . _JingleCB , ' error ' )
con . RegisterHandler ( ' iq ' , self . _JingleCB , ' set ' ,
common . xmpp . NS_JINGLE )
2006-03-19 14:54:00 +00:00
con . RegisterHandler ( ' iq ' , self . _ErrorCB , ' error ' )
con . RegisterHandler ( ' iq ' , self . _IqCB )
con . RegisterHandler ( ' iq ' , self . _StanzaArrivedCB )
2006-04-11 22:23:51 +00:00
con . RegisterHandler ( ' iq ' , self . _ResultCB , ' result ' )
2006-03-19 14:54:00 +00:00
con . RegisterHandler ( ' presence ' , self . _StanzaArrivedCB )
2006-03-19 14:59:17 +00:00
con . RegisterHandler ( ' message ' , self . _StanzaArrivedCB )
2007-06-03 10:04:20 +00:00
con . RegisterHandler ( ' unknown ' , self . _StreamCB , ' urn:ietf:params:xml:ns:xmpp-streams ' , xmlns = ' http://etherx.jabber.org/streams ' )
2008-07-29 19:49:31 +00:00
2008-08-01 10:27:38 +00:00
# vim: se ts=3: