changeset fe9d79c951fa in /home/hg/repos/gajim
details:http://hg.gajim.org/gajim?cmd=changeset;node=fe9d79c951fa
description: support for xep-300
diffstat:
src/common/gajim.py | 4 +-
src/common/jingle.py | 14 ++++++
src/common/jingle_ft.py | 39 +++++++++++++++--
src/common/jingle_session.py | 27 +++++++++++-
src/common/xmpp/protocol.py | 91 ++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 161 insertions(+), 14 deletions(-)
diffs (truncated from 317 to 300 lines):
diff -r 3ccb8751f4f7 -r fe9d79c951fa src/common/gajim.py
--- a/src/common/gajim.py Sat Jan 07 20:49:07 2012 -0500
+++ b/src/common/gajim.py Sun Jan 15 19:37:00 2012 -0500
@@ -208,7 +208,9 @@
'jabber:iq:gateway', xmpp.NS_LAST, xmpp.NS_PRIVACY, xmpp.NS_PRIVATE,
xmpp.NS_REGISTER, xmpp.NS_VERSION, xmpp.NS_DATA, xmpp.NS_ENCRYPTED,
'msglog',
'sslc2s', 'stringprep', xmpp.NS_PING, xmpp.NS_TIME_REVISED,
xmpp.NS_SSN,
- xmpp.NS_MOOD, xmpp.NS_ACTIVITY, xmpp.NS_NICK, xmpp.NS_ROSTERX,
xmpp.NS_SECLABEL]
+ xmpp.NS_MOOD, xmpp.NS_ACTIVITY, xmpp.NS_NICK, xmpp.NS_ROSTERX,
xmpp.NS_SECLABEL,
+ xmpp.NS_HASHES, xmpp.NS_HASHES_MD5, xmpp.NS_HASHES_SHA1,
+ xmpp.NS_HASHES_SHA256, xmpp.NS_HASHES_SHA512]
# Optional features gajim supports per account
gajim_optional_features = {}
diff -r 3ccb8751f4f7 -r fe9d79c951fa src/common/jingle.py
--- a/src/common/jingle.py Sat Jan 07 20:49:07 2012 -0500
+++ b/src/common/jingle.py Sun Jan 15 19:37:00 2012 -0500
@@ -151,10 +151,24 @@
file_props['sid'] = jingle.sid
c = JingleFileTransfer(jingle, file_props=file_props,
use_security=use_security)
+ c.hash_algo = self.__hash_support(contact)
jingle.add_content('file' + helpers.get_random_string_16(), c)
jingle.start_session()
return c.transport.sid
+ def __hash_support(self, contact):
+
+ if contact.supports(xmpp.NS_HASHES):
+ if contact.supports(xmpp.NS_HASHES_MD5):
+ return 'md5'
+ elif contact.supports(xmpp.NS_HASHES_SHA1):
+ return 'sha-1'
+ elif contact.supports(xmpp.NS_HASHES_SHA256):
+ return 'sha-256'
+ elif contact.supports(xmpp.NS_HASHES_SHA512):
+ return 'sha-512'
+
+ return None
def iter_jingle_sessions(self, jid, sid=None, media=None):
if sid:
diff -r 3ccb8751f4f7 -r fe9d79c951fa src/common/jingle_ft.py
--- a/src/common/jingle_ft.py Sat Jan 07 20:49:07 2012 -0500
+++ b/src/common/jingle_ft.py Sun Jan 15 19:37:00 2012 -0500
@@ -26,7 +26,7 @@
from common import helpers
from common.socks5 import Socks5ReceiverClient, Socks5SenderClient
from common.connection_handlers_events import FileRequestReceivedEvent
-
+import threading
import logging
log = logging.getLogger('gajim.c.jingle_ft')
@@ -56,9 +56,11 @@
# events we might be interested in
self.callbacks['session-initiate'] += [self.__on_session_initiate]
+ self.callbacks['session-initiate-sent'] +=
[self.__on_session_initiate_sent]
self.callbacks['content-add'] += [self.__on_session_initiate]
self.callbacks['session-accept'] += [self.__on_session_accept]
- self.callbacks['session-terminate'] += [self.__on_session_terminate]
+ self.callbacks['session-terminate'] += [self.__on_session_terminate]
+ self.callbacks['session-info'] += [self.__on_session_info]
self.callbacks['transport-accept'] += [self.__on_transport_accept]
self.callbacks['transport-replace'] += [self.__on_transport_replace]
self.callbacks['session-accept-sent'] += [self.__transport_setup]
@@ -99,12 +101,36 @@
self.session = session
self.media = 'file'
self.nominated_cand = {}
+
+ # Hash algorithm that we are using to calculate the integrity of the
+ # file. Could be 'md5', 'sha-1', etc...
+ self.hash_algo = None
def __on_session_initiate(self, stanza, content, error, action):
gajim.nec.push_incoming_event(FileRequestReceivedEvent(None,
conn=self.session.connection, stanza=stanza,
jingle_content=content,
FT_content=self))
-
+ def __on_session_initiate_sent(self, stanza, content, error, action):
+ # Calculate file_hash in a new thread
+ self.hashThread = threading.Thread(target=self.__calcHash)
+ self.hashThread.start()
+
+ def __calcHash(self):
+ if self.hash_algo == None:
+ return
+ try:
+ file = open(self.file_props['file-name'], 'r')
+ except:
+ return
+ h = xmpp.Hashes()
+ h.calculateHash(self.hash_algo, file)
+ checksum = xmpp.Node(tag='checksum',
+ payload=[xmpp.Node(tag='file', payload=[h])])
+ checksum.setNamespace(xmpp.NS_JINGLE_FILE_TRANSFER)
+ # Send hash in a session info
+ self.session.__session_info(checksum )
+
+
def __on_session_accept(self, stanza, content, error, action):
log.info("__on_session_accept")
con = self.session.connection
@@ -152,6 +178,9 @@
def __on_session_terminate(self, stanza, content, error, action):
log.info("__on_session_terminate")
+ def __on_session_info(self, stanza, content, error, action):
+ pass
+
def __on_transport_accept(self, stanza, content, error, action):
log.info("__on_transport_accept")
@@ -164,8 +193,6 @@
def __on_transport_info(self, stanza, content, error, action):
log.info("__on_transport_info")
- #if not self.weinitiate: # proxy activated from initiator
- # return
if content.getTag('transport').getTag('candidate-error'):
self.nominated_cand['peer-cand'] = False
if self.state == STATE_CAND_SENT_PENDING_REPLY:
@@ -392,7 +419,7 @@
def start_transfer(self):
-
+
self.state = STATE_TRANSFERING
# It tells wether we start the transfer as client or server
diff -r 3ccb8751f4f7 -r fe9d79c951fa src/common/jingle_session.py
--- a/src/common/jingle_session.py Sat Jan 07 20:49:07 2012 -0500
+++ b/src/common/jingle_session.py Sun Jan 15 19:37:00 2012 -0500
@@ -98,7 +98,7 @@
self.accepted = True # is this session accepted by user
-
+ self.file_hash = None
# callbacks to call on proper contents
# use .prepend() to add new callbacks, especially when you're going
# to send error instead of ack
@@ -126,6 +126,7 @@
'iq-result': [self.__broadcast],
'iq-error': [self.__on_error],
}
+
def collect_iq_id(self, iq_id):
if iq_id is not None:
@@ -416,9 +417,20 @@
def __on_session_info(self, stanza, jingle, error, action):
# TODO: ringing, active, (un)hold, (un)mute
payload = jingle.getPayload()
- if payload:
- self.__send_error(stanza, 'feature-not-implemented',
'unsupported-info', type_='modify')
- raise xmpp.NodeProcessed
+ for p in payload:
+ if p.getName() == 'checksum':
+ hashes = p.getTag('file').getTag(name='hashes',
+ namespace=xmpp.NS_HASHES)
+ for hash in hashes.getChildren():
+ algo = hash.getAttr('algo')
+ if algo in xmpp.Hashes.supported:
+ data = hash.getData()
+ self.file_hash = data
+ print data
+ raise xmpp.NodeProcessed
+ self.__send_error(stanza, 'feature-not-implemented',
'unsupported-info', type_='modify')
+ raise xmpp.NodeProcessed
+
def __on_content_remove(self, stanza, jingle, error, action):
for content in jingle.iterTags('content'):
@@ -704,6 +716,13 @@
if payload:
jingle.addChild(node=payload)
self.connection.connection.send(stanza)
+
+ def _JingleFileTransfer__session_info(self, p):
+ # For some strange reason when I call
+ # self.session.__session_info(h) from the jingleFileTransfer object
+ # within a thread, this method gets called instead. Even though, it
+ # isn't being called explicitly.
+ self.__session_info(p)
def _session_terminate(self, reason=None):
assert self.state != JingleStates.ended
diff -r 3ccb8751f4f7 -r fe9d79c951fa src/common/xmpp/protocol.py
--- a/src/common/xmpp/protocol.py Sat Jan 07 20:49:07 2012 -0500
+++ b/src/common/xmpp/protocol.py Sun Jan 15 19:37:00 2012 -0500
@@ -23,6 +23,7 @@
from simplexml import Node, NodeBuilder
import time
import string
+import hashlib
def ascii_upper(s):
trans_table = string.maketrans(string.ascii_lowercase,
@@ -89,7 +90,7 @@
NS_JINGLE_RTP = 'urn:xmpp:jingle:apps:rtp:1' #
XEP-0167
NS_JINGLE_RTP_AUDIO = 'urn:xmpp:jingle:apps:rtp:audio' #
XEP-0167
NS_JINGLE_RTP_VIDEO = 'urn:xmpp:jingle:apps:rtp:video' #
XEP-0167
-NS_JINGLE_FILE_TRANSFER='urn:xmpp:jingle:apps:file-transfer:1' #
XEP-0234
+NS_JINGLE_FILE_TRANSFER ='urn:xmpp:jingle:apps:file-transfer:1' #
XEP-0234
NS_JINGLE_XTLS='urn:xmpp:jingle:security:xtls:0' # XTLS:
EXPERIMENTAL security layer of jingle
NS_JINGLE_RAW_UDP = 'urn:xmpp:jingle:transports:raw-udp:1' #
XEP-0177
NS_JINGLE_ICE_UDP = 'urn:xmpp:jingle:transports:ice-udp:1' #
XEP-0176
@@ -160,7 +161,12 @@
NS_PUBKEY_REVOKE = 'urn:xmpp:revoke:2'
NS_PUBKEY_ATTEST = 'urn:xmpp:attest:2'
NS_STREAM_MGMT = 'urn:xmpp:sm:2' # XEP-198
-
+NS_HASHES = 'urn:xmpp:hashes:0' # XEP-300
+NS_HASHES_MD5 = 'urn:xmpp:hash-function-textual-names:md5'
+NS_HASHES_SHA1 = 'urn:xmpp:hash-function-textual-names:sha-1'
+NS_HASHES_SHA256 = 'urn:xmpp:hash-function-textual-names:sha-256'
+NS_HASHES_SHA512 = 'urn:xmpp:hash-function-textual-names:sha-512'
+
xmpp_stream_error_conditions = '''
bad-format -- -- -- The entity has sent XML that cannot be processed.
bad-namespace-prefix -- -- -- The entity has sent a namespace prefix that is
unsupported, or has sent no namespace prefix on an element that requires such a
prefix.
@@ -1030,7 +1036,85 @@
attrs={'id': self.getID()})
iq.setQuery(self.getQuery().getName()).setNamespace(self.getQueryNS())
return iq
-
+
+class Hashes(Node):
+ """
+ Hash elements for various XEPs as defined in XEP-300
+ """
+
+ """
+ RECOMENDED HASH USE:
+ Algorithm Support
+ MD2 MUST NOT
+ MD4 MUST NOT
+ MD5 MAY
+ SHA-1 MUST
+ SHA-256 MUST
+ SHA-512 SHOULD
+ """
+
+ supported = ('md5', 'sha-1', 'sha-256', 'sha-512')
+
+ def __init__(self, nsp=NS_HASHES):
+ Node.__init__(self, None, {}, [], None, None,False, None)
+ self.setNamespace(nsp)
+ self.setName('hashes')
+
+ def calculateHash(self, algo, file_string):
+ """
+ Calculate the hash and add it. It is preferable doing it here
+ instead of doing it all over the place in Gajim.
+ """
+ hl = None
+ hash = None
+
+ # file_string can be a string or a file
+ if type(file_string) == str: # if it is a string
+ if algo == 'md5':
+ hl = hashlib.md5()
+ elif algo == 'sha-1':
+ hl = hashlib.sha1()
+ elif algo == 'sha-256':
+ hl = hashlib.sha256()
+ elif algo == 'sha-512':
+ hl = hashlib.sha512()
+
+ if hl == None:
+ # Raise exception
+ raise Exception('Hash algorithm not supported')
+ else:
+ hl.update(file_string)
+ hash = hl.hexdigest()
+ else: # if it is a file
+
+ if algo == 'md5':
+ hl = hashlib.md5()
+ elif algo == 'sha-1':
+ hl = hashlib.sha1()
+ elif algo == 'sha-256':
+ hl = hashlib.sha256()
+ elif algo == 'sha-512':
+ hl = hashlib.sha512()
+
+ if hl == None:
+ # Raise exception
+ raise Exception('Hash algorithm not supported')
+ else:
+ for line in file_string:
+ hl.update(line)
+ hash = hl.hexdigest()
+
+ self.addHash(hash, algo)
+
_______________________________________________
Commits mailing list
[email protected]
http://lists.gajim.org/cgi-bin/listinfo/commits