Daniel Brötzmann pushed to branch master at gajim / gajim
Commits:
-
da837340
by wurstsalat at 2022-05-23T01:33:37+02:00
-
ddc4e211
by wurstsalat at 2022-05-23T01:33:37+02:00
-
f2459751
by wurstsalat at 2022-05-23T01:33:37+02:00
-
3429c7bf
by wurstsalat at 2022-05-23T01:33:37+02:00
-
27173321
by wurstsalat at 2022-05-23T01:33:37+02:00
-
d129668a
by wurstsalat at 2022-05-23T01:33:37+02:00
5 changed files:
- gajim/common/jingle_ft.py
- gajim/common/jingle_transport.py
- gajim/common/modules/jingle.py
- gajim/common/socks5.py
- gajim/gtk/filetransfer.py
Changes:
| ... | ... | @@ -74,13 +74,13 @@ class State(IntEnum): |
| 74 | 74 | |
| 75 | 75 | |
| 76 | 76 | class JingleFileTransfer(JingleContent):
|
| 77 | - |
|
| 78 | 77 | def __init__(self,
|
| 79 | 78 | session: JingleSession,
|
| 79 | + file_props: FileProp,
|
|
| 80 | 80 | transport: Optional[JingleTransport] = None,
|
| 81 | - file_props: Optional[FileProp] = None,
|
|
| 82 | 81 | use_security: bool = False,
|
| 83 | - senders: Optional[str] = None):
|
|
| 82 | + senders: Optional[str] = None
|
|
| 83 | + ) -> None:
|
|
| 84 | 84 | |
| 85 | 85 | JingleContent.__init__(self, session, transport, senders)
|
| 86 | 86 | log.info("transport value: %s", transport)
|
| ... | ... | @@ -99,29 +99,31 @@ def __init__(self, |
| 99 | 99 | self.callbacks['transport-reject'] += [self.__on_transport_reject]
|
| 100 | 100 | self.callbacks['transport-info'] += [self.__on_transport_info]
|
| 101 | 101 | self.callbacks['iq-result'] += [self.__on_iq_result]
|
| 102 | + |
|
| 102 | 103 | self.use_security = use_security
|
| 103 | 104 | self.x509_fingerprint = None
|
| 104 | 105 | self.file_props = file_props
|
| 105 | 106 | self.weinitiate = self.session.weinitiate
|
| 106 | 107 | self.werequest = self.session.werequest
|
| 107 | - if self.file_props is not None:
|
|
| 108 | - if self.session.werequest:
|
|
| 109 | - self.file_props.sender = self.session.peerjid
|
|
| 110 | - self.file_props.receiver = self.session.ourjid
|
|
| 111 | - else:
|
|
| 112 | - self.file_props.sender = self.session.ourjid
|
|
| 113 | - self.file_props.receiver = self.session.peerjid
|
|
| 114 | - self.file_props.session_type = 'jingle'
|
|
| 115 | - self.file_props.sid = session.sid
|
|
| 116 | - self.file_props.transfered_size = []
|
|
| 117 | - self.file_props.transport_sid = self.transport.sid
|
|
| 118 | - log.info("FT request: %s", file_props)
|
|
| 108 | + |
|
| 119 | 109 | if transport is None:
|
| 120 | 110 | self.transport = JingleTransportSocks5()
|
| 121 | 111 | self.transport.set_connection(session.connection)
|
| 122 | 112 | self.transport.set_file_props(self.file_props)
|
| 123 | 113 | self.transport.set_our_jid(session.ourjid)
|
| 124 | 114 | log.info('ourjid: %s', session.ourjid)
|
| 115 | + |
|
| 116 | + if self.session.werequest:
|
|
| 117 | + self.file_props.sender = self.session.peerjid
|
|
| 118 | + self.file_props.receiver = self.session.ourjid
|
|
| 119 | + else:
|
|
| 120 | + self.file_props.sender = self.session.ourjid
|
|
| 121 | + self.file_props.receiver = self.session.peerjid
|
|
| 122 | + self.file_props.session_type = 'jingle'
|
|
| 123 | + self.file_props.sid = session.sid
|
|
| 124 | + self.file_props.transfered_size = []
|
|
| 125 | + self.file_props.transport_sid = self.transport.sid
|
|
| 126 | + |
|
| 125 | 127 | self.session = session
|
| 126 | 128 | self.media = 'file'
|
| 127 | 129 | self.nominated_cand = {}
|
| ... | ... | @@ -16,8 +16,8 @@ |
| 16 | 16 | Handles Jingle Transports (currently only ICE-UDP)
|
| 17 | 17 | """
|
| 18 | 18 | |
| 19 | -from typing import Any # pylint: disable=unused-import
|
|
| 20 | -from typing import Dict # pylint: disable=unused-import
|
|
| 19 | +from typing import Any
|
|
| 20 | +from typing import Optional
|
|
| 21 | 21 | |
| 22 | 22 | import logging
|
| 23 | 23 | import socket
|
| ... | ... | @@ -29,11 +29,13 @@ |
| 29 | 29 | from nbxmpp.util import generate_id
|
| 30 | 30 | |
| 31 | 31 | from gajim.common import app
|
| 32 | +from gajim.common.client import Client
|
|
| 33 | +from gajim.common.file_props import FileProp
|
|
| 32 | 34 | |
| 33 | 35 | log = logging.getLogger('gajim.c.jingle_transport')
|
| 34 | 36 | |
| 37 | +transports: dict[str, Any] = {}
|
|
| 35 | 38 | |
| 36 | -transports = {} # type: Dict[str, Any]
|
|
| 37 | 39 | |
| 38 | 40 | def get_jingle_transport(node):
|
| 39 | 41 | namespace = node.getNamespace()
|
| ... | ... | @@ -59,15 +61,15 @@ class JingleTransport: |
| 59 | 61 | __slots__ = ['type_', 'candidates', 'remote_candidates', 'connection',
|
| 60 | 62 | 'file_props', 'ourjid', 'sid']
|
| 61 | 63 | |
| 62 | - def __init__(self, type_):
|
|
| 64 | + def __init__(self, type_: TransportType) -> None:
|
|
| 63 | 65 | self.type_ = type_
|
| 64 | 66 | self.candidates = []
|
| 65 | 67 | self.remote_candidates = []
|
| 66 | 68 | |
| 67 | - self.connection = None
|
|
| 68 | - self.file_props = None
|
|
| 69 | - self.ourjid = None
|
|
| 70 | - self.sid = None
|
|
| 69 | + self.connection: Optional[Client] = None
|
|
| 70 | + self.file_props: Optional[FileProp] = None
|
|
| 71 | + self.ourjid: Optional[str] = None
|
|
| 72 | + self.sid: Optional[str] = None
|
|
| 71 | 73 | |
| 72 | 74 | def _iter_candidates(self):
|
| 73 | 75 | for candidate in self.candidates:
|
| ... | ... | @@ -96,20 +98,21 @@ def parse_transport_stanza(self, transport): |
| 96 | 98 | """
|
| 97 | 99 | return []
|
| 98 | 100 | |
| 99 | - def set_connection(self, conn):
|
|
| 101 | + def set_connection(self, conn: Client) -> None:
|
|
| 100 | 102 | self.connection = conn
|
| 101 | 103 | if not self.sid:
|
| 102 | 104 | self.sid = generate_id()
|
| 103 | 105 | |
| 104 | - def set_file_props(self, file_props):
|
|
| 106 | + def set_file_props(self, file_props: FileProp) -> None:
|
|
| 105 | 107 | self.file_props = file_props
|
| 106 | 108 | |
| 107 | - def set_our_jid(self, jid):
|
|
| 109 | + def set_our_jid(self, jid: str) -> None:
|
|
| 108 | 110 | self.ourjid = jid
|
| 109 | 111 | |
| 110 | - def set_sid(self, sid):
|
|
| 112 | + def set_sid(self, sid: str) -> None:
|
|
| 111 | 113 | self.sid = sid
|
| 112 | 114 | |
| 115 | + |
|
| 113 | 116 | class JingleTransportSocks5(JingleTransport):
|
| 114 | 117 | """
|
| 115 | 118 | Socks5 transport in jingle scenario
|
| ... | ... | @@ -28,6 +28,8 @@ |
| 28 | 28 | # * config:
|
| 29 | 29 | # - codecs
|
| 30 | 30 | |
| 31 | +from typing import Optional
|
|
| 32 | + |
|
| 31 | 33 | import logging
|
| 32 | 34 | |
| 33 | 35 | import nbxmpp
|
| ... | ... | @@ -36,8 +38,8 @@ |
| 36 | 38 | |
| 37 | 39 | from gajim.common import helpers
|
| 38 | 40 | from gajim.common import jingle_xtls
|
| 41 | +from gajim.common.file_props import FileProp
|
|
| 39 | 42 | from gajim.common.modules.base import BaseModule
|
| 40 | - |
|
| 41 | 43 | from gajim.common.jingle_session import JingleSession
|
| 42 | 44 | from gajim.common.jingle_session import JingleStates
|
| 43 | 45 | from gajim.common.jingle_ft import JingleFileTransfer
|
| ... | ... | @@ -74,14 +76,14 @@ def __init__(self, con): |
| 74 | 76 | ]
|
| 75 | 77 | |
| 76 | 78 | # dictionary: sessionid => JingleSession object
|
| 77 | - self._sessions = {}
|
|
| 79 | + self._sessions: dict[str, JingleSession] = {}
|
|
| 78 | 80 | |
| 79 | 81 | # dictionary: (jid, iq stanza id) => JingleSession object,
|
| 80 | 82 | # one time callbacks
|
| 81 | 83 | self.__iq_responses = {}
|
| 82 | 84 | self.files = []
|
| 83 | 85 | |
| 84 | - def delete_jingle_session(self, sid):
|
|
| 86 | + def delete_jingle_session(self, sid: str) -> None:
|
|
| 85 | 87 | """
|
| 86 | 88 | Remove a jingle session from a jingle stanza dispatcher
|
| 87 | 89 | """
|
| ... | ... | @@ -204,7 +206,11 @@ def start_audio_video(self, jid): |
| 204 | 206 | jingle_session.start_session()
|
| 205 | 207 | return jingle_session.sid
|
| 206 | 208 | |
| 207 | - def start_file_transfer(self, jid, file_props, request=False):
|
|
| 209 | + def start_file_transfer(self,
|
|
| 210 | + jid: str,
|
|
| 211 | + file_props: FileProp,
|
|
| 212 | + request: bool = False
|
|
| 213 | + ) -> Optional[str]:
|
|
| 208 | 214 | logger.info("start file transfer with file: %s", file_props)
|
| 209 | 215 | contact = self._con.get_module('Contacts').get_contact(jid)
|
| 210 | 216 | use_security = contact.supports(Namespace.JINGLE_XTLS)
|
| ... | ... | @@ -222,7 +228,9 @@ def start_file_transfer(self, jid, file_props, request=False): |
| 222 | 228 | elif contact.supports(Namespace.JINGLE_IBB):
|
| 223 | 229 | transport = JingleTransportIBB()
|
| 224 | 230 | else:
|
| 225 | - transport = None
|
|
| 231 | + logger.error('No suitable transport method available for %s',
|
|
| 232 | + contact.jid)
|
|
| 233 | + return
|
|
| 226 | 234 | |
| 227 | 235 | senders = 'initiator'
|
| 228 | 236 | if request:
|
| ... | ... | @@ -689,9 +689,12 @@ def write_next(self): |
| 689 | 689 | raise e
|
| 690 | 690 | except OpenSSL.SSL.SysCallError:
|
| 691 | 691 | return self._on_send_exception()
|
| 692 | - except Exception as e:
|
|
| 692 | + except socket.error as err:
|
|
| 693 | 693 | if e.errno not in (EINTR, ENOBUFS, EWOULDBLOCK):
|
| 694 | 694 | return self._on_send_exception()
|
| 695 | + except Exception as err:
|
|
| 696 | + return self._on_send_exception()
|
|
| 697 | + |
|
| 695 | 698 | self.size += lenn
|
| 696 | 699 | current_time = time.time()
|
| 697 | 700 | self.file_props.elapsed_time += current_time - \
|
| ... | ... | @@ -17,6 +17,10 @@ |
| 17 | 17 | # You should have received a copy of the GNU General Public License
|
| 18 | 18 | # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
| 19 | 19 | |
| 20 | +from __future__ import annotations
|
|
| 21 | + |
|
| 22 | +from typing import Optional
|
|
| 23 | + |
|
| 20 | 24 | import os
|
| 21 | 25 | import time
|
| 22 | 26 | import logging
|
| ... | ... | @@ -48,6 +52,7 @@ |
| 48 | 52 | from gajim.common.modules.bytestream import is_transfer_paused
|
| 49 | 53 | from gajim.common.modules.bytestream import is_transfer_stopped
|
| 50 | 54 | from gajim.common.modules.contacts import BareContact
|
| 55 | +from gajim.common import types
|
|
| 51 | 56 | |
| 52 | 57 | from .dialogs import DialogButton
|
| 53 | 58 | from .dialogs import ConfirmationDialog
|
| ... | ... | @@ -390,12 +395,20 @@ def _on_yes(): |
| 390 | 395 | text=_('_Download Again'),
|
| 391 | 396 | callback=_on_yes)]).show()
|
| 392 | 397 | |
| 393 | - def show_file_send_request(self, account, contact):
|
|
| 398 | + def show_file_send_request(self,
|
|
| 399 | + account: str,
|
|
| 400 | + contact: types.BareContact
|
|
| 401 | + ) -> None:
|
|
| 394 | 402 | send_callback = partial(self.send_file, account, contact)
|
| 395 | 403 | SendFileDialog(contact, send_callback, self.window)
|
| 396 | 404 | |
| 397 | - def send_file(self, account, contact, resource_jid, file_path,
|
|
| 398 | - file_desc=''):
|
|
| 405 | + def send_file(self,
|
|
| 406 | + account: str,
|
|
| 407 | + contact: types.BareContact,
|
|
| 408 | + resource_jid: JID,
|
|
| 409 | + file_path: str,
|
|
| 410 | + file_desc: str = ''
|
|
| 411 | + ) -> bool:
|
|
| 399 | 412 | """
|
| 400 | 413 | Start the real transfer(upload) of the file
|
| 401 | 414 | """
|
| ... | ... | @@ -403,11 +416,15 @@ def send_file(self, account, contact, resource_jid, file_path, |
| 403 | 416 | pritext = _('Gajim can not read this file')
|
| 404 | 417 | sextext = _('Another process is using this file.')
|
| 405 | 418 | ErrorDialog(pritext, sextext)
|
| 406 | - return
|
|
| 419 | + return False
|
|
| 407 | 420 | |
| 408 | 421 | file_name = os.path.split(file_path)[1]
|
| 409 | - file_props = self.get_send_file_props(account, contact, file_path,
|
|
| 410 | - file_name, file_desc)
|
|
| 422 | + file_props = self.get_send_file_props(
|
|
| 423 | + account,
|
|
| 424 | + resource_jid,
|
|
| 425 | + file_path,
|
|
| 426 | + file_name,
|
|
| 427 | + file_desc)
|
|
| 411 | 428 | if file_props is None:
|
| 412 | 429 | return False
|
| 413 | 430 | |
| ... | ... | @@ -682,13 +699,19 @@ def get_iter_by_sid(self, typ, sid): |
| 682 | 699 | return iter_
|
| 683 | 700 | iter_ = self.model.iter_next(iter_)
|
| 684 | 701 | |
| 685 | - def __convert_date(self, epoch):
|
|
| 702 | + @staticmethod
|
|
| 703 | + def __convert_date(epoch: float) -> str:
|
|
| 686 | 704 | # Converts date-time from seconds from epoch to iso 8601
|
| 687 | 705 | dt = datetime.utcfromtimestamp(epoch)
|
| 688 | 706 | return dt.isoformat() + 'Z'
|
| 689 | 707 | |
| 690 | - def get_send_file_props(self, account, contact, file_path, file_name,
|
|
| 691 | - file_desc=''):
|
|
| 708 | + def get_send_file_props(self,
|
|
| 709 | + account: str,
|
|
| 710 | + resource_jid: JID,
|
|
| 711 | + file_path: str,
|
|
| 712 | + file_name: str,
|
|
| 713 | + file_desc: str = ''
|
|
| 714 | + ) -> Optional[FileProp]:
|
|
| 692 | 715 | """
|
| 693 | 716 | Create new file_props object and set initial file transfer
|
| 694 | 717 | properties in it
|
| ... | ... | @@ -696,15 +719,20 @@ def get_send_file_props(self, account, contact, file_path, file_name, |
| 696 | 719 | if os.path.isfile(file_path):
|
| 697 | 720 | stat = os.stat(file_path)
|
| 698 | 721 | else:
|
| 699 | - ErrorDialog(_('Invalid File'), _('File: ') + file_path)
|
|
| 722 | + ErrorDialog(
|
|
| 723 | + _('Invalid File'),
|
|
| 724 | + _('File: %s') % file_path)
|
|
| 700 | 725 | return None
|
| 726 | + |
|
| 701 | 727 | if stat[6] == 0:
|
| 702 | 728 | ErrorDialog(
|
| 703 | 729 | _('Invalid File'),
|
| 704 | 730 | _('It is not possible to send empty files'))
|
| 705 | 731 | return None
|
| 732 | + |
|
| 706 | 733 | file_props = FilesProp.getNewFileProp(
|
| 707 | - account, sid=helpers.get_random_string())
|
|
| 734 | + account,
|
|
| 735 | + sid=helpers.get_random_string())
|
|
| 708 | 736 | mod_date = os.path.getmtime(file_path)
|
| 709 | 737 | file_props.file_name = file_path
|
| 710 | 738 | file_props.name = file_name
|
| ... | ... | @@ -714,7 +742,7 @@ def get_send_file_props(self, account, contact, file_path, file_name, |
| 714 | 742 | file_props.elapsed_time = 0
|
| 715 | 743 | file_props.size = stat[6]
|
| 716 | 744 | file_props.sender = account
|
| 717 | - file_props.receiver = contact
|
|
| 745 | + file_props.receiver = str(resource_jid)
|
|
| 718 | 746 | file_props.tt_account = account
|
| 719 | 747 | return file_props
|
| 720 | 748 |