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 gajim.connections: # there is a connection to the account gajim.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 = gajim.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 gajim.events.get_events(account, jid, [ev_type]): if event.file_props.sid == file_props.sid: gajim.events.remove_events(account, jid, event) gajim.interface.roster.draw_contact(jid, account) gajim.interface.roster.show_title() FilesProp.deleteFileProp(file_props) del(file_props)
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 gajim.connections: # there is a connection to the account gajim.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 = gajim.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 gajim.events.get_events(account, jid, [ev_type]): if event.parameters.sid == file_props.sid: gajim.events.remove_events(account, jid, event) gajim.interface.roster.draw_contact(jid, account) gajim.interface.roster.show_title() FilesProp.deleteFileProp(file_props) del(file_props)
def _bytestreamSetCB(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.name, 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 gajim.socks5queue.connect_to_hosts( self.name, 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': gajim.socks5queue.connect_to_hosts(self.name, sid, self.send_success_connect_reply, _connection_error) raise nbxmpp.NodeProcessed
def _bytestreamSetCB(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.name, 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 gajim.socks5queue.connect_to_hosts(self.name, 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': gajim.socks5queue.connect_to_hosts(self.name, sid, self.send_success_connect_reply, _connection_error) raise nbxmpp.NodeProcessed
def _connect_error(self,sid, code=404): """ 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 msg_dict = { 404: 'Could not connect to given hosts', 405: 'Cancel', 406: 'Not acceptable', } msg = msg_dict[code] 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.sid) err = iq.setTag('error') err.setAttr('code', unicode(code)) err.setData(msg) self.connection.send(iq) if code == 404: self.disconnect_transfer(file_props) file_props.error = -3 from common.connection_handlers_events import \ FileRequestErrorEvent gajim.nec.push_incoming_event(FileRequestErrorEvent(None, conn=self, jid=to, file_props=file_props, error_msg=msg))
def OpenStream(self, sid, to, fp, blocksize=4096): """ Start new stream. You should provide stream id 'sid', the endpoind 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. """ if not nbxmpp.JID(to).getResource(): return file_props = FilesProp.getFilePropBySid(sid) file_props.direction = '|>' + to 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 _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 common.connection_handlers_events import \ FileRequestErrorEvent gajim.nec.push_incoming_event(FileRequestErrorEvent(None, conn=self, jid=to, file_props=file_props, error_msg=msg))
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, 'r') 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 = gajim.get_room_and_nick_from_fjid(fjid) if resource: contact = gajim.contacts.get_contact(account, jid, resource) else: contact = gajim.contacts.get_contact_with_highest_priority( account, jid) fjid = contact.get_full_jid() # Request the file to the sender sid = helpers.get_random_string_16() 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 = gajim.connections[account].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: dialogs.ErrorDialog(_('Invalid File'), _('File: ') + file_path) return None if stat[6] == 0: dialogs.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 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 common.connection_handlers_events import \ FileRequestErrorEvent gajim.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 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 SendHandler(self): """ Send next portion of data if it is time to do it. Used internally. """ log.debug('SendHandler called') for file_props in FilesProp.getAllFileProp(): if not file_props.direction: # it's socks5 bytestream continue sid = file_props.sid if file_props.direction[:2] == '|>': # We waitthat other part accept stream continue if file_props.direction[0] == '>': if file_props.paused: continue if not file_props.connected: #TODO: Reply with out of order error continue chunk = file_props.fp.read(file_props.block_size) if chunk: datanode = nbxmpp.Node( nbxmpp.NS_IBB + ' data', { 'sid': file_props.transport_sid, 'seq': file_props.seq }, base64.b64encode( chunk.encode('utf-8')).decode('utf-8')) file_props.seq += 1 file_props.started = True if file_props.seq == 65536: file_props.seq = 0 self.last_sent_ibb_id = self.connection.send( nbxmpp.Protocol(name='iq', to=file_props.direction[1:], typ='set', payload=[datanode])) 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(chunk) gajim.socks5queue.progress_transfer_cb( self.name, file_props) else: # notify the other side about stream closing # notify the local user about sucessfull send # delete the local stream self.connection.send( nbxmpp.Protocol( 'iq', file_props.direction[1:], 'set', payload=[ nbxmpp.Node(nbxmpp.NS_IBB + ' close', {'sid': file_props.transport_sid}) ])) file_props.completed = True
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][C_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 IBBAllIqHandler(self, conn, stanza): """ Handle remote side reply about if it agree or not to receive our datastream. Used internally. Raises xmpppy event specfiying if the data transfer is agreed upon. """ syn_id = stanza.getID() log.debug('IBBAllIqHandler called syn_id->%s' % syn_id) for file_props in FilesProp.getAllFileProp(): if not file_props.direction or not file_props.connected: # It's socks5 bytestream # Or we closed the IBB stream continue if file_props.syn_id == syn_id: if stanza.getType() == 'error': if file_props.direction[0] == '<': conn.Event('IBB', 'ERROR ON RECEIVE', file_props) else: conn.Event('IBB', 'ERROR ON SEND', file_props) elif stanza.getType() == 'result': if file_props.direction[0] == '|': file_props.direction = file_props.direction[1:] self.SendHandler() else: conn.send( nbxmpp.Error(stanza, nbxmpp.ERR_UNEXPECTED_REQUEST)) break else: if stanza.getTag('data'): sid = stanza.getTagAttr('data', 'sid') file_props = FilesProp.getFilePropByTransportSid( self.name, sid) if file_props.connected and self.IBBMessageHandler( conn, stanza): reply = stanza.buildReply('result') reply.delChild('data') conn.send(reply) raise nbxmpp.NodeProcessed elif syn_id == self.last_sent_ibb_id: self.SendHandler()
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_][C_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_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][C_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 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 IBBAllIqHandler(self, conn, stanza): """ Handle remote side reply about if it agree or not to receive our datastream. Used internally. Raises xmpppy event specfiying if the data transfer is agreed upon. """ syn_id = stanza.getID() log.debug('IBBAllIqHandler called syn_id->%s' % syn_id) for file_props in FilesProp.getAllFileProp(): if not file_props.direction or not file_props.connected: # It's socks5 bytestream # Or we closed the IBB stream continue if file_props.syn_id == syn_id: if stanza.getType() == 'error': if file_props.direction[0] == '<': conn.Event('IBB', 'ERROR ON RECEIVE', file_props) else: conn.Event('IBB', 'ERROR ON SEND', file_props) elif stanza.getType() == 'result': if file_props.direction[0] == '|': file_props.direction = file_props.direction[1:] self.SendHandler() else: conn.send(nbxmpp.Error(stanza, nbxmpp.ERR_UNEXPECTED_REQUEST)) break else: if stanza.getTag('data'): sid = stanza.getTagAttr('data', 'sid') file_props = FilesProp.getFilePropByTransportSid(self.name, sid) if file_props.connected and self.IBBMessageHandler(conn, stanza): reply = stanza.buildReply('result') reply.delChild('data') conn.send(reply) raise nbxmpp.NodeProcessed elif syn_id == self.last_sent_ibb_id: self.SendHandler()
def _ResultCB(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 = unicode(iq_obj.getAttr('id')) if not real_id.startswith('au_'): return frm = self._ft_get_from(iq_obj) id_ = real_id[3:] file_props = FilesProp.getFilePropBySid(id_) if file_props.streamhost_used: for host in file_props.proxyhosts: if host['initiator'] == frm and 'idx' in host: gajim.socks5queue.activate_proxy(host['idx']) raise nbxmpp.NodeProcessed
def _ResultCB(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 not real_id.startswith('au_'): return frm = self._ft_get_from(iq_obj) id_ = real_id[3:] file_props = FilesProp.getFilePropBySid(id_) if file_props.streamhost_used: for host in file_props.proxyhosts: if host['initiator'] == frm and 'idx' in host: gajim.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 common.connection_handlers_events import FileRequestErrorEvent gajim.nec.push_incoming_event(FileRequestErrorEvent(None, conn=self, jid=jid, file_props=file_props, error_msg='')) raise nbxmpp.NodeProcessed
def _bytestreamErrorCB(self, con, iq_obj): id_ = unicode(iq_obj.getAttr('id')) frm = helpers.get_full_jid_from_iq(iq_obj) query = iq_obj.getTag('query') gajim.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 common.connection_handlers_events import FileRequestErrorEvent gajim.nec.push_incoming_event(FileRequestErrorEvent(None, conn=self, jid=jid, file_props=file_props, error_msg='')) 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') gajim.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 common.connection_handlers_events import FileRequestErrorEvent gajim.nec.push_incoming_event(FileRequestErrorEvent(None, conn=self, 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')).decode('utf-8') except Exception: seq = '' data = '' 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('Successfull receive 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) gajim.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 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][C_SID] file_props = FilesProp.getFilePropByType(sid[0], sid[1:]) account = file_props.tt_account if account not in gajim.connections: return con = gajim.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 _proxy_auth_ok(self, proxy): """ Called after authentication to proxy server """ if not self.connection or self.connected < 2: return file_props = FilesProp.getFileProp(self.name, 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.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 gajim.connections: return con = gajim.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 SendHandler(self): """ Send next portion of data if it is time to do it. Used internally. """ log.debug('SendHandler called') for file_props in FilesProp.getAllFileProp(): if not file_props.direction: # it's socks5 bytestream continue sid = file_props.sid if file_props.direction[:2] == '|>': # We waitthat other part accept stream continue if file_props.direction[0] == '>': if file_props.paused: continue if not file_props.connected: #TODO: Reply with out of order error continue chunk = file_props.fp.read(file_props.block_size) if chunk: datanode = nbxmpp.Node(nbxmpp.NS_IBB + ' data', { 'sid': file_props.transport_sid, 'seq': file_props.seq}, base64.b64encode(chunk.encode( 'utf-8')).decode('utf-8')) file_props.seq += 1 file_props.started = True if file_props.seq == 65536: file_props.seq = 0 self.last_sent_ibb_id = self.connection.send( nbxmpp.Protocol(name='iq', to=file_props.direction[1:], typ='set', payload=[datanode])) 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(chunk) gajim.socks5queue.progress_transfer_cb(self.name, file_props) else: # notify the other side about stream closing # notify the local user about sucessfull send # delete the local stream self.connection.send(nbxmpp.Protocol('iq', file_props.direction[1:], 'set', payload=[nbxmpp.Node(nbxmpp.NS_IBB + ' close', {'sid': file_props.transport_sid})])) file_props.completed = True
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, gajim.idlequeue, host, port, None, None, None) self.sid = sid
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.decodestring(data) except Exception: seq = '' data = '' 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('Successfull receive 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) gajim.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 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) from common.connection_handlers_events import \ FileRequestErrorEvent gajim.nec.push_incoming_event(FileRequestErrorEvent(None, conn=self, 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 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 = unicode(file_props.receiver) if contact.get_full_jid() == receiver_jid: file_props.error = -5 self.remove_transfer(file_props) from common.connection_handlers_events import \ FileRequestErrorEvent gajim.nec.push_incoming_event(FileRequestErrorEvent(None, conn=self, jid=contact.jid, file_props=file_props, error_msg='')) sender_jid = unicode(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][C_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)
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)
def StreamCloseHandler(self, conn, stanza): """ Handle stream closure due to all data transmitted. Raise xmpppy event specifying successfull data receive. """ sid = stanza.getTagAttr('close', 'sid') log.debug('StreamCloseHandler called sid->%s' % sid) # look in sending files file_props = FilesProp.getFilePropByTransportSid(self.name, sid) if file_props: reply = stanza.buildReply('result') reply.delChild('close') conn.send(reply) # look in receiving files file_props.fp.close() file_props.completed = file_props.received_len >= file_props.size if not file_props.completed: file_props.error = -1 gajim.socks5queue.complete_transfer_cb(self.name, file_props) else: conn.send(nbxmpp.Error(stanza, nbxmpp.ERR_ITEM_NOT_FOUND))
def show_tooltip(self, widget): self.tooltip.timeout = 0 if self.height_diff == 0: self.tooltip.hide_tooltip() return pointer = self.tree.get_pointer() props = self.tree.get_path_at_pos(pointer[0], pointer[1] - self.height_diff) # check if the current pointer is at the same path # as it was before setting the timeout if props and self.tooltip.id == props[0]: iter_ = self.model.get_iter(props[0]) sid = self.model[iter_][C_SID].decode('utf-8') file_props = FilesProp.getFilePropByType(sid[0], sid[1:]) # bounding rectangle of coordinates for the cell within the treeview rect = self.tree.get_cell_area(props[0], props[1]) # position of the treeview on the screen position = widget.window.get_origin() self.tooltip.show_tooltip(file_props, rect.height, position[1] + rect.y + self.height_diff) else: self.tooltip.hide_tooltip()
def on_transfers_list_motion_notify_event(self, widget, event): pointer = self.tree.get_pointer() props = widget.get_path_at_pos(int(event.x), int(event.y)) self.height_diff = pointer[1] - int(event.y) if self.tooltip.timeout > 0 or self.tooltip.shown: if not props or self.tooltip.id != props[0]: self.tooltip.hide_tooltip() if props: row = props[0] iter_ = None try: iter_ = self.model.get_iter(row) except Exception: self.tooltip.hide_tooltip() return sid = self.model[iter_][C_SID].decode('utf-8') file_props = FilesProp.getFilePropByType(sid[0], sid[1:]) if file_props is not None: if self.tooltip.timeout == 0 or self.tooltip.id != props[0]: self.tooltip.id = row self.tooltip.timeout = gobject.timeout_add(500, self.show_tooltip, widget)
def StreamOpenHandler(self, conn, stanza): """ Handles opening of new incoming stream. Used internally. """ err = None sid = stanza.getTagAttr('open', 'sid') blocksize = stanza.getTagAttr('open', 'block-size') log.debug('StreamOpenHandler called sid->%s blocksize->%s' % (sid, blocksize)) file_props = FilesProp.getFilePropByTransportSid(self.name, sid) try: blocksize = int(blocksize) except: err = nbxmpp.ERR_BAD_REQUEST if not sid or not blocksize: err = nbxmpp.ERR_BAD_REQUEST elif not file_props: err = nbxmpp.ERR_UNEXPECTED_REQUEST if err: rep = nbxmpp.Error(stanza, err) else: log.debug("Opening stream: id %s, block-size %s" % (sid, blocksize)) rep = nbxmpp.Protocol('iq', stanza.getFrom(), 'result', stanza.getTo(), {'id': stanza.getID()}) file_props.block_size = blocksize 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, 'w') conn.send(rep)
def set_buttons_sensitive(self, path, is_row_selected): """ Make buttons/menuitems sensitive as appropriate to the state of file transfer located at path 'path' """ if path is None: self.set_all_insensitive() return current_iter = self.model.get_iter(path) sid = self.model[current_iter][C_SID] file_props = FilesProp.getFilePropByType(sid[0], sid[1:]) self.remove_menuitem.set_sensitive(is_row_selected) self.open_folder_menuitem.set_sensitive(is_row_selected) is_stopped = False if is_transfer_stopped(file_props): is_stopped = True self.cancel_button.set_sensitive(not is_stopped) self.cancel_menuitem.set_sensitive(not is_stopped) if not is_row_selected: # no selection, disable the buttons self.set_all_insensitive() elif not is_stopped: if is_transfer_active(file_props): # file transfer is active self.toggle_pause_continue(True) self.pause_button.set_sensitive(True) elif is_transfer_paused(file_props): # file transfer is paused self.toggle_pause_continue(False) self.pause_button.set_sensitive(True) else: self.pause_button.set_sensitive(False) self.pause_menuitem.set_sensitive(False) self.continue_menuitem.set_sensitive(False) else: self.pause_button.set_sensitive(False) self.pause_menuitem.set_sensitive(False) self.continue_menuitem.set_sensitive(False) return True
def set_buttons_sensitive(self, path, is_row_selected): """ Make buttons/menuitems sensitive as appropriate to the state of file transfer located at path 'path' """ if path is None: self.set_all_insensitive() return current_iter = self.model.get_iter(path) sid = self.model[current_iter][Column.SID] file_props = FilesProp.getFilePropByType(sid[0], sid[1:]) self.remove_menuitem.set_sensitive(is_row_selected) self.open_folder_menuitem.set_sensitive(is_row_selected) is_stopped = False if is_transfer_stopped(file_props): is_stopped = True self.cancel_button.set_sensitive(not is_stopped) self.cancel_menuitem.set_sensitive(not is_stopped) if not is_row_selected: # no selection, disable the buttons self.set_all_insensitive() elif not is_stopped: if is_transfer_active(file_props): # file transfer is active self.toggle_pause_continue(True) self.pause_button.set_sensitive(True) elif is_transfer_paused(file_props): # file transfer is paused self.toggle_pause_continue(False) self.pause_button.set_sensitive(True) else: self.pause_button.set_sensitive(False) self.pause_menuitem.set_sensitive(False) self.continue_menuitem.set_sensitive(False) else: self.pause_button.set_sensitive(False) self.pause_menuitem.set_sensitive(False) self.continue_menuitem.set_sensitive(False) return True
def show_tooltip(self, widget): self.tooltip.timeout = 0 if self.height_diff == 0: self.tooltip.hide_tooltip() return w = self.tree.get_window() device = w.get_display().get_device_manager().get_client_pointer() pointer = w.get_device_position(device) props = self.tree.get_path_at_pos(pointer[1], pointer[2] - self.height_diff) # check if the current pointer is at the same path # as it was before setting the timeout if props and self.tooltip.id == props[0]: iter_ = self.model.get_iter(props[0]) sid = self.model[iter_][Column.SID] file_props = FilesProp.getFilePropByType(sid[0], sid[1:]) # bounding rectangle of coordinates for the cell within the treeview rect = self.tree.get_cell_area(props[0], props[1]) # position of the treeview on the screen position = widget.get_window().get_origin()[1:] self.tooltip.show_tooltip(file_props, rect.height, position[1] + rect.y + self.height_diff) else: self.tooltip.hide_tooltip()
def on_download_clicked(self, widget, data=None): tree, row = self.tv_search.get_selection().get_selected() path = tree.get_path(row) file_info = self.brw_file_info[path] fjid = self.get_contact_from_iter(tree, row) # Request the file file_path = os.path.join(self.plugin.config['incoming_dir'], file_info[0]) sid = helpers.get_random_string_16() new_file_props = FilesProp.getNewFileProp(self.account, sid) new_file_props.file_name = file_path print file_path new_file_props.name = file_info[0] new_file_props.desc = file_info[4] new_file_props.size = file_info[2] new_file_props.date = file_info[1] new_file_props.hash_ = None if file_info[3] == '' else file_info[3] new_file_props.type_ = 'r' tsid = gajim.connections[self.account].start_file_transfer( fjid, new_file_props, True) new_file_props.transport_sid = tsid ft_window = gajim.interface.instances['file_transfers'] contact = gajim.contacts.get_contact_from_full_jid(self.account, fjid) ft_window.add_transfer(self.account, contact, new_file_props)
def on_transfers_list_motion_notify_event(self, widget, event): w = self.tree.get_window() device = w.get_display().get_device_manager().get_client_pointer() pointer = w.get_device_position(device) props = widget.get_path_at_pos(int(event.x), int(event.y)) self.height_diff = pointer[2] - int(event.y) if self.tooltip.timeout > 0 or self.tooltip.shown: if not props or self.tooltip.id != props[0]: self.tooltip.hide_tooltip() if props: row = props[0] iter_ = None try: iter_ = self.model.get_iter(row) except Exception: self.tooltip.hide_tooltip() return sid = self.model[iter_][Column.SID] file_props = FilesProp.getFilePropByType(sid[0], sid[1:]) if file_props is not None: if self.tooltip.timeout == 0 or self.tooltip.id != props[0]: self.tooltip.id = row self.tooltip.timeout = GLib.timeout_add(500, self.show_tooltip, widget)