def start_file_transfer(self, jid, file_props, request=False): logger.info("start file transfer with file: %s" % file_props) contact = gajim.contacts.get_contact_with_highest_priority(self.name, gajim.get_jid_without_resource(jid)) if gajim.contacts.is_gc_contact(self.name,jid): gcc = jid.split('/') if len(gcc) == 2: contact = gajim.contacts.get_gc_contact(self.name, gcc[0], gcc[1]) if contact is None: return use_security = contact.supports(nbxmpp.NS_JINGLE_XTLS) jingle = JingleSession(self, weinitiate=True, jid=jid, werequest=request) # this is a file transfer jingle.session_type_FT = True self._sessions[jingle.sid] = jingle file_props.sid = jingle.sid if contact.supports(nbxmpp.NS_JINGLE_BYTESTREAM): transport = JingleTransportSocks5() elif contact.supports(nbxmpp.NS_JINGLE_IBB): transport = JingleTransportIBB() c = JingleFileTransfer(jingle, transport=transport, file_props=file_props, use_security=use_security) file_props.algo = self.__hash_support(contact) jingle.add_content('file' + helpers.get_random_string_16(), c) jingle.start_session() return c.transport.sid
def __on_transport_info(self, stanza, content, error, action): log.info("__on_transport_info") candError = content.getTag('transport').getTag('candidate-error') candUsed = content.getTag('transport').getTag('candidate-used') if (candError or candUsed) and \ self.state >= STATE_CAND_SENT_AND_RECEIVED: raise nbxmpp.NodeProcessed if candError: if not gajim.socks5queue.listener.connections: gajim.socks5queue.listener.disconnect() self.nominated_cand['peer-cand'] = False if self.state == STATE_CAND_SENT: if not self.nominated_cand['our-cand'] and \ not self.nominated_cand['peer-cand']: if not self.weinitiate: return self.__state_changed(STATE_TRANSPORT_REPLACE) else: response = stanza.buildReply('result') response.delChild(response.getQuery()) self.session.connection.connection.send(response) self.__state_changed(STATE_TRANSFERING) raise nbxmpp.NodeProcessed else: args = {'candError' : True} self.__state_changed(STATE_CAND_RECEIVED, args) return if candUsed: streamhost_cid = candUsed.getAttr('cid') streamhost_used = None for cand in self.transport.candidates: if cand['candidate_id'] == streamhost_cid: streamhost_used = cand break if streamhost_used == None or streamhost_used['type'] == 'proxy': if gajim.socks5queue.listener and \ not gajim.socks5queue.listener.connections: gajim.socks5queue.listener.disconnect() if content.getTag('transport').getTag('activated'): self.state = STATE_TRANSFERING jid = gajim.get_jid_without_resource(self.session.ourjid) gajim.socks5queue.send_file(self.file_props, self.session.connection.name, 'client') return args = {'content' : content, 'sendCand' : False} if self.state == STATE_CAND_SENT: self.__state_changed(STATE_CAND_SENT_AND_RECEIVED, args) self.__state_changed(STATE_TRANSFERING) raise nbxmpp.NodeProcessed else: self.__state_changed(STATE_CAND_RECEIVED, args)
def __send_hash(self): # Send hash in a session info checksum = nbxmpp.Node(tag='checksum', payload=[nbxmpp.Node(tag='file', payload=[self._calcHash()])]) checksum.setNamespace(nbxmpp.NS_JINGLE_FILE_TRANSFER) self.session.__session_info(checksum ) pjid = gajim.get_jid_without_resource(self.session.peerjid) file_info = {'name' : self.file_props.name, 'file-name' : self.file_props.file_name, 'hash' : self.file_props.hash_, 'size' : self.file_props.size, 'date' : self.file_props.date, 'peerjid' : pjid } self.session.connection.set_file_info(file_info)
def save_if_not_exists(self, with_, direction, tim, msg='', nick=None): if tim: time_col = int(float(time.mktime(tim))) else: time_col = int(float(time.time())) if not msg: return if self.jid_is_from_pm(with_) or nick: # It's a groupchat message if nick: # It's a message from a groupchat occupent type_ = 'gc_msg' with_ = with_ + '/' + nick else: # It's a server message message, we don't log them return else: if direction == 'from': type_ = 'chat_msg_recv' elif direction == 'to': type_ = 'chat_msg_sent' jid_id = self.get_jid_id(with_) where_sql = 'jid_id = %s AND message=?' % jid_id if type_ == 'gc_msg': # We cannot differentiate gc message and pm messages, so look in # both logs with_2 = gajim.get_jid_without_resource(with_) if with_ != with_2: jid_id2 = self.get_jid_id(with_2) where_sql = 'jid_id in (%s, %s) AND message=?' % (jid_id, jid_id2) start_time = time_col - 300 # 5 minutes arrount given time end_time = time_col + 300 # 5 minutes arrount given time self.cur.execute(''' SELECT log_line_id FROM logs WHERE (%s) AND time BETWEEN %d AND %d ORDER BY time ''' % (where_sql, start_time, end_time), (msg,)) results = self.cur.fetchall() if results: log.debug('Log already in DB, ignoring it') return log.debug('New log received from server archives, storing it') self.write(type_, with_, message=msg, tim=tim)
def __on_session_accept(self, stanza, content, error, action): log.info("__on_session_accept") con = self.session.connection security = content.getTag('security') if not security: # responder can not verify our fingerprint self.use_security = False else: fingerprint = security.getTag('fingerprint') if fingerprint: fingerprint = fingerprint.getData() self.x509_fingerprint = fingerprint if not jingle_xtls.check_cert(gajim.get_jid_without_resource( self.session.responder), fingerprint): id_ = jingle_xtls.send_cert_request(con, self.session.responder) jingle_xtls.key_exchange_pend(id_, self.continue_session_accept, [stanza]) raise nbxmpp.NodeProcessed self.continue_session_accept(stanza)
def _fill_content(self, content): description_node = nbxmpp.simplexml.Node(tag=nbxmpp.NS_JINGLE_FILE_TRANSFER + " description") if self.session.werequest: simode = nbxmpp.simplexml.Node(tag="request") else: simode = nbxmpp.simplexml.Node(tag="offer") file_tag = simode.setTag("file") if self.file_props.name: node = nbxmpp.simplexml.Node(tag="name") node.addData(self.file_props.name) file_tag.addChild(node=node) if self.file_props.date: node = nbxmpp.simplexml.Node(tag="date") node.addData(self.file_props.date) file_tag.addChild(node=node) if self.file_props.size: node = nbxmpp.simplexml.Node(tag="size") node.addData(self.file_props.size) file_tag.addChild(node=node) if self.file_props.type_ == "r": if self.file_props.hash_: h = file_tag.addChild( "hash", attrs={"algo": self.file_props.algo}, namespace=nbxmpp.NS_HASHES, payload=self.file_props.hash_, ) else: # if the file is less than 10 mb, then it is small # lets calculate it right away if self.file_props.size < 10000000 and not self.file_props.hash_: h = self._calcHash() if h: file_tag.addChild(node=h) pjid = gajim.get_jid_without_resource(self.session.peerjid) file_info = { "name": self.file_props.name, "file-name": self.file_props.file_name, "hash": self.file_props.hash_, "size": self.file_props.size, "date": self.file_props.date, "peerjid": pjid, } self.session.connection.set_file_info(file_info) desc = file_tag.setTag("desc") if self.file_props.desc: desc.setData(self.file_props.desc) description_node.addChild(node=simode) if self.use_security: security = nbxmpp.simplexml.Node(tag=nbxmpp.NS_JINGLE_XTLS + " security") certpath = os.path.join(gajim.MY_CERT_DIR, SELF_SIGNED_CERTIFICATE) + ".cert" cert = load_cert_file(certpath) if cert: try: digest_algo = cert.get_signature_algorithm().split("With")[0] except AttributeError, e: # Old py-OpenSSL is missing get_signature_algorithm digest_algo = "sha256" security.addChild("fingerprint").addData(cert.digest(digest_algo)) for m in ("x509",): # supported authentication methods method = nbxmpp.simplexml.Node(tag="method") method.setAttr("name", m) security.addChild(node=method) content.addChild(node=security)
def get_jid_from_iq(iq_obj): '''return the jid (without resource) from an iq as unicode''' jid = get_full_jid_from_iq(iq_obj) return gajim.get_jid_without_resource(jid)
def __on_session_initiate(self, stanza, jingle, error, action): """ We got a jingle session request from other entity, therefore we are the receiver... Unpack the data, inform the user """ if self.state != JingleStates.ended: raise OutOfOrder self.initiator = jingle['initiator'] self.responder = self.ourjid self.peerjid = self.initiator self.accepted = False # user did not accept this session yet # TODO: If the initiator is unknown to the receiver (e.g., via presence # subscription) and the receiver has a policy of not communicating via # Jingle with unknown entities, it SHOULD return a <service-unavailable/> # error. # Lets check what kind of jingle session does the peer want contents, contents_rejected, reason_txt = self.__parse_contents(jingle) # If we are not receivin a file # Check if there's already a session with this user: if contents[0][0] != 'file': for session in self.connection.iter_jingle_sessions(self.peerjid): if not session is self: reason = nbxmpp.Node('reason') alternative_session = reason.setTag('alternative-session') alternative_session.setTagData('sid', session.sid) self.__ack(stanza, jingle, error, action) self._session_terminate(reason) raise nbxmpp.NodeProcessed else: # Stop if we don't have the requested file or the peer is not # allowed to request the file request = \ jingle.getTag('content').getTag('description').getTag('request') if request: self.request = True h = request.getTag('file').getTag('hash') h = h.getData() if h else None n = request.getTag('file').getTag('name') n = n.getData() if n else None pjid = gajim.get_jid_without_resource(self.peerjid) file_info = self.connection.get_file_info(pjid, h, n, self.connection.name) if not file_info: log.warning('The peer ' + pjid + \ ' is requesting a ' + \ 'file that we dont have or ' + \ 'it is not allowed to request') self.decline_session() raise nbxmpp.NodeProcessed # If there's no content we understand... if not contents: # TODO: http://xmpp.org/extensions/xep-0166.html#session-terminate reason = nbxmpp.Node('reason') reason.setTag(reason_txt) self.__ack(stanza, jingle, error, action) self._session_terminate(reason) raise nbxmpp.NodeProcessed self.state = JingleStates.pending # Send event about starting a session gajim.nec.push_incoming_event(JingleRequestReceivedEvent(None, conn=self.connection, jingle_session=self, contents=contents))
def __start_SOCK5_transfer(self): # It tells wether we start the transfer as client or server mode = None if self.jft.isOurCandUsed(): mode = 'client' streamhost_used = self.jft.nominated_cand['our-cand'] gajim.socks5queue.remove_server(self.jft.file_props.sid) else: mode = 'server' streamhost_used = self.jft.nominated_cand['peer-cand'] gajim.socks5queue.remove_client(self.jft.file_props.sid) # our_cand = self.jft.nominated_cand['our-cand'] # gajim.socks5queue.remove_receiver(our_cand['idx']) if streamhost_used['type'] == 'proxy': self.jft.file_props.is_a_proxy = True if self.jft.file_props.type_ == 's' and self.jft.weinitiate: self.jft.file_props.proxy_sender = streamhost_used['initiator'] self.jft.file_props.proxy_receiver = streamhost_used['target'] else: self.jft.file_props.proxy_sender = streamhost_used['target'] self.jft.file_props.proxy_receiver = streamhost_used[ 'initiator'] if self.jft.file_props.type_ == 's': s = gajim.socks5queue.senders for sender in s: if s[sender].host == streamhost_used['host'] and \ s[sender].connected: return elif self.jft.file_props.type_ == 'r': r = gajim.socks5queue.readers for reader in r: if r[reader].host == streamhost_used['host'] and \ r[reader].connected: return else: raise TypeError self.jft.file_props.streamhost_used = True streamhost_used['sid'] = self.jft.file_props.sid self.jft.file_props.streamhosts = [] self.jft.file_props.streamhosts.append(streamhost_used) self.jft.file_props.proxyhosts = [] self.jft.file_props.proxyhosts.append(streamhost_used) if self.jft.file_props.type_ == 's': gajim.socks5queue.idx += 1 idx = gajim.socks5queue.idx sockobj = Socks5SenderClient(gajim.idlequeue, idx, gajim.socks5queue, _sock=None, host=str(streamhost_used['host']), port=int(streamhost_used['port']), fingerprint=None, connected=False, file_props=self.jft.file_props) else: sockobj = Socks5ReceiverClient(gajim.idlequeue, streamhost_used, sid=self.jft.file_props.sid, file_props=self.jft.file_props, fingerprint=None) sockobj.proxy = True sockobj.streamhost = streamhost_used gajim.socks5queue.add_sockobj(self.jft.session.connection.name, sockobj) streamhost_used['idx'] = sockobj.queue_idx # If we offered the nominated candidate used, we activate # the proxy if not self.jft.isOurCandUsed(): gajim.socks5queue.on_success[self.jft.file_props.sid] = \ self.jft.transport._on_proxy_auth_ok # TODO: add on failure else: jid = gajim.get_jid_without_resource(self.jft.session.ourjid) gajim.socks5queue.send_file(self.jft.file_props, self.jft.session.connection.name, mode)