Changeset 9123 for branches/pep/src/common/connection_handlers.py
- Timestamp:
- 12/12/07 09:44:46 (12 months ago)
- Files:
-
- 1 modified
-
branches/pep/src/common/connection_handlers.py (modified) (43 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/pep/src/common/connection_handlers.py
r8487 r9123 3 3 ## 4 4 ## Contributors for this file: 5 ## - Yann Le Boulanger <asterix@lagaule.org>5 ## - Yann Leboulanger <asterix@lagaule.org> 6 6 ## - Nikos Kouremenos <kourem@gmail.com> 7 7 ## - Dimitur Kirov <dkirov@gmail.com> 8 8 ## - Travis Shirk <travis@pobox.com> 9 9 ## 10 ## This program is free software; you can redistribute it and/or modify 10 ## This file is part of Gajim. 11 ## 12 ## Gajim is free software; you can redistribute it and/or modify 11 13 ## it under the terms of the GNU General Public License as published 12 ## by the Free Software Foundation; version 2only.14 ## by the Free Software Foundation; version 3 only. 13 15 ## 14 ## This program is distributed in the hope that it will be useful,16 ## Gajim is distributed in the hope that it will be useful, 15 17 ## but WITHOUT ANY WARRANTY; without even the implied warranty of 16 18 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 19 ## GNU General Public License for more details. 20 ## 21 ## You should have received a copy of the GNU General Public License 22 ## along with Gajim. If not, see <http://www.gnu.org/licenses/>. 18 23 ## 19 24 … … 25 30 26 31 from time import (altzone, daylight, gmtime, localtime, mktime, strftime, 27 time as time_time, timezone, tzname)32 time as time_time, timezone, tzname) 28 33 from calendar import timegm 29 34 … … 45 50 import dbus 46 51 from music_track_listener import MusicTrackListener 52 53 from common.stanza_session import EncryptedStanzaSession 47 54 48 55 STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd', … … 65 72 def __init__(self): 66 73 self.files_props = {} 67 68 def is_transfer_stop ed(self, file_props):74 75 def is_transfer_stopped(self, file_props): 69 76 if file_props.has_key('error') and file_props['error'] != 0: 70 77 return True … … 95 102 ''' stop all active transfer for contact ''' 96 103 for file_props in self.files_props.values(): 97 if self.is_transfer_stop ed(file_props):104 if self.is_transfer_stopped(file_props): 98 105 continue 99 106 receiver_jid = unicode(file_props['receiver']).split('/')[0] … … 183 190 ft_add_hosts_to_send.split(',')) 184 191 for ft_host in ft_add_hosts_to_send: 185 try: 186 ft_host = socket.gethostbyname(ft_host) 187 ft_add_hosts.append(ft_host) 188 except socket.gaierror: 189 self.dispatch('ERROR', (_('Wrong host'), _('The host %s you configured as the ft_add_hosts_to_send advanced option is not valid, so ignored.') % ft_host)) 192 ft_add_hosts.append(ft_host) 190 193 listener = gajim.socks5queue.start_listener(port, 191 194 sha_str, self._result_socks5_sid, file_props['sid']) … … 213 216 ostreamhost.setAttr('host', ft_host) 214 217 ostreamhost.setAttr('jid', sender) 215 for thehost in self.peerhost: 216 try: 217 thehost = self.peerhost[0] 218 streamhost = common.xmpp.Node(tag = 'streamhost') # My IP 219 query.addChild(node = streamhost) 220 streamhost.setAttr('port', unicode(port)) 221 streamhost.setAttr('host', thehost) 222 streamhost.setAttr('jid', sender) 223 except socket.gaierror: 224 self.dispatch('ERROR', (_('Wrong host'), 225 _('Invalid local address? :-O'))) 218 try: 219 thehost = self.peerhost[0] 220 streamhost = common.xmpp.Node(tag = 'streamhost') # My IP 221 query.addChild(node = streamhost) 222 streamhost.setAttr('port', unicode(port)) 223 streamhost.setAttr('host', thehost) 224 streamhost.setAttr('jid', sender) 225 except socket.gaierror: 226 self.dispatch('ERROR', (_('Wrong host'), 227 _('Invalid local address? :-O'))) 226 228 227 229 if fast and proxyhosts != [] and gajim.config.get_per('accounts', … … 354 356 query = iq.setTag('query') 355 357 query.setNamespace(common.xmpp.NS_BYTESTREAM) 356 query.setAttr('sid', proxy['sid'])358 query.setAttr('sid', proxy['sid']) 357 359 activate = query.setTag('activate') 358 360 activate.setData(file_props['proxy_receiver']) … … 445 447 446 448 try: 447 streamhost = query.getTag('streamhost-used')449 streamhost = query.getTag('streamhost-used') 448 450 except: # this bytestream result is not what we need 449 451 pass … … 474 476 475 477 if real_id[:3] == 'au_': 476 gajim.socks5queue.send_file(file_props, self.name) 478 if file.has_key('stopped') and file_props['stopped']: 479 self.remove_transfer(file_props) 480 else: 481 gajim.socks5queue.send_file(file_props, self.name) 477 482 raise common.xmpp.NodeProcessed 478 483 … … 496 501 497 502 else: 498 gajim.socks5queue.send_file(file_props, self.name) 503 if file_props.has_key('stopped') and file_props['stopped']: 504 self.remove_transfer(file_props) 505 else: 506 gajim.socks5queue.send_file(file_props, self.name) 499 507 if file_props.has_key('fast'): 500 508 fasts = file_props['fast'] … … 658 666 iq.setAttr('id', id) 659 667 query = iq.setTag('query') 660 query.setAttr('node','http://gajim.org/caps#' + gajim.version) 668 query.setAttr('node','http://gajim.org/caps#' + gajim.version.split('-', 669 1)[0]) 661 670 for f in (common.xmpp.NS_BYTESTREAM, common.xmpp.NS_SI, \ 662 671 common.xmpp.NS_FILE, common.xmpp.NS_COMMANDS): … … 710 719 def _DiscoverItemsGetCB(self, con, iq_obj): 711 720 gajim.log.debug('DiscoverItemsGetCB') 721 if self.commandItemsQuery(con, iq_obj): 722 raise common.xmpp.NodeProcessed 712 723 node = iq_obj.getTagAttr('query', 'node') 713 if node is None:724 if node is None: 714 725 result = iq_obj.buildReply('result') 715 726 self.connection.send(result) … … 724 735 node = q.getAttr('node') 725 736 726 if self.command Query(con, iq_obj):737 if self.commandInfoQuery(con, iq_obj): 727 738 raise common.xmpp.NodeProcessed 728 739 … … 737 748 if node and node.find('#') != -1: 738 749 extension = node[node.index('#') + 1:] 739 client_version = 'http://gajim.org/caps#' + gajim.version 750 client_version = 'http://gajim.org/caps#' + gajim.version.split('-', 751 1)[0] 740 752 741 753 if node in (None, client_version): … … 746 758 q.addChild('feature', attrs = {'var': common.xmpp.NS_COMMANDS}) 747 759 q.addChild('feature', attrs = {'var': common.xmpp.NS_DISCO_INFO}) 748 q.addChild('feature', attrs = {'var': common.xmpp.NS_ACTIVITY}) 749 q.addChild('feature', attrs = {'var': common.xmpp.NS_ACTIVITY + '+notify'}) 750 q.addChild('feature', attrs = {'var': common.xmpp.NS_TUNE}) 751 q.addChild('feature', attrs = {'var': common.xmpp.NS_TUNE + '+notify'}) 752 q.addChild('feature', attrs = {'var': common.xmpp.NS_MOOD}) 753 q.addChild('feature', attrs = {'var': common.xmpp.NS_MOOD + '+notify'}) 760 if gajim.config.get('use_pep'): 761 q.addChild('feature', attrs = {'var': common.xmpp.NS_ACTIVITY}) 762 q.addChild('feature', attrs = {'var': common.xmpp.NS_ACTIVITY + '+notify'}) 763 q.addChild('feature', attrs = {'var': common.xmpp.NS_TUNE}) 764 q.addChild('feature', attrs = {'var': common.xmpp.NS_TUNE + '+notify'}) 765 q.addChild('feature', attrs = {'var': common.xmpp.NS_MOOD}) 766 q.addChild('feature', attrs = {'var': common.xmpp.NS_MOOD + '+notify'}) 767 q.addChild('feature', attrs = {'var': common.xmpp.NS_ESESSION_INIT}) 754 768 755 769 if (node is None or extension == 'cstates') and gajim.config.get('outgoing_chat_state_notifactions') != 'disabled': … … 793 807 attr[key] = i.getAttr(key) 794 808 if attr.has_key('category') and \ 795 attr['category'] in ('gateway', 'headline') and \796 attr.has_key('type'):809 attr['category'] in ('gateway', 'headline') and \ 810 attr.has_key('type'): 797 811 transport_type = attr['type'] 798 812 if attr.has_key('category') and \ 799 attr['category'] == 'conference' and \800 attr.has_key('type') and attr['type'] == 'text':813 attr['category'] == 'conference' and \ 814 attr.has_key('type') and attr['type'] == 'text': 801 815 is_muc = True 802 816 identities.append(attr) … … 869 883 if len(ext): 870 884 c.setAttr('ext', ' '.join(ext)) 871 c.setAttr('ver', gajim.version )885 c.setAttr('ver', gajim.version.split('-', 1)[0]) 872 886 return p 873 887 … … 1083 1097 data = {'jid': jid} 1084 1098 order = meta.getAttr('order') 1099 try: 1100 order = int(order) 1101 except: 1102 order = 0 1085 1103 if order != None: 1086 1104 data['order'] = order … … 1091 1109 self.dispatch('METACONTACTS', meta_list) 1092 1110 else: 1093 self.metacontacts_supported = False 1111 if iq_obj.getErrorCode() not in ('403', '406', '404'): 1112 self.private_storage_supported = False 1094 1113 # We can now continue connection by requesting the roster 1095 1114 self.connection.initRoster() … … 1208 1227 ConnectionCommands.__init__(self) 1209 1228 ConnectionPubSub.__init__(self) 1210 self.gmail_url =None1229 self.gmail_url = None 1211 1230 # List of IDs we are waiting answers for {id: (type_of_request, data), } 1212 1231 self.awaiting_answers = {} … … 1217 1236 # SUBSCRIBED event to gui 1218 1237 self.automatically_added = [] 1219 # keep the latest subscribed event for each jid to prevent loop when we 1238 # keep the latest subscribed event for each jid to prevent loop when we 1220 1239 # acknoledge presences 1221 1240 self.subscribed_events = {} 1241 1242 # keep track of sessions this connection has with other JIDs 1243 self.sessions = {} 1222 1244 try: 1223 1245 idle.init() 1224 1246 except: 1225 1247 HAS_IDLE = False 1226 1248 1227 1249 def build_http_auth_answer(self, iq_obj, answer): 1228 1250 if answer == 'yes': … … 1244 1266 msg = iq_obj.getTagData('body') # In case it's a message with a body 1245 1267 self.dispatch('HTTP_AUTH', (method, url, id, iq_obj, msg)); 1268 raise common.xmpp.NodeProcessed 1269 1270 def _FeatureNegCB(self, con, stanza, session): 1271 gajim.log.debug('FeatureNegCB') 1272 feature = stanza.getTag(name='feature', namespace=common.xmpp.NS_FEATURE) 1273 form = common.xmpp.DataForm(node=feature.getTag('x')) 1274 1275 if form['FORM_TYPE'] == 'urn:xmpp:ssn': 1276 self.dispatch('SESSION_NEG', (stanza.getFrom(), session, form)) 1277 else: 1278 reply = stanza.buildReply() 1279 reply.setType('error') 1280 1281 reply.addChild(feature) 1282 reply.addChild(node=xmpp.ErrorNode('service-unavailable', typ='cancel')) 1283 1284 con.send(reply) 1285 1286 raise common.xmpp.NodeProcessed 1287 1288 def _InitE2ECB(self, con, stanza, session): 1289 gajim.log.debug('InitE2ECB') 1290 init = stanza.getTag(name='init', namespace=common.xmpp.NS_ESESSION_INIT) 1291 form = common.xmpp.DataForm(node=init.getTag('x')) 1292 1293 self.dispatch('SESSION_NEG', (stanza.getFrom(), session, form)) 1294 1246 1295 raise common.xmpp.NodeProcessed 1247 1296 … … 1314 1363 ns = storage_tag.getNamespace() 1315 1364 if ns == 'storage:metacontacts': 1316 self. metacontacts_supported = False1365 self.private_storage_supported = False 1317 1366 # Private XML Storage (XEP49) is not supported by server 1318 1367 # Continue connecting … … 1322 1371 gajim.log.debug('rosterSetCB') 1323 1372 for item in iq_obj.getTag('query').getChildren(): 1324 jid = helpers.parse_jid(item.getAttr('jid'))1373 jid = helpers.parse_jid(item.getAttr('jid')) 1325 1374 name = item.getAttr('name') 1326 sub = item.getAttr('subscription')1327 ask = item.getAttr('ask')1375 sub = item.getAttr('subscription') 1376 ask = item.getAttr('ask') 1328 1377 groups = [] 1329 1378 for group in item.getTags('group'): … … 1400 1449 qp.setTagData('utc', strftime('%Y%m%dT%T', gmtime())) 1401 1450 qp.setTagData('tz', tzname[daylight]) 1402 qp.setTagData('display', strftime('%c', localtime())) 1451 qp.setTagData('display', helpers.decode_string(strftime('%c', 1452 localtime()))) 1403 1453 self.connection.send(iq_obj) 1404 1454 raise common.xmpp.NodeProcessed … … 1408 1458 iq_obj = iq_obj.buildReply('result') 1409 1459 qp = iq_obj.setTag('time', 1410 namespace=common.xmpp.NS_TIME_REVISED)1460 namespace=common.xmpp.NS_TIME_REVISED) 1411 1461 qp.setTagData('utc', strftime('%Y-%m-%dT%TZ', gmtime())) 1412 1462 zone = -(timezone, altzone)[daylight] / 60 … … 1461 1511 def _messageCB(self, con, msg): 1462 1512 '''Called when we receive a message''' 1513 frm = helpers.get_full_jid_from_iq(msg) 1514 mtype = msg.getType() 1515 thread_id = msg.getThread() 1516 1517 if not mtype: 1518 mtype = 'normal' 1519 1520 if not mtype == 'groupchat': 1521 session = self.get_session(frm, thread_id, mtype) 1522 1523 if thread_id and not session.received_thread_id: 1524 session.received_thread_id = True 1525 1463 1526 # check if the message is pubsub#event 1464 1527 if msg.getTag('event') is not None: … … 1470 1533 self._HttpAuthCB(con, msg) 1471 1534 return 1535 if msg.getTag('feature') and msg.getTag('feature').namespace == \ 1536 common.xmpp.NS_FEATURE: 1537 if gajim.HAVE_PYCRYPTO: 1538 self._FeatureNegCB(con, msg, session) 1539 return 1540 if msg.getTag('init') and msg.getTag('init').namespace == \ 1541 common.xmpp.NS_ESESSION_INIT: 1542 self._InitE2ECB(con, msg, session) 1543 1544 encrypted = False 1545 tim = msg.getTimestamp() 1546 tim = helpers.datetime_tuple(tim) 1547 tim = localtime(timegm(tim)) 1548 1549 e2e_tag = msg.getTag('c', namespace = common.xmpp.NS_STANZA_CRYPTO) 1550 if e2e_tag: 1551 encrypted = True 1552 1553 try: 1554 msg = session.decrypt_stanza(msg) 1555 except: 1556 self.dispatch('FAILED_DECRYPT', (frm, tim)) 1557 1472 1558 msgtxt = msg.getBody() 1473 1559 msghtml = msg.getXHTML() 1474 mtype = msg.getType()1475 1560 subject = msg.getSubject() # if not there, it's None 1476 1561 tim = msg.getTimestamp() … … 1491 1576 no_log_for = '' 1492 1577 no_log_for = no_log_for.split() 1493 encrypted = False1494 1578 chatstate = None 1495 1579 encTag = msg.getTag('x', namespace = common.xmpp.NS_ENCRYPTED) … … 1511 1595 if xtag.getNamespace() == common.xmpp.NS_CONFERENCE and not invite: 1512 1596 room_jid = xtag.getAttr('jid') 1513 self.dispatch('GC_INVITATION', (room_jid, frm, '', None)) 1597 is_continued = False 1598 if xtag.getTag('continue'): 1599 is_continued = True 1600 self.dispatch('GC_INVITATION', (room_jid, frm, '', None, 1601 is_continued)) 1514 1602 return 1603 form_node = None 1604 for xtag in xtags: 1605 if xtag.getNamespace() == common.xmpp.NS_DATA: 1606 form_node = xtag 1607 break 1515 1608 # chatstates - look for chatstate tags in a message if not delayed 1516 1609 if not delayed: … … 1538 1631 #decrypt 1539 1632 encmsg = encTag.getData() 1540 1633 1541 1634 keyID = gajim.config.get_per('accounts', self.name, 'keyid') 1542 1635 if keyID: 1543 1636 decmsg = self.gpg.decrypt(encmsg, keyID) 1637 # \x00 chars are not allowed in C (so in GTK) 1638 decmsg = decmsg.replace('\x00', '') 1544 1639 if decmsg: 1545 1640 msgtxt = decmsg … … 1550 1645 error_msg = msgtxt 1551 1646 msgtxt = None 1552 if se lf.name not in no_log_for:1647 if session.is_loggable(): 1553 1648 try: 1554 1649 gajim.logger.write('error', frm, error_msg, tim = tim, … … 1566 1661 self.dispatch('GC_SUBJECT', (frm, subject, msgtxt, has_timestamp)) 1567 1662 else: 1663 statusCode = msg.getStatusCode() 1568 1664 if not msg.getTag('body'): #no <body> 1569 1665 # It could be a config change. See 1570 1666 # http://www.xmpp.org/extensions/xep-0045.html#roomconfig-notify 1571 1667 if msg.getTag('x'): 1572 statusCode = msg.getStatusCode()1573 1668 if statusCode != []: 1574 1669 self.dispatch('GC_CONFIG_CHANGE', (jid, statusCode)) … … 1577 1672 if not self.last_history_line.has_key(jid): 1578 1673 return 1579 self.dispatch('GC_MSG', (frm, msgtxt, tim, has_timestamp, msghtml)) 1580 if self.name not in no_log_for and not int(float(mktime(tim)))\ 1581 <= self.last_history_line[jid] and msgtxt: 1674 self.dispatch('GC_MSG', (frm, msgtxt, tim, has_timestamp, msghtml, 1675 statusCode)) 1676 if self.name not in no_log_for and jid not in no_log_for and not \ 1677 int(float(mktime(tim))) <= self.last_history_line[jid] and msgtxt: 1582 1678 try: 1583 1679 gajim.logger.write('gc_msg', frm, msgtxt, tim = tim) … … 1588 1684 if not msg.getTag('body') and chatstate is None: #no <body> 1589 1685 return 1590 if msg.getTag('body') and self.name not in no_log_for and jid not in\ 1591 no_log_for and msgtxt: 1686 if msg.getTag('body') and session.is_loggable() and msgtxt: 1592 1687 try: 1593 1688 msg_id = gajim.logger.write('chat_msg_recv', frm, msgtxt, … … 1602 1697 item = invite.getTag('password') 1603 1698 password = invite.getTagData('password') 1604 self.dispatch('GC_INVITATION',(frm, jid_from, reason, password)) 1699 is_continued = False 1700 if invite.getTag('invite').getTag('continue'): 1701 is_continued = True 1702 self.dispatch('GC_INVITATION',(frm, jid_from, reason, password, 1703 is_continued)) 1605 1704 return 1606 if se lf.name not in no_log_for and jid not in no_log_forand msgtxt:1705 if session.is_loggable()and msgtxt: 1607 1706 try: 1608 1707 gajim.logger.write('single_msg_recv', frm, msgtxt, tim = tim, … … 1615 1714 mtype = treat_as 1616 1715 self.dispatch('MSG', (frm, msgtxt, tim, encrypted, mtype, 1617 subject, chatstate, msg_id, composing_xep, user_nick, msghtml)) 1716 subject, chatstate, msg_id, composing_xep, user_nick, msghtml, 1717 session, form_node)) 1618 1718 # END messageCB 1719 1720 def get_session(self, jid, thread_id, type): 1721 '''returns an existing session between this connection and 'jid', returns a new one if none exist.''' 1722 session = self.find_session(jid, thread_id, type) 1723 1724 if session: 1725 return session 1726 else: 1727 # it's possible we initiated a session with a bare JID and this is the 1728 # first time we've seen a resource 1729 bare_jid = gajim.get_jid_without_resource(jid) 1730 if bare_jid != jid: 1731 session = self.find_session(bare_jid, thread_id, type) 1732 if session: 1733 if not session.received_thread_id: 1734 thread_id = session.thread_id 1735 1736 self.move_session(bare_jid, thread_id, jid.split("/")[1]) 1737 return session 1738 1739 return self.make_new_session(jid, thread_id, type) 1740 1741 def find_session(self, jid, thread_id, type): 1742 try: 1743 if type == 'chat' and not thread_id: 1744 return self.find_null_session(jid) 1745 else:
