diff --git a/toxygen/communication/__init__.py b/toxygen/communication/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/toxygen/callbacks.py b/toxygen/communication/callbacks.py similarity index 90% rename from toxygen/callbacks.py rename to toxygen/communication/callbacks.py index ba2994d..0e7345c 100644 --- a/toxygen/callbacks.py +++ b/toxygen/communication/callbacks.py @@ -12,72 +12,7 @@ import util import cv2 import numpy as np -# ----------------------------------------------------------------------------------------------------------------- -# Threads -# ----------------------------------------------------------------------------------------------------------------- - - -class InvokeEvent(QtCore.QEvent): - EVENT_TYPE = QtCore.QEvent.Type(QtCore.QEvent.registerEventType()) - - def __init__(self, fn, *args, **kwargs): - QtCore.QEvent.__init__(self, InvokeEvent.EVENT_TYPE) - self.fn = fn - self.args = args - self.kwargs = kwargs - - -class Invoker(QtCore.QObject): - - def event(self, event): - event.fn(*event.args, **event.kwargs) - return True - - -_invoker = Invoker() - - -def invoke_in_main_thread(fn, *args, **kwargs): - QtCore.QCoreApplication.postEvent(_invoker, InvokeEvent(fn, *args, **kwargs)) - - -class FileTransfersThread(threading.Thread): - - def __init__(self): - self._queue = queue.Queue() - self._timeout = 0.01 - self._continue = True - super().__init__() - - def execute(self, function, *args, **kwargs): - self._queue.put((function, args, kwargs)) - - def stop(self): - self._continue = False - - def run(self): - while self._continue: - try: - function, args, kwargs = self._queue.get(timeout=self._timeout) - function(*args, **kwargs) - except queue.Empty: - pass - except queue.Full: - util.log('Queue is Full in _thread') - except Exception as ex: - util.log('Exception in _thread: ' + str(ex)) - - -_thread = FileTransfersThread() - - -def start(): - _thread.start() - - -def stop(): - _thread.stop() - _thread.join() +# TODO: use closures # ----------------------------------------------------------------------------------------------------------------- # Callbacks - current user diff --git a/toxygen/communication/tox_factory.py b/toxygen/communication/tox_factory.py new file mode 100644 index 0000000..a39bb15 --- /dev/null +++ b/toxygen/communication/tox_factory.py @@ -0,0 +1,27 @@ + + +def tox_factory(data=None, settings=None): + """ + :param data: user data from .tox file. None = no saved data, create new profile + :param settings: current profile settings. None = default settings will be used + :return: new tox instance + """ + if settings is None: + settings = Settings.get_default_settings() + tox_options = Tox.options_new() + tox_options.contents.udp_enabled = settings['udp_enabled'] + tox_options.contents.proxy_type = settings['proxy_type'] + tox_options.contents.proxy_host = bytes(settings['proxy_host'], 'UTF-8') + tox_options.contents.proxy_port = settings['proxy_port'] + tox_options.contents.start_port = settings['start_port'] + tox_options.contents.end_port = settings['end_port'] + tox_options.contents.tcp_port = settings['tcp_port'] + if data: # load existing profile + tox_options.contents.savedata_type = TOX_SAVEDATA_TYPE['TOX_SAVE'] + tox_options.contents.savedata_data = c_char_p(data) + tox_options.contents.savedata_length = len(data) + else: # create new profile + tox_options.contents.savedata_type = TOX_SAVEDATA_TYPE['NONE'] + tox_options.contents.savedata_data = None + tox_options.contents.savedata_length = 0 + return Tox(tox_options) diff --git a/toxygen/contacts/contact.py b/toxygen/contacts/contact.py index ad491fd..4b221e3 100644 --- a/toxygen/contacts/contact.py +++ b/toxygen/contacts/contact.py @@ -2,7 +2,7 @@ from db.history import * from contacts import basecontact import util from messenger.messages import * -import file_transfers as ft +from file_tansfers import file_transfers as ft import re diff --git a/toxygen/contacts/profile.py b/toxygen/contacts/profile.py index f74d134..9c585c2 100644 --- a/toxygen/contacts/profile.py +++ b/toxygen/contacts/profile.py @@ -7,7 +7,7 @@ from ctypes import * from util import log, Singleton, curr_directory from network.tox_dns import tox_dns from db.history import * -from file_transfers import * +from file_tansfers.file_transfers import * import time from av import calls import plugin_support @@ -1299,154 +1299,3 @@ class Profile(basecontact.BaseContact, Singleton): if friend_number == self.get_active_number(): self.create_message_item(text, time.time(), '', MESSAGE_TYPE['INFO_MESSAGE']) self._messages.scrollToBottom() - - # ----------------------------------------------------------------------------------------------------------------- - # GC support - # ----------------------------------------------------------------------------------------------------------------- - - def is_active_a_friend(self): - return type(self.get_curr_friend()) is Friend - - def get_group_by_number(self, number): - groups = filter(lambda x: type(x) is GroupChat and x.number == number, self._contacts) - return list(groups)[0] - - def add_gc(self, number): - widget = self.create_friend_item() - gc = GroupChat('Group chat #' + str(number), '', widget, self._tox, number) - self._contacts.append(gc) - - def create_group_chat(self): - number = self._tox.add_av_groupchat() - self.add_gc(number) - - def leave_gc(self, num): - gc = self._contacts[num] - self._tox.del_groupchat(gc.number) - del self._contacts[num] - self._screen.friends_list.takeItem(num) - if num == self._active_friend: # active friend was deleted - if not len(self._contacts): # last friend was deleted - self.set_active(-1) - else: - self.set_active(0) - - def group_invite(self, friend_number, gc_type, data): - text = QtWidgets.QApplication.translate('MainWindow', 'User {} invites you to group chat. Accept?') - title = QtWidgets.QApplication.translate('MainWindow', 'Group chat invite') - friend = self.get_friend_by_number(friend_number) - reply = QtWidgets.QMessageBox.question(None, title, text.format(friend.name), QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) - if reply == QtWidgets.QMessageBox.Yes: # accepted - if gc_type == TOX_GROUPCHAT_TYPE['TEXT']: - number = self._tox.join_groupchat(friend_number, data) - else: - number = self._tox.join_av_groupchat(friend_number, data) - self.add_gc(number) - - def new_gc_message(self, group_number, peer_number, message_type, message): - name = self._tox.group_peername(group_number, peer_number) - message_type += 5 - if group_number == self.get_active_number() and not self.is_active_a_friend(): # add message to list - t = time.time() - self.create_gc_message_item(message, t, MESSAGE_OWNER['FRIEND'], name, message_type) - self._messages.scrollToBottom() - self.get_curr_friend().append_message( - GroupChatMessage(message, MESSAGE_OWNER['FRIEND'], t, message_type, name)) - else: - gc = self.get_group_by_number(group_number) - gc.inc_messages() - gc.append_message( - GroupChatMessage(message, MESSAGE_OWNER['FRIEND'], time.time(), message_type, name)) - if not gc.visibility: - self.update_filtration() - - def new_gc_title(self, group_number, title): - gc = self.get_group_by_number(group_number) - gc.new_title(title) - if not self.is_active_a_friend() and self.get_active_number() == group_number: - self.update() - - def update_gc(self, group_number): - count = self._tox.group_number_peers(group_number) - gc = self.get_group_by_number(group_number) - text = QtWidgets.QApplication.translate('MainWindow', '{} users in chat') - gc.status_message = text.format(str(count)).encode('utf-8') - if not self.is_active_a_friend() and self.get_active_number() == group_number: - self.update() - - def send_gc_message(self, text): - group_number = self.get_active_number() - if text.startswith('/me '): - text = text[4:] - self._tox.group_action_send(group_number, text.encode('utf-8')) - else: - self._tox.group_message_send(group_number, text.encode('utf-8')) - self._screen.messageEdit.clear() - - def set_title(self, num): - """ - Set new title for gc - """ - gc = self._contacts[num] - name = gc.name - dialog = QtWidgets.QApplication.translate('MainWindow', - "Enter new title for group {}:") - dialog = dialog.format(name) - title = QtWidgets.QApplication.translate('MainWindow', - 'Set title') - text, ok = QtWidgets.QInputDialog.getText(None, - title, - dialog, - QtWidgets.QLineEdit.Normal, - name) - if ok: - text = text.encode('utf-8') - self._tox.group_set_title(gc.number, text) - self.new_gc_title(gc.number, text) - - def get_group_chats(self): - chats = filter(lambda x: type(x) is GroupChat, self._contacts) - chats = map(lambda c: (c.name, c.number), chats) - return list(chats) - - def invite_friend(self, friend_num, group_number): - friend = self._contacts[friend_num] - self._tox.invite_friend(friend.number, group_number) - - def get_gc_peer_name(self, text): - gc = self.get_curr_friend() - if type(gc) is not GroupChat: - return '\t' - names = gc.get_names() - name = re.split("\s+", text)[-1] - suggested_names = list(filter(lambda x: x.startswith(name), names)) - if not len(suggested_names): - return '\t' - return suggested_names[0][len(name):] + ': ' - - -def tox_factory(data=None, settings=None): - """ - :param data: user data from .tox file. None = no saved data, create new profile - :param settings: current profile settings. None = default settings will be used - :return: new tox instance - """ - if settings is None: - settings = Settings.get_default_settings() - tox_options = Tox.options_new() - tox_options.contents.udp_enabled = settings['udp_enabled'] - tox_options.contents.proxy_type = settings['proxy_type'] - tox_options.contents.proxy_host = bytes(settings['proxy_host'], 'UTF-8') - tox_options.contents.proxy_port = settings['proxy_port'] - tox_options.contents.start_port = settings['start_port'] - tox_options.contents.end_port = settings['end_port'] - tox_options.contents.tcp_port = settings['tcp_port'] - if data: # load existing profile - tox_options.contents.savedata_type = TOX_SAVEDATA_TYPE['TOX_SAVE'] - tox_options.contents.savedata_data = c_char_p(data) - tox_options.contents.savedata_length = len(data) - else: # create new profile - tox_options.contents.savedata_type = TOX_SAVEDATA_TYPE['NONE'] - tox_options.contents.savedata_data = None - tox_options.contents.savedata_length = 0 - return Tox(tox_options) diff --git a/toxygen/file_tansfers/__init__.py b/toxygen/file_tansfers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/toxygen/file_transfers.py b/toxygen/file_tansfers/file_transfers.py similarity index 100% rename from toxygen/file_transfers.py rename to toxygen/file_tansfers/file_transfers.py diff --git a/toxygen/file_tansfers/file_transfers_handler.py b/toxygen/file_tansfers/file_transfers_handler.py new file mode 100644 index 0000000..e69de29 diff --git a/toxygen/login.py b/toxygen/login.py index e69de29..d68629a 100644 --- a/toxygen/login.py +++ b/toxygen/login.py @@ -0,0 +1,19 @@ +class Login: + + def __init__(self, arr): + self.arr = arr + + def login_screen_close(self, t, number=-1, default=False, name=None): + """ Function which processes data from login screen + :param t: 0 - window was closed, 1 - new profile was created, 2 - profile loaded + :param number: num of chosen profile in list (-1 by default) + :param default: was or not chosen profile marked as default + :param name: name of new profile + """ + self.t = t + self.num = number + self.default = default + self.name = name + + def get_data(self): + return self.arr[self.num] \ No newline at end of file diff --git a/toxygen/main.py b/toxygen/main.py index 4e91c50..c8f18f6 100644 --- a/toxygen/main.py +++ b/toxygen/main.py @@ -1,31 +1,10 @@ import sys from user_data.settings import * -from callbacks import init_callbacks, stop, start from util import curr_directory, program_version, remove -import updater import argparse - class Login: - - def __init__(self, arr): - self.arr = arr - - def login_screen_close(self, t, number=-1, default=False, name=None): - """ Function which processes data from login screen - :param t: 0 - window was closed, 1 - new profile was created, 2 - profile loaded - :param number: num of chosen profile in list (-1 by default) - :param default: was or not chosen profile marked as default - :param name: name of new profile - """ - self.t = t - self.num = number - self.default = default - self.name = name - - def get_data(self): - return self.arr[self.num] def clean(): diff --git a/toxygen/threads.py b/toxygen/threads.py index dae8800..a79297a 100644 --- a/toxygen/threads.py +++ b/toxygen/threads.py @@ -60,3 +60,68 @@ class ToxAVIterateThread(QtCore.QThread): while not self.stop: self.toxav.iterate() self.msleep(self.toxav.iteration_interval()) + + +class FileTransfersThread(threading.Thread): + + def __init__(self): + self._queue = queue.Queue() + self._timeout = 0.01 + self._continue = True + super().__init__() + + def execute(self, function, *args, **kwargs): + self._queue.put((function, args, kwargs)) + + def stop(self): + self._continue = False + + def run(self): + while self._continue: + try: + function, args, kwargs = self._queue.get(timeout=self._timeout) + function(*args, **kwargs) + except queue.Empty: + pass + except queue.Full: + util.log('Queue is Full in _thread') + except Exception as ex: + util.log('Exception in _thread: ' + str(ex)) + + +_thread = FileTransfersThread() + + +def start(): + _thread.start() + + +def stop(): + _thread.stop() + _thread.join() + + + + +class InvokeEvent(QtCore.QEvent): + EVENT_TYPE = QtCore.QEvent.Type(QtCore.QEvent.registerEventType()) + + def __init__(self, fn, *args, **kwargs): + QtCore.QEvent.__init__(self, InvokeEvent.EVENT_TYPE) + self.fn = fn + self.args = args + self.kwargs = kwargs + + +class Invoker(QtCore.QObject): + + def event(self, event): + event.fn(*event.args, **event.kwargs) + return True + + +_invoker = Invoker() + + +def invoke_in_main_thread(fn, *args, **kwargs): + QtCore.QCoreApplication.postEvent(_invoker, InvokeEvent(fn, *args, **kwargs)) diff --git a/toxygen/ui/list_items.py b/toxygen/ui/list_items.py index 0e4991e..f6ab154 100644 --- a/toxygen/ui/list_items.py +++ b/toxygen/ui/list_items.py @@ -1,7 +1,7 @@ from wrapper.toxcore_enums_and_consts import * from PyQt5 import QtCore, QtGui, QtWidgets from contacts import profile -from file_transfers import TOX_FILE_TRANSFER_STATE, PAUSED_FILE_TRANSFERS, DO_NOT_SHOW_ACCEPT_BUTTON, ACTIVE_FILE_TRANSFERS, SHOW_PROGRESS_BAR +from file_tansfers.file_transfers import TOX_FILE_TRANSFER_STATE, PAUSED_FILE_TRANSFERS, DO_NOT_SHOW_ACCEPT_BUTTON, ACTIVE_FILE_TRANSFERS, SHOW_PROGRESS_BAR from util import curr_directory, convert_time, curr_time from ui.widgets import DataLabel, create_menu import html as h diff --git a/toxygen/user_data/toxes.py b/toxygen/user_data/toxes.py index 5a22f61..982f287 100644 --- a/toxygen/user_data/toxes.py +++ b/toxygen/user_data/toxes.py @@ -1,24 +1,24 @@ class ToxES: - def __init__(self, toxencryptsave): - self._toxencryptsave = toxencryptsave - self._passphrase = None + def __init__(self, tox_encrypt_save): + self._tox_encrypt_save = tox_encrypt_save + self._password = None - def set_password(self, passphrase): - self._passphrase = passphrase + def set_password(self, password): + self._password = password def has_password(self): - return bool(self._passphrase) + return bool(self._password) def is_password(self, password): - return self._passphrase == password + return self._password == password def is_data_encrypted(self, data): - return len(data) > 0 and self._toxencryptsave.is_data_encrypted(data) + return len(data) > 0 and self._tox_encrypt_save.is_data_encrypted(data) def pass_encrypt(self, data): - return self._toxencryptsave.pass_encrypt(data, self._passphrase) + return self._tox_encrypt_save.pass_encrypt(data, self._password) def pass_decrypt(self, data): - return self._toxencryptsave.pass_decrypt(data, self._passphrase) + return self._tox_encrypt_save.pass_decrypt(data, self._password)