Commit 6600a6ba authored by Tijmen de Mes's avatar Tijmen de Mes

Added HTTP download function and updated file panel

parent ce8123a3
...@@ -4,13 +4,14 @@ import pickle as pickle ...@@ -4,13 +4,14 @@ import pickle as pickle
import contextlib import contextlib
import os import os
import re import re
import requests
import string import string
import sys import sys
import uuid import uuid
from abc import ABCMeta, abstractproperty from abc import ABCMeta, abstractproperty
from collections import defaultdict, deque from collections import defaultdict, deque
from datetime import datetime, timedelta from datetime import datetime, timedelta, timezone
from enum import Enum from enum import Enum
from itertools import chain from itertools import chain
from operator import attrgetter from operator import attrgetter
...@@ -26,7 +27,7 @@ from application.notification import IObserver, NotificationCenter, Notification ...@@ -26,7 +27,7 @@ from application.notification import IObserver, NotificationCenter, Notification
from application.python import Null, limit from application.python import Null, limit
from application.python.types import MarkerType, Singleton from application.python.types import MarkerType, Singleton
from application.python.weakref import weakobjectmap, defaultweakobjectmap from application.python.weakref import weakobjectmap, defaultweakobjectmap
from application.system import makedirs from application.system import makedirs, openfile, FileExistsError
from eventlib.proc import spawn from eventlib.proc import spawn
from zope.interface import implementer from zope.interface import implementer
...@@ -44,6 +45,7 @@ from sipsimple.streams.msrp.filetransfer import FileSelector ...@@ -44,6 +45,7 @@ from sipsimple.streams.msrp.filetransfer import FileSelector
from sipsimple.streams.msrp.screensharing import ExternalVNCServerHandler, ExternalVNCViewerHandler, ScreenSharingStream from sipsimple.streams.msrp.screensharing import ExternalVNCServerHandler, ExternalVNCViewerHandler, ScreenSharingStream
from sipsimple.threading import run_in_thread, run_in_twisted_thread from sipsimple.threading import run_in_thread, run_in_twisted_thread
from blink.logging import MessagingTrace as message_log
from blink.configuration.settings import BlinkSettings from blink.configuration.settings import BlinkSettings
from blink.resources import ApplicationData, Resources from blink.resources import ApplicationData, Resources
from blink.screensharing import ScreensharingWindow, VNCClient, ServerDefault from blink.screensharing import ScreensharingWindow, VNCClient, ServerDefault
...@@ -4840,7 +4842,12 @@ class FileListItemWidget(base_class, ui_class): ...@@ -4840,7 +4842,12 @@ class FileListItemWidget(base_class, ui_class):
if item.encrypted: if item.encrypted:
self.state_indicator.setPixmap(self.pixmaps.encrypted_transfer) self.state_indicator.setPixmap(self.pixmaps.encrypted_transfer)
if item.until is not None: if item.until is not None:
self.status_label.setText(translate('chat_window', "Expiry: %s" % item.until.strftime('%d %b %Y %H:%M'))) if item.expired:
self.status_label.setText(translate('chat_window', "Expired: %s" % item.until.strftime('%d %b %Y %H:%M')))
self.setToolTip(translate('chat_window', "Item still available in cache or local"))
self.status_label.setStyleSheet('color: red')
else:
self.status_label.setText(translate('chat_window', "Expiry: %s" % item.until.strftime('%d %b %Y %H:%M')))
else: else:
self.status_label.setVisible(False) self.status_label.setVisible(False)
...@@ -4865,7 +4872,6 @@ class FileListItem(object): ...@@ -4865,7 +4872,6 @@ class FileListItem(object):
self.widget = FileListItemWidget() self.widget = FileListItemWidget()
self.widget.update_content(self, initial=True) self.widget.update_content(self, initial=True)
def __getstate__(self): def __getstate__(self):
state = self.__dict__.copy() state = self.__dict__.copy()
del state['widget'] del state['widget']
...@@ -4913,6 +4919,10 @@ class FileListItem(object): ...@@ -4913,6 +4919,10 @@ class FileListItem(object):
def until(self): def until(self):
return self.file.until or '' return self.file.until or ''
@property
def expired(self):
return self.until != '' and self.until < datetime.now(timezone.utc)
@property @property
def decrypted_filename(self): def decrypted_filename(self):
return self.file.decrypted_filename return self.file.decrypted_filename
...@@ -5018,7 +5028,7 @@ class FileListModel(QAbstractListModel): ...@@ -5018,7 +5028,7 @@ class FileListModel(QAbstractListModel):
if id in self.items: if id in self.items:
item = [item for item in self.items if item.id == id][0] item = [item for item in self.items if item.id == id][0]
if not item.hash: if not item.hash:
MessageManager().get_file_from_url(session, item.file) SessionManager().get_file_from_url(session, item.file)
return return
SessionManager().get_file(session.contact, session.contact_uri, item.original_filename, item.hash, item.id, account=session.account) SessionManager().get_file(session.contact, session.contact_uri, item.original_filename, item.hash, item.id, account=session.account)
...@@ -5057,8 +5067,11 @@ class FileListDelegate(QStyledItemDelegate): ...@@ -5057,8 +5067,11 @@ class FileListDelegate(QStyledItemDelegate):
QDesktopServices.openUrl(link) QDesktopServices.openUrl(link)
return True return True
if item.expired:
return True
if not item.hash: if not item.hash:
MessageManager().get_file_from_url(model.session, item.file) SessionManager().get_file_from_url(model.session, item.file)
return True return True
SessionManager().get_file(model.session.contact, model.session.contact_uri, item.filename, item.hash, item.id, account=model.session.account) SessionManager().get_file(model.session.contact, model.session.contact_uri, item.filename, item.hash, item.id, account=model.session.account)
return True return True
...@@ -5192,8 +5205,11 @@ class FileListView(QListView, ColorHelperMixin): ...@@ -5192,8 +5205,11 @@ class FileListView(QListView, ColorHelperMixin):
QDesktopServices.openUrl(link) QDesktopServices.openUrl(link)
return True return True
if item.expired:
return True
if not item.hash: if not item.hash:
MessageManager().get_file_from_url(model.session, item.file) SessionManager().get_file_from_url(model.session, item.file)
return True return True
SessionManager().get_file(model.session.contact, model.session.contact_uri, item.filename, item.hash, item.id, account=model.session.account) SessionManager().get_file(model.session.contact, model.session.contact_uri, item.filename, item.hash, item.id, account=model.session.account)
...@@ -6257,6 +6273,40 @@ class SessionManager(object, metaclass=Singleton): ...@@ -6257,6 +6273,40 @@ class SessionManager(object, metaclass=Singleton):
transfer.connect() transfer.connect()
return transfer return transfer
@run_in_thread('file-io')
def get_file_from_url(self, session, file):
message_log.info(f"Fetching content for filetransfer message from: {file.url}")
try:
r = requests.get(file.url, timeout=10)
r.raise_for_status()
except (requests.ConnectionError, requests.Timeout) as e:
message_log.warning(f'HTTP filetransfer connection error: {e}')
except requests.HTTPError as e:
message_log.warning(f'HTTP filetransfer error {e}')
except requests.RequestException as e:
message_log.warning(f'HTTP filetransfer error {e}')
else:
directory = ApplicationData.get(f'transfer_images/{file.id}')
makedirs(directory)
full_filepath = os.path.join(directory, file.name)
for name in UniqueFilenameGenerator.generate(full_filepath):
try:
openfile(name, 'xb')
except FileExistsError:
continue
else:
full_filepath = name
break
with open(full_filepath, 'wb+') as output_file:
output_file.write(r.content)
file.name = full_filepath
message_log.info(f'File saved: {full_filepath}')
notification_center = NotificationCenter()
notification_center.post_notification('BlinkHTTPFileTransferDidEnd', sender=session, data=NotificationData(file=file))
def update_ringtone(self): def update_ringtone(self):
# Outgoing ringtone # Outgoing ringtone
outgoing_sessions_or_proposals = [session for session in self.sessions if session.state == 'connecting/ringing' and session.direction == 'outgoing' or session.state == 'connected/sent_proposal'] outgoing_sessions_or_proposals = [session for session in self.sessions if session.state == 'connecting/ringing' and session.direction == 'outgoing' or session.state == 'connected/sent_proposal']
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment