def _remove_transfer(self, iter_, sid, file_props): self.model.remove(iter_) if not file_props: return if file_props.tt_account: # file transfer is set account = file_props.tt_account if account in app.connections: # there is a connection to the account app.connections[account].remove_transfer(file_props) if file_props.type_ == 'r': # we receive a file other = file_props.sender else: # we send a file other = file_props.receiver if isinstance(other, str): jid = app.get_jid_without_resource(other) else: # It's a Contact instance jid = other.jid for ev_type in ('file-error', 'file-completed', 'file-request-error', 'file-send-error', 'file-stopped'): for event in app.events.get_events(account, jid, [ev_type]): if event.file_props.sid == file_props.sid: app.events.remove_events(account, jid, event) app.interface.roster.draw_contact(jid, account) app.interface.roster.show_title() FilesProp.deleteFileProp(file_props) del (file_props)
def _ibb_received(self, _con, stanza, properties): if not properties.is_ibb: return if properties.ibb.type == 'data': self._log.info('Data received, sid: %s, seq: %s', properties.ibb.sid, properties.ibb.seq) file_props = FilesProp.getFilePropByTransportSid( self._account, properties.ibb.sid) if not file_props: self.send_reply(stanza, nbxmpp.ERR_ITEM_NOT_FOUND) raise NodeProcessed if file_props.connected: self._on_data_received(stanza, file_props, properties) self.send_reply(stanza) elif properties.ibb.type == 'open': self._log.info('Open received, sid: %s, blocksize: %s', properties.ibb.sid, properties.ibb.block_size) file_props = FilesProp.getFilePropByTransportSid( self._account, properties.ibb.sid) if not file_props: self.send_reply(stanza, nbxmpp.ERR_ITEM_NOT_FOUND) raise NodeProcessed file_props.block_size = properties.ibb.block_size file_props.direction = '<' file_props.seq = 0 file_props.received_len = 0 file_props.last_time = time.time() file_props.error = 0 file_props.paused = False file_props.connected = True file_props.completed = False file_props.disconnect_cb = None file_props.continue_cb = None file_props.syn_id = stanza.getID() file_props.fp = open(file_props.file_name, 'wb') self.send_reply(stanza) elif properties.ibb.type == 'close': self._log.info('Close received, sid: %s', properties.ibb.sid) file_props = FilesProp.getFilePropByTransportSid( self._account, properties.ibb.sid) if not file_props: self.send_reply(stanza, nbxmpp.ERR_ITEM_NOT_FOUND) raise NodeProcessed self.send_reply(stanza) file_props.fp.close() file_props.completed = file_props.received_len >= file_props.size if not file_props.completed: file_props.error = -1 app.socks5queue.complete_transfer_cb(self._account, file_props) raise NodeProcessed
def _on_bytestream_set(self, con, iq_obj): target = iq_obj.getAttr('to') id_ = iq_obj.getAttr('id') query = iq_obj.getTag('query') sid = query.getAttr('sid') file_props = FilesProp.getFileProp(self._account, sid) streamhosts = [] for item in query.getChildren(): if item.getName() == 'streamhost': host_dict = { 'state': 0, 'target': target, 'id': id_, 'sid': sid, 'initiator': self._ft_get_from(iq_obj) } for attr in item.getAttrs(): host_dict[attr] = item.getAttr(attr) if 'host' not in host_dict: continue if 'jid' not in host_dict: continue if 'port' not in host_dict: continue streamhosts.append(host_dict) file_props = FilesProp.getFilePropBySid(sid) if file_props is not None: if file_props.type_ == 's': # FIXME: remove fast xmlns # only psi do this if file_props.streamhosts: file_props.streamhosts.extend(streamhosts) else: file_props.streamhosts = streamhosts app.socks5queue.connect_to_hosts( self._account, sid, self.send_success_connect_reply, None) raise nbxmpp.NodeProcessed else: log.warning('Gajim got streamhosts for unknown transfer. ' 'Ignoring it.') raise nbxmpp.NodeProcessed file_props.streamhosts = streamhosts def _connection_error(sid): self._connect_error(sid, 'item-not-found', 'cancel', msg='Could not connect to given hosts') if file_props.type_ == 'r': app.socks5queue.connect_to_hosts(self._account, sid, self.send_success_connect_reply, _connection_error) raise nbxmpp.NodeProcessed
def OpenStream(self, sid, to, fp, blocksize=4096): """ Start new stream. You should provide stream id 'sid', the endpoint jid 'to', the file object containing info for send 'fp'. Also the desired blocksize can be specified. Take into account that recommended stanza size is 4k and IBB uses base64 encoding that increases size of data by 1/3. """ file_props = FilesProp.getFilePropBySid(sid) file_props.direction = '>' file_props.block_size = blocksize file_props.fp = fp file_props.seq = 0 file_props.error = 0 file_props.paused = False file_props.received_len = 0 file_props.last_time = time.time() file_props.connected = True file_props.completed = False file_props.disconnect_cb = None file_props.continue_cb = None syn = nbxmpp.Protocol('iq', to, 'set', payload=[ nbxmpp.Node( nbxmpp.NS_IBB + ' open', { 'sid': file_props.transport_sid, 'block-size': blocksize, 'stanza': 'iq' }) ]) self.connection.send(syn) file_props.syn_id = syn.getID() return file_props
def IBBIqHandler(self, conn, stanza): """ Handles streams state change. Used internally. """ typ = stanza.getType() log.debug('IBBIqHandler called typ->%s' % typ) if typ == 'set' and stanza.getTag('open'): self.StreamOpenHandler(conn, stanza) elif typ == 'set' and stanza.getTag('close'): self.StreamCloseHandler(conn, stanza) elif typ == 'set' and stanza.getTag('data'): sid = stanza.getTagAttr('data', 'sid') file_props = FilesProp.getFilePropByTransportSid(self.name, sid) if not file_props: conn.send(nbxmpp.Error(stanza, nbxmpp.ERR_ITEM_NOT_FOUND)) elif file_props.connected and self.IBBMessageHandler(conn, stanza): reply = stanza.buildReply('result') reply.delChild('data') conn.send(reply) elif not file_props.connected: log.debug('Received IQ for closed filetransfer, IQ dropped') elif typ == 'error': app.socks5queue.error_cb() else: conn.send(nbxmpp.Error(stanza, nbxmpp.ERR_BAD_REQUEST)) raise nbxmpp.NodeProcessed
def _connect_error(self, sid, error, error_type, msg=None): """ Called when there is an error establishing BS connection, or when connection is rejected """ if not self.connection or self.connected < 2: return file_props = FilesProp.getFileProp(self.name, sid) if file_props is None: log.error('can not send iq error on failed transfer') return if file_props.type_ == 's': to = file_props.receiver else: to = file_props.sender iq = nbxmpp.Iq(to=to, typ='error') iq.setAttr('id', file_props.request_id) err = iq.setTag('error') err.setAttr('type', error_type) err.setTag(error, namespace=nbxmpp.NS_STANZAS) self.connection.send(iq) if msg: self.disconnect_transfer(file_props) file_props.error = -3 from gajim.common.connection_handlers_events import \ FileRequestErrorEvent app.nec.push_incoming_event( FileRequestErrorEvent(None, conn=self, jid=to, file_props=file_props, error_msg=msg))
def _result_socks5_sid(self, sid, hash_id): """ Store the result of SHA message from auth """ file_props = FilesProp.getFilePropBySid(sid) file_props.hash_ = hash_id return
def _siResultCB(self, con, iq_obj): file_props = FilesProp.getFileProp(self.name, iq_obj.getAttr('id')) if not file_props: return if file_props.request_id: # we have already sent streamhosts info return file_props.receiver = self._ft_get_from(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() != nbxmpp.NS_FEATURE: return form_tag = feature.getTag('x') form = nbxmpp.DataForm(node=form_tag) field = form.getField('stream-method') if field.getValue() == nbxmpp.NS_BYTESTREAM: self._send_socks5_info(file_props) raise nbxmpp.NodeProcessed if field.getValue() == nbxmpp.NS_IBB: sid = file_props.sid file_props.transport_sid = sid fp = open(file_props.file_name, 'rb') self.OpenStream(sid, file_props.receiver, fp) raise nbxmpp.NodeProcessed
def on_yes(dummy, fjid, file_props, account): # Delete old file os.remove(file_props.file_name) jid, resource = app.get_room_and_nick_from_fjid(fjid) if resource: contact = app.contacts.get_contact(account, jid, resource) else: contact = app.contacts.get_contact_with_highest_priority( account, jid) fjid = contact.get_full_jid() # Request the file to the sender sid = helpers.get_random_string() new_file_props = FilesProp.getNewFileProp(account, sid) new_file_props.file_name = file_props.file_name new_file_props.name = file_props.name new_file_props.desc = file_props.desc new_file_props.size = file_props.size new_file_props.date = file_props.date new_file_props.hash_ = file_props.hash_ new_file_props.type_ = 'r' tsid = app.connections[account].get_module( 'Jingle').start_file_transfer(fjid, new_file_props, True) new_file_props.transport_sid = tsid self.add_transfer(account, contact, new_file_props)
def get_send_file_props(self, account, contact, file_path, file_name, file_desc=''): """ Create new file_props object and set initial file transfer properties in it """ if os.path.isfile(file_path): stat = os.stat(file_path) else: ErrorDialog(_('Invalid File'), _('File: ') + file_path) return None if stat[6] == 0: ErrorDialog(_('Invalid File'), _('It is not possible to send empty files')) return None file_props = FilesProp.getNewFileProp( account, sid=helpers.get_random_string_16()) mod_date = os.path.getmtime(file_path) file_props.file_name = file_path file_props.name = file_name file_props.date = self.__convert_date(mod_date) file_props.type_ = 's' file_props.desc = file_desc file_props.elapsed_time = 0 file_props.size = stat[6] file_props.sender = account file_props.receiver = contact file_props.tt_account = account return file_props
def _connect_error(self, sid, error, error_type, msg=None): """ Called when there is an error establishing BS connection, or when connection is rejected """ if not app.account_is_connected(self._account): return file_props = FilesProp.getFileProp(self._account, sid) if file_props is None: log.error('can not send iq error on failed transfer') return if file_props.type_ == 's': to = file_props.receiver else: to = file_props.sender iq = nbxmpp.Iq(to=to, typ='error') iq.setAttr('id', file_props.request_id) err = iq.setTag('error') err.setAttr('type', error_type) err.setTag(error, namespace=nbxmpp.NS_STANZAS) self._con.connection.send(iq) if msg: self.disconnect_transfer(file_props) file_props.error = -3 app.nec.push_incoming_event( NetworkEvent('file-request-error', conn=self._con, jid=app.get_jid_without_resource(to), file_props=file_props, error_msg=msg))
def _query_tooltip(self, widget, x_pos, y_pos, keyboard_mode, tooltip): try: x_pos, y_pos = widget.convert_widget_to_bin_window_coords( x_pos, y_pos) row = widget.get_path_at_pos(x_pos, y_pos)[0] except TypeError: self.tooltip.clear_tooltip() return False if not row: self.tooltip.clear_tooltip() return False iter_ = None try: model = widget.get_model() iter_ = model.get_iter(row) except Exception: self.tooltip.clear_tooltip() return False sid = self.model[iter_][Column.SID] file_props = FilesProp.getFilePropByType(sid[0], sid[1:]) value, widget = self.tooltip.get_tooltip(file_props, sid) tooltip.set_custom(widget) return value
def on_remove_menuitem_activate(self, widget): selected = self.tree.get_selection().get_selected() if not selected or not selected[1]: return s_iter = selected[1] sid = self.model[s_iter][Column.SID] file_props = FilesProp.getFilePropByType(sid[0], sid[1:]) self._remove_transfer(s_iter, sid, file_props) self.set_all_insensitive()
def disconnect(self, connection): if self.host_tester: self.host_tester.disconnect() FilesProp.deleteFileProp(self.host_tester.file_props) self.host_tester = None if self.receiver_tester: self.receiver_tester.disconnect() FilesProp.deleteFileProp(self.receiver_tester.file_props) self.receiver_tester = None try: self.connections.remove(connection) except ValueError: pass if connection == self.active_connection: self.active_connection = None if self.state != S_FINISHED: self.state = S_INITIAL self.try_next_connection()
def on_cleanup_button_clicked(self, widget): i = len(self.model) - 1 while i >= 0: iter_ = self.model.get_iter((i)) sid = self.model[iter_][Column.SID] file_props = FilesProp.getFilePropByType(sid[0], sid[1:]) if is_transfer_stopped(file_props): self._remove_transfer(iter_, sid, file_props) i -= 1 self.tree.get_selection().unselect_all() self.set_all_insensitive()
def on_open_folder_menuitem_activate(self, widget): selected = self.tree.get_selection().get_selected() if not selected or not selected[1]: return s_iter = selected[1] sid = self.model[s_iter][Column.SID] file_props = FilesProp.getFilePropByType(sid[0], sid[1:]) if not file_props.file_name: return path = os.path.split(file_props.file_name)[0] if os.path.exists(path) and os.path.isdir(path): helpers.launch_file_manager(path)
def _iq_error_received(self, _con, _stanza, properties): self._log.info('Error: %s', properties.error) if properties.error.condition in ('jid-malformed', 'forbidden', 'not-acceptable'): sid = self._get_sid(properties.id) file_props = FilesProp.getFileProp(self._account, sid) if file_props: if properties.error.condition == 'jid-malformed': file_props.error = -3 else: file_props.error = -4 app.nec.push_incoming_event( NetworkEvent('file-request-error', conn=self._con, jid=properties.jid.getBare(), file_props=file_props, error_msg=to_user_string(properties.error))) self._con.get_module('Bytestream').disconnect_transfer( file_props) raise nbxmpp.NodeProcessed if properties.error.condition == 'item-not-found': sid = self._get_sid(properties.id) file_props = FilesProp.getFileProp(self._account, sid) if file_props: app.nec.push_incoming_event( NetworkEvent('file-send-error', account=self._account, jid=str(properties.jid), file_props=file_props)) self._con.get_module('Bytestream').disconnect_transfer( file_props) raise nbxmpp.NodeProcessed app.nec.push_incoming_event( NetworkEvent('iq-error-received', account=self._account, properties=properties)) raise nbxmpp.NodeProcessed
def _iq_error_received(self, _con, _stanza, properties): self._log.info('Error: %s', properties.error) if properties.error.type in (Error.JID_MALFORMED, Error.FORBIDDEN, Error.NOT_ACCEPTABLE): sid = self._get_sid(properties.id) file_props = FilesProp.getFileProp(self._account, sid) if file_props: if properties.error.type == Error.JID_MALFORMED: file_props.error = -3 else: file_props.error = -4 app.nec.push_incoming_event( NetworkEvent('file-request-error', conn=self._con, jid=properties.jid.getBare(), file_props=file_props, error_msg=properties.error.message)) self._con.get_module('Bytestream').disconnect_transfer(file_props) raise nbxmpp.NodeProcessed if properties.error.type == Error.ITEM_NOT_FOUND: sid = self._get_sid(properties.id) file_props = FilesProp.getFileProp(self._account, sid) if file_props: app.nec.push_incoming_event( NetworkEvent('file-send-error', account=self._account, jid=str(properties.jid), file_props=file_props)) self._con.get_module('Bytestream').disconnect_transfer(file_props) raise nbxmpp.NodeProcessed app.nec.push_incoming_event( NetworkEvent('iq-error-received', account=self._account, properties=properties)) raise nbxmpp.NodeProcessed
def _bytestreamErrorCB(self, con, iq_obj): id_ = iq_obj.getAttr('id') frm = helpers.get_full_jid_from_iq(iq_obj) query = iq_obj.getTag('query') app.proxy65_manager.error_cb(frm, query) jid = helpers.get_jid_from_iq(iq_obj) id_ = id_[3:] file_props = FilesProp.getFilePropBySid(id_) if not file_props: return file_props.error = -4 from gajim.common.connection_handlers_events import FileRequestErrorEvent app.nec.push_incoming_event(FileRequestErrorEvent(None, conn=self._con, jid=jid, file_props=file_props, error_msg='')) raise nbxmpp.NodeProcessed
def IBBMessageHandler(self, conn, stanza): """ Receive next portion of incoming datastream and store it write it to temporary file. Used internally. """ sid = stanza.getTagAttr('data', 'sid') seq = stanza.getTagAttr('data', 'seq') data = stanza.getTagData('data') log.debug('ReceiveHandler called sid->%s seq->%s' % (sid, seq)) try: seq = int(seq) data = base64.b64decode(data.encode('utf-8')) except Exception: seq = '' data = b'' err = None file_props = FilesProp.getFilePropByTransportSid(self.name, sid) if file_props is None: err = nbxmpp.ERR_ITEM_NOT_FOUND else: if not data: err = nbxmpp.ERR_BAD_REQUEST elif seq != file_props.seq: err = nbxmpp.ERR_UNEXPECTED_REQUEST else: log.debug('Successfully received sid->%s %s+%s bytes' % (sid, file_props.fp.tell(), len(data))) file_props.seq += 1 file_props.started = True file_props.fp.write(data) current_time = time.time() file_props.elapsed_time += current_time - file_props.last_time file_props.last_time = current_time file_props.received_len += len(data) app.socks5queue.progress_transfer_cb(self.name, file_props) if file_props.received_len >= file_props.size: file_props.completed = True if err: log.debug('Error on receive: %s' % err) conn.send( nbxmpp.Error(nbxmpp.Iq( to=stanza.getFrom(), frm=stanza.getTo(), payload=[nbxmpp.Node(nbxmpp.NS_IBB + ' close')]), err, reply=0)) else: return True
def _proxy_auth_ok(self, proxy): """ Called after authentication to proxy server """ if not app.account_is_connected(self._account): return file_props = FilesProp.getFileProp(self._account, proxy['sid']) iq = nbxmpp.Iq(to=proxy['initiator'], typ='set') auth_id = "au_" + proxy['sid'] iq.setID(auth_id) query = iq.setTag('query', namespace=nbxmpp.NS_BYTESTREAM) query.setAttr('sid', proxy['sid']) activate = query.setTag('activate') activate.setData(file_props.proxy_receiver) iq.setID(auth_id) self._con.connection.send(iq)
def on_cancel_button_clicked(self, widget): selected = self.tree.get_selection().get_selected() if selected is None or selected[1] is None: return s_iter = selected[1] sid = self.model[s_iter][Column.SID] file_props = FilesProp.getFilePropByType(sid[0], sid[1:]) account = file_props.tt_account if account not in app.connections: return con = app.connections[account] # Check if we are in a IBB transfer if file_props.direction: con.CloseIBBStream(file_props) con.disconnect_transfer(file_props) self.set_status(file_props, 'stop')
def _on_result(self, _con, iq_obj): # if we want to respect xep-0065 we have to check for proxy # activation result in any result iq real_id = iq_obj.getAttr('id') if real_id is None: log.warning('Invalid IQ without id attribute:\n%s', iq_obj) raise nbxmpp.NodeProcessed if real_id is None or not real_id.startswith('au_'): return frm = self._ft_get_from(iq_obj) id_ = real_id[3:] file_props = FilesProp.getFilePropByTransportSid(self._account, id_) if file_props.streamhost_used: for host in file_props.proxyhosts: if host['initiator'] == frm and 'idx' in host: app.socks5queue.activate_proxy(host['idx']) raise nbxmpp.NodeProcessed
def _siErrorCB(self, con, iq_obj): si = iq_obj.getTag('si') profile = si.getAttr('profile') if profile != nbxmpp.NS_FILE: return file_props = FilesProp.getFileProp(self.name, iq_obj.getAttr('id')) if not file_props: return jid = self._ft_get_from(iq_obj) file_props.error = -3 from gajim.common.connection_handlers_events import FileRequestErrorEvent app.nec.push_incoming_event( FileRequestErrorEvent(None, conn=self, jid=jid, file_props=file_props, error_msg='')) raise nbxmpp.NodeProcessed
def _on_bytestream_error(self, _con, iq_obj): id_ = iq_obj.getAttr('id') frm = helpers.get_full_jid_from_iq(iq_obj) query = iq_obj.getTag('query') app.proxy65_manager.error_cb(frm, query) jid = helpers.get_jid_from_iq(iq_obj) id_ = id_[3:] file_props = FilesProp.getFilePropBySid(id_) if not file_props: return file_props.error = -4 app.nec.push_incoming_event( NetworkEvent('file-request-error', conn=self._con, jid=app.get_jid_without_resource(jid), file_props=file_props, error_msg='')) raise nbxmpp.NodeProcessed
def __init__(self, host, port, jid, sid, sender_jid, on_success, on_failure): """ Try to establish and auth to proxy at (host, port) Call on_success, or on_failure according to the result. """ self.host = host self.port = port self.jid = jid self.on_success = on_success self.on_failure = on_failure self._sock = None self.file_props = FilesProp.getNewFileProp(jid, sid) self.file_props.is_a_proxy = True self.file_props.proxy_sender = sender_jid self.file_props.proxy_receiver = '[email protected]/test2' Socks5.__init__(self, app.idlequeue, host, port, None, None, None) self.sid = sid
def stop_all_active_file_transfers(self, contact): """ Stop all active transfer to or from the given contact """ for file_props in FilesProp.getAllFileProp(): if is_transfer_stopped(file_props): continue receiver_jid = file_props.receiver if contact.get_full_jid() == receiver_jid: file_props.error = -5 self.remove_transfer(file_props) from gajim.common.connection_handlers_events import \ FileRequestErrorEvent app.nec.push_incoming_event(FileRequestErrorEvent(None, conn=self._con, jid=contact.jid, file_props=file_props, error_msg='')) sender_jid = file_props.sender if contact.get_full_jid() == sender_jid: file_props.error = -3 self.remove_transfer(file_props)
def find_transfer_by_jid(self, account, jid): """ Find all transfers with peer 'jid' that belong to 'account' """ active_transfers = [[], []] # ['senders', 'receivers'] allfp = FilesProp.getAllFileProp() for file_props in allfp: if file_props.type_ == 's' and file_props.tt_account == account: # 'account' is the sender receiver_jid = file_props.receiver.split('/')[0] if jid == receiver_jid and not is_transfer_stopped(file_props): active_transfers[0].append(file_props) elif file_props.type_ == 'r' and file_props.tt_account == account: # 'account' is the recipient sender_jid = file_props.sender.split('/')[0] if jid == sender_jid and not is_transfer_stopped(file_props): active_transfers[1].append(file_props) else: raise Exception('file_props has no type') return active_transfers
def stop_all_active_file_transfers(self, contact): """ Stop all active transfer to or from the given contact """ for file_props in FilesProp.getAllFileProp(): if is_transfer_stopped(file_props): continue receiver_jid = file_props.receiver if contact.get_full_jid() == receiver_jid: file_props.error = -5 self.remove_transfer(file_props) app.nec.push_incoming_event( NetworkEvent('file-request-error', conn=self._con, jid=app.get_jid_without_resource(contact.jid), file_props=file_props, error_msg='')) sender_jid = file_props.sender if contact.get_full_jid() == sender_jid: file_props.error = -3 self.remove_transfer(file_props)
def on_pause_restore_button_clicked(self, widget): selected = self.tree.get_selection().get_selected() if selected is None or selected[1] is None: return s_iter = selected[1] sid = self.model[s_iter][Column.SID] file_props = FilesProp.getFilePropByType(sid[0], sid[1:]) if is_transfer_paused(file_props): file_props.last_time = time.time() file_props.paused = False types = {'r': 'download', 's': 'upload'} self.set_status(file_props, types[sid[0]]) self.toggle_pause_continue(True) if file_props.continue_cb: file_props.continue_cb() elif is_transfer_active(file_props): file_props.paused = True self.set_status(file_props, 'pause') # reset that to compute speed only when we resume file_props.transfered_size = [] self.toggle_pause_continue(False)