Misc fixes

This commit is contained in:
emdee 2023-07-14 14:46:18 +00:00
parent 948335c8a0
commit dcde8e3d1e
18 changed files with 313 additions and 272 deletions

View File

@ -4,7 +4,7 @@ import sys
import traceback
from random import shuffle
import threading
from time import sleep
from time import sleep, time
from gevent import monkey; monkey.patch_all(); del monkey # noqa
import gevent
@ -21,8 +21,16 @@ try:
except ImportError as e:
coloredlogs = False
# install https://github.com/weechat/qweechat
# if you want IRC and jabber
try:
# https://github.com/pyqtconsole/pyqtconsole
from pyqtconsole.console import PythonConsole
except Exception as e:
PythonConsole = None
try:
import qdarkstylexxx
except ImportError:
qdarkstyle = None
from middleware import threads
import middleware.callbacks as callbacks
@ -145,7 +153,7 @@ class App:
def __init__(self, version, oArgs):
global LOG
self._args = oArgs
self._oArgs = oArgs
self.oArgs = oArgs
self._path = path_to_profile = oArgs.profile
uri = oArgs.uri
logfile = oArgs.logfile
@ -212,11 +220,11 @@ class App:
# this throws everything as errors
if not self._select_and_load_profile():
return 2
if hasattr(self._oArgs, 'update') and self._oArgs.update:
if hasattr(self._args, 'update') and self._args.update:
if self._try_to_update(): return 3
self._load_app_styles()
if self._oArgs.language != 'English':
if self._args.language != 'English':
# > /var/local/src/toxygen/toxygen/app.py(303)_load_app_translations()->None
# -> self._app.translator = translator
# (Pdb) Fatal Python error: Segmentation fault
@ -307,7 +315,7 @@ class App:
self._kill_tox()
del self._tox
oArgs = self._oArgs
oArgs = self._args
if hasattr(oArgs, 'log_oFd'):
LOG.debug(f"Closing {oArgs.log_oFd}")
oArgs.log_oFd.close()
@ -318,20 +326,20 @@ class App:
# -----------------------------------------------------------------------------------------------------------------
def _load_base_style(self):
if self._oArgs.theme in ['', 'default']: return
if self._args.theme in ['', 'default']: return
if qdarkstyle:
LOG.debug("_load_base_style qdarkstyle " +self._oArgs.theme)
LOG.debug("_load_base_style qdarkstyle " +self._args.theme)
# QDarkStyleSheet
if self._oArgs.theme == 'light':
if self._args.theme == 'light':
from qdarkstyle.light.palette import LightPalette
style = qdarkstyle.load_stylesheet(palette=LightPalette)
else:
from qdarkstyle.dark.palette import DarkPalette
style = qdarkstyle.load_stylesheet(palette=DarkPalette)
else:
LOG.debug("_load_base_style qss " +self._oArgs.theme)
name = self._oArgs.theme + '.qss'
LOG.debug("_load_base_style qss " +self._args.theme)
name = self._args.theme + '.qss'
with open(util.join_path(util.get_styles_directory(), name)) as fl:
style = fl.read()
style += '\n' +sSTYLE
@ -345,9 +353,9 @@ class App:
if self._settings['theme'] != theme:
continue
if qdarkstyle:
LOG.debug("_load_base_style qdarkstyle " +self._oArgs.theme)
LOG.debug("_load_base_style qdarkstyle " +self._args.theme)
# QDarkStyleSheet
if self._oArgs.theme == 'light':
if self._args.theme == 'light':
from qdarkstyle.light.palette import LightPalette
style = qdarkstyle.load_stylesheet(palette=LightPalette)
else:
@ -364,7 +372,7 @@ class App:
LOG.debug('_load_app_styles: loading theme file ' + file_path)
style += '\n' +sSTYLE
self._app.setStyleSheet(style)
LOG.info('_load_app_styles: loaded theme ' +self._oArgs.theme)
LOG.info('_load_app_styles: loaded theme ' +self._args.theme)
break
def _load_login_screen_translations(self):
@ -479,7 +487,7 @@ class App:
LOG.debug(f"_start_threads init: {te()!r}")
# starting threads for tox iterate and toxav iterate
self._main_loop = threads.ToxIterateThread(self._tox)
self._main_loop = threads.ToxIterateThread(self._tox, app=self)
self._main_loop.start()
self._av_loop = threads.ToxAVIterateThread(self._tox.AV)
@ -511,7 +519,7 @@ class App:
def _select_profile(self):
LOG.debug("_select_profile")
if self._oArgs.language != 'English':
if self._args.language != 'English':
self._load_login_screen_translations()
ls = LoginScreen()
profiles = ProfileManager.find_profiles()
@ -550,7 +558,7 @@ class App:
util_ui.tr('Error'))
return False
name = profile_name or 'toxygen_user'
assert self._oArgs
assert self._args
self._path = profile_path
if result.password:
self._toxes.set_password(result.password)
@ -652,7 +660,7 @@ class App:
def _create_dependencies(self):
LOG.info(f"_create_dependencies toxygen version {self._version}")
if hasattr(self._oArgs, 'update') and self._oArgs.update:
if hasattr(self._args, 'update') and self._args.update:
self._backup_service = BackupService(self._settings,
self._profile_manager)
self._smiley_loader = SmileyLoader(self._settings)
@ -764,13 +772,13 @@ class App:
self._ms.show()
# FixMe:
self._log = lambda line: LOG.log(self._oArgs.loglevel,
self._log = lambda line: LOG.log(self._args.loglevel,
self._ms.status(line))
# self._ms._log = self._log # was used in callbacks.py
if False:
self.status_handler = logging.Handler()
self.status_handler.setLevel(logging.INFO) # self._oArgs.loglevel
self.status_handler.setLevel(logging.INFO) # self._args.loglevel
self.status_handler.handle = self._ms.status
self._init_callbacks()
@ -789,9 +797,9 @@ class App:
def _create_tox(self, data, settings_):
LOG.info("_create_tox calling tox_factory")
assert self._oArgs
assert self._args
retval = tox_factory(data=data, settings=settings_,
args=self._oArgs, app=self)
args=self._args, app=self)
LOG.debug("_create_tox succeeded")
self._tox = retval
return retval
@ -837,22 +845,21 @@ class App:
sleep(interval / 1000.0)
def _test_tox(self):
self.test_net()
self.test_net(iMax=8)
self._ms.log_console()
def test_net(self, lElts=None, oThread=None, iMax=4):
LOG.debug("test_net " +self._oArgs.network)
# bootstrap
LOG.debug('Calling generate_nodes: udp')
lNodes = ts.generate_nodes(oArgs=self._oArgs,
LOG.debug('test_net: Calling generate_nodes: udp')
lNodes = ts.generate_nodes(oArgs=self._args,
ipv='ipv4',
udp_not_tcp=True)
self._settings['current_nodes_udp'] = lNodes
if not lNodes:
LOG.warn('empty generate_nodes udp')
LOG.debug('Calling generate_nodes: tcp')
lNodes = ts.generate_nodes(oArgs=self._oArgs,
LOG.debug('test_net: Calling generate_nodes: tcp')
lNodes = ts.generate_nodes(oArgs=self._args,
ipv='ipv4',
udp_not_tcp=False)
self._settings['current_nodes_tcp'] = lNodes
@ -860,8 +867,8 @@ class App:
LOG.warn('empty generate_nodes tcp')
# if oThread and oThread._stop_thread: return
LOG.debug("test_net network=" +self._oArgs.network +' iMax=' +str(iMax))
if self._oArgs.network not in ['local', 'localnew', 'newlocal']:
LOG.debug("test_net network=" +self._args.network +' iMax=' +str(iMax))
if self._args.network not in ['local', 'localnew', 'newlocal']:
b = ts.bAreWeConnected()
if b is None:
i = os.system('ip route|grep ^def')
@ -870,33 +877,33 @@ class App:
else:
b = True
if not b:
LOG.warn("No default route for network " +self._oArgs.network)
LOG.warn("No default route for network " +self._args.network)
text = 'You have no default route - are you connected?'
reply = util_ui.question(text, "Are you connected?")
if not reply: return
iMax = 1
else:
LOG.debug("Have default route for network " +self._oArgs.network)
LOG.debug("Have default route for network " +self._args.network)
lUdpElts = self._settings['current_nodes_udp']
if self._oArgs.proxy_type <= 0 and not lUdpElts:
if self._args.proxy_type <= 0 and not lUdpElts:
title = 'test_net Error'
text = 'Error: ' + str('No UDP nodes')
util_ui.message_box(text, title)
return
lTcpElts = self._settings['current_nodes_tcp']
if self._oArgs.proxy_type > 0 and not lTcpElts:
if self._args.proxy_type > 0 and not lTcpElts:
title = 'test_net Error'
text = 'Error: ' + str('No TCP nodes')
util_ui.message_box(text, title)
return
LOG.debug(f"test_net {self._oArgs.network} lenU={len(lUdpElts)} lenT={len(lTcpElts)} iMax= {iMax}")
LOG.debug(f"test_net {self._args.network} lenU={len(lUdpElts)} lenT={len(lTcpElts)} iMax={iMax}")
i = 0
while i < iMax:
# if oThread and oThread._stop_thread: return
i = i + 1
LOG.debug(f"bootstrapping status proxy={self._oArgs.proxy_type} # {i}")
if self._oArgs.proxy_type == 0:
LOG.debug(f"bootstrapping status proxy={self._args.proxy_type} # {i}")
if self._args.proxy_type == 0:
self._test_bootstrap(lUdpElts)
else:
self._test_bootstrap([lUdpElts[0]])
@ -961,7 +968,7 @@ class App:
if not reply: return
if lElts is None:
if self._oArgs.proxy_type == 0:
if self._args.proxy_type == 0:
sProt = "udp4"
lElts = self._settings['current_nodes_tcp']
else:
@ -969,7 +976,7 @@ class App:
lElts = self._settings['current_nodes_tcp']
shuffle(lElts)
try:
ts.bootstrap_iNmapInfo(lElts, self._oArgs, sProt)
ts.bootstrap_iNmapInfo(lElts, self._args, sProt)
self._ms.log_console()
except Exception as e:
LOG.error(f"test_nmap ' +' : {e}")
@ -990,10 +997,10 @@ class App:
text = 'Run the Extended Test Suite?\nThe program may freeze for 20-60 minutes.'
reply = util_ui.question(text, title)
if reply:
if hasattr(self._oArgs, 'proxy_type') and self._oArgs.proxy_type:
lArgs = ['--proxy_host', self._oArgs.proxy_host,
'--proxy_port', str(self._oArgs.proxy_port),
'--proxy_type', str(self._oArgs.proxy_type), ]
if hasattr(self._args, 'proxy_type') and self._args.proxy_type:
lArgs = ['--proxy_host', self._args.proxy_host,
'--proxy_port', str(self._args.proxy_port),
'--proxy_type', str(self._args.proxy_type), ]
else:
lArgs = list()
try:

View File

@ -136,16 +136,16 @@ class Contact(basecontact.BaseContact):
"""
:return list of unsent messages for saving
"""
messages = filter(lambda m: m.type in (MESSAGE_TYPE['TEXT'], MESSAGE_TYPE['ACTION'])
and m.author.type == MESSAGE_AUTHOR['NOT_SENT'], self._corr)
return list(messages)
def mark_as_sent(self, tox_message_id):
message = list(filter(lambda m: m.author is not None
and m.author.type == MESSAGE_AUTHOR['NOT_SENT']
and m.tox_message_id == tox_message_id,
self._corr))[0]
return list(messages)
def mark_as_sent(self, tox_message_id):
try:
message = list(filter(lambda m: m.author is not None and m.author.type == MESSAGE_AUTHOR['NOT_SENT']
and m.tox_message_id == tox_message_id, self._corr))[0]
message.mark_as_sent()
except Exception as ex:
# wrapped C/C++ object of type QLabel has been deleted

View File

@ -87,22 +87,21 @@ class ContactProvider(tox_save.ToxSave):
def get_group_by_number(self, group_number):
group = None
try:
LOG_INFO(f"group_get_number {group_number} ")
LOG_INFO(f"CP.group_get_number {group_number} ")
# original code
chat_id = self._tox.group_get_chat_id(group_number)
if not chat_id:
LOG_ERROR(f"get_group_by_number NULL number ({group_number})")
if chat_id is None:
LOG_ERROR(f"get_group_by_number NULL chat_id ({group_number})")
elif chat_id == '-1':
LOG_ERROR(f"get_group_by_number <0 chat_id ({group_number})")
else:
LOG_INFO(f"group_get_number {group_number} {chat_id}")
group = self.get_group_by_chat_id(chat_id)
if not group:
LOG_ERROR(f"get_group_by_number NULL group ({chat_id})")
if group is None:
LOG_WARN(f"get_group_by_number leaving ({group_number})")
#? iRet = self._tox.group_leave(group_number)
# invoke in main thread?
# self._contacts_manager.delete_group(group_number)
if group is None or group == '-1':
LOG_WARN(f"get_group_by_number leaving {group} ({group_number})")
#? iRet = self._tox.group_leave(group_number)
# invoke in main thread?
# self._contacts_manager.delete_group(group_number)
return group
except Exception as e:
LOG_WARN(f"group_get_number {group_number} {e}")

View File

@ -421,9 +421,10 @@ class ContactsManager(ToxSave):
def add_group(self, group_number):
index = len(self._contacts)
group = self._contact_provider.get_group_by_number(group_number)
# group num >= 0?
if group is None:
LOG.warn(f"CM.add_group: NO group {group_number}")
LOG.warn(f"CM.add_group: NULL group from group_number={group_number}")
elif group < 0:
LOG.warn(f"CM.add_group: NO group from group={group} group_number={group_number}")
else:
LOG.info(f"CM.add_group: Adding group {group._name}")
self._contacts.append(group)

View File

@ -255,7 +255,7 @@ class GroupsService(tox_save.ToxSave):
# -----------------------------------------------------------------------------------------------------------------
def _add_new_group_by_number(self, group_number):
LOG.debug(f"_add_new_group_by_number {group_number}")
LOG.debug(f"_add_new_group_by_number group_number={group_number}")
self._contacts_manager.add_group(group_number)
def _get_group_by_number(self, group_number):

View File

@ -171,7 +171,7 @@ def setup_default_video():
video['output_devices'] = default_video
return video
def main_parser():
def main_parser(_=None, iMode=2):
import cv2
if not os.path.exists('/proc/sys/net/ipv6'):
bIpV6 = 'False'
@ -182,32 +182,17 @@ def main_parser():
audio = setup_default_audio()
default_video = setup_default_video()
logfile = os.path.join(os.environ.get('TMPDIR', '/tmp'), 'toxygen.log')
parser = argparse.ArgumentParser()
# parser = argparse.ArgumentParser()
parser = ts.oMainArgparser()
parser.add_argument('--version', action='store_true', help='Prints Toxygen version')
parser.add_argument('--clean', action='store_true', help='Delete toxcore libs from libs folder')
parser.add_argument('--reset', action='store_true', help='Reset default profile')
parser.add_argument('--uri', type=str, default='',
help='Add specified Tox ID to friends')
parser.add_argument('--logfile', default=logfile,
help='Filename for logging')
parser.add_argument('--loglevel', type=int, default=logging.INFO,
help='Threshold for logging (lower is more) default: 20')
parser.add_argument('--proxy_host', '--proxy-host', type=str,
# oddball - we want to use '' as a setting
default='0.0.0.0',
help='proxy host')
parser.add_argument('--proxy_port', '--proxy-port', default=0, type=int,
help='proxy port')
parser.add_argument('--proxy_type', '--proxy-type', default=0, type=int,
choices=[0,1,2],
help='proxy type 1=https, 2=socks')
parser.add_argument('--tcp_port', '--tcp-port', default=0, type=int,
help='tcp port')
parser.add_argument('--auto_accept_path', '--auto-accept-path', type=str,
default=os.path.join(os.environ['HOME'], 'Downloads'),
help="auto_accept_path")
parser.add_argument('--mode', type=int, default=2,
parser.add_argument('--mode', type=int, default=iMode,
help='Mode: 0=chat 1=chat+audio 2=chat+audio+video default: 0')
parser.add_argument('--font', type=str, default="Courier",
help='Message font')
@ -216,15 +201,6 @@ def main_parser():
parser.add_argument('--local_discovery_enabled',type=str,
default='False', choices=['True','False'],
help='Look on the local lan')
parser.add_argument('--udp_enabled',type=str,
default='True', choices=['True','False'],
help='En/Disable udp')
parser.add_argument('--trace_enabled',type=str,
default='False', choices=['True','False'],
help='Debugging from toxcore logger_trace')
parser.add_argument('--ipv6_enabled',type=str,
default=bIpV6, choices=lIpV6Choices,
help='En/Disable ipv6')
parser.add_argument('--compact_mode',type=str,
default='True', choices=['True','False'],
help='Compact mode')
@ -243,28 +219,12 @@ def main_parser():
parser.add_argument('--core_logging',type=str,
default='False', choices=['True','False'],
help='Dis/Enable Toxcore notifications')
parser.add_argument('--hole_punching_enabled',type=str,
default='False', choices=['True','False'],
help='En/Enable hole punching')
parser.add_argument('--dht_announcements_enabled',type=str,
default='True', choices=['True','False'],
help='En/Disable DHT announcements')
parser.add_argument('--save_history',type=str,
default='True', choices=['True','False'],
help='En/Disable save history')
parser.add_argument('--update', type=int, default=0,
choices=[0,0],
help='Update program (broken)')
parser.add_argument('--download_nodes_list',type=str,
default='False', choices=['True','False'],
help='Download nodes list')
parser.add_argument('--nodes_json', type=str,
default='')
parser.add_argument('--download_nodes_url', type=str,
default='https://nodes.tox.chat/json')
parser.add_argument('--network', type=str,
choices=['old', 'main', 'new', 'local', 'newlocal'],
default='old')
parser.add_argument('--video_input', type=str,
default=-1,
choices=default_video['output_devices'],

View File

@ -88,9 +88,9 @@ class PluginLoader:
if is_active:
try:
instance.start()
self._app.LOG('INFO: Started Plugin ' +short_name)
self._app._log('INFO: Started Plugin ' +short_name)
except Exception as e:
self._app.LOG.error(f"Starting Plugin ' +short_name +' {e}")
self._app._log.error(f"Starting Plugin ' +short_name +' {e}")
# else: LOG.info('Defined Plugin ' +short_name)
except Exception as ex:
LOG.error('in module ' + short_name + ' Exception: ' + str(ex))
@ -150,7 +150,7 @@ class PluginLoader:
if key in self._plugins and hasattr(self._plugins[key], 'instance'):
return self._plugins[key].instance.get_window()
except Exception as e:
self._app.LOG('WARN: ' +key +' _plugins no slot instance: ' +str(e))
self._app._log('WARN: ' +key +' _plugins no slot instance: ' +str(e))
return None
@ -202,7 +202,7 @@ class PluginLoader:
continue
if not hasattr(plugin.instance, 'get_message_menu'):
name = plugin.instance.get_short_name()
self._app.LOG('WARN: get_message_menu not found: ' + name)
self._app._log('WARN: get_message_menu not found: ' + name)
continue
try:
result.extend(plugin.instance.get_message_menu(menu, selected_text))
@ -222,9 +222,9 @@ class PluginLoader:
def reload(self):
path = util.get_plugins_directory()
if not os.path.exists(path):
self._app.LOG('WARN: Plugin directory not found: ' + path)
self._app._log('WARN: Plugin directory not found: ' + path)
return
self.stop()
self._app.LOG('INFO: Reloading plugins from ' +path)
self._app._log('INFO: Reloading plugins from ' +path)
self.load()

View File

@ -1,9 +1,9 @@
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
import os
from PyQt5 import QtCore, QtWidgets
import common.tox_save as tox_save
import utils.ui as util_ui
import common.tox_save as tox_save
MAX_SHORT_NAME_LENGTH = 5
@ -20,7 +20,7 @@ def path_to_data(name):
return os.path.dirname(os.path.realpath(__file__)) + '/' + name + '/'
def log(name, data):
def log(name, data=''):
"""
:param name: plugin unique name
:param data: data for saving in log
@ -48,7 +48,7 @@ class PluginSuperClass(tox_save.ToxSave):
name = name.strip()
short_name = short_name.strip()
if not name or not short_name:
raise NameError('Wrong name')
raise NameError('Wrong name or not name or not short_name')
self._name = name
self._short_name = short_name[:MAX_SHORT_NAME_LENGTH]
self._translator = None # translator for plugin's GUI
@ -75,7 +75,7 @@ class PluginSuperClass(tox_save.ToxSave):
"""
return self.__doc__
def get_menu(self, row_number):
def get_menu(self, menu, row_number=None):
"""
This method creates items for menu which called on right click in list of friends
:param row_number: number of selected row in list of contacts

View File

@ -2,7 +2,7 @@
import os
from PyQt5 import uic
from PyQt5 import QtWidgets, QtGui
from PyQt5 import QtCore, QtGui, QtWidgets
from qtpy.QtGui import (QColor, QTextCharFormat, QFont, QSyntaxHighlighter)
from ui.contact_items import *
@ -751,9 +751,10 @@ class MainWindow(QtWidgets.QMainWindow):
font_width = size
geometry = self._we.geometry()
geometry.setWidth(font_width*80+20)
geometry.setHeight(font_width*(2+24)*11/8)
geometry.setHeight(int(font_width*(2+24)*11/8))
self._we.setGeometry(geometry)
self._we.resize(font_width*80+20, font_width*(2+24)*11/8)
#? QtCore.QSize()
self._we.resize(font_width*80+20, int(font_width*(2+24)*11/8))
self._we.list_buffers.setSizePolicy(QtWidgets.QSizePolicy.Preferred,
QtWidgets.QSizePolicy.Preferred)

View File

@ -10,6 +10,8 @@ import utils.util as util
import utils.ui as util_ui
from stickers.stickers import load_stickers
import logging
LOG = logging.getLogger('app.'+'msw')
class MessageArea(QtWidgets.QPlainTextEdit):
"""User types messages here"""

View File

@ -27,6 +27,7 @@ class AddContact(CenteredWidget):
uic.loadUi(get_views_path('add_contact_screen'), self)
self._update_ui(tox_id)
self._adding = False
self._bootstrap = False
def _update_ui(self, tox_id):
self.toxIdLineEdit = LineEdit(self)
@ -80,6 +81,7 @@ class AddBootstrap(CenteredWidget):
uic.loadUi(get_views_path('add_bootstrap_screen'), self)
self._update_ui(tox_id)
self._adding = False
self._bootstrap = False
def _update_ui(self, tox_id):
self.toxIdLineEdit = LineEdit(self)

View File

@ -7,7 +7,7 @@ import re
from ui.widgets import *
from messenger.messages import MESSAGE_AUTHOR
from file_transfers.file_transfers import *
from PyQt5 import QtCore, QtGui, QtWidgets
class MessageBrowser(QtWidgets.QTextBrowser):
@ -39,7 +39,16 @@ class MessageBrowser(QtWidgets.QTextBrowser):
font.setPixelSize(settings['message_font_size'])
font.setBold(False)
self.setFont(font)
self.resize(width, self.document().size().height())
try:
# was self.resize(width, self.document().size().height())
# guessing QSize
self.resize(QtCore.QSize(width, int(self.document().size().height())))
except TypeError as e:
# TypeError: arguments did not match any overloaded call:
# resize(self, a0: QSize): argument 1 has unexpected type 'int'
# resize(self, w: int, h: int): argument 2 has unexpected type 'float'
pass
self.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse | QtCore.Qt.LinksAccessibleByMouse)
self.anchorClicked.connect(self.on_anchor_clicked)

View File

@ -138,8 +138,8 @@ class Settings(dict):
self._profile_path = path.replace('.json', '.tox')
self._toxes = toxes
self._app = app
self._args = app._oArgs
self._oArgs = app._oArgs
self._args = app._args
self._oArgs = app._args
self._log = lambda l: LOG.log(self._oArgs.loglevel, l)
self._settings_saved_event = Event()
@ -156,29 +156,29 @@ class Settings(dict):
text = title + path
LOG.error(title +str(ex))
util_ui.message_box(text, title)
info = Settings.get_default_settings(app._oArgs)
info = Settings.get_default_settings(app._args)
user_data.settings.clean_settings(info)
else:
LOG.debug('get_default_settings for: ' + repr(path))
info = Settings.get_default_settings(app._oArgs)
info = Settings.get_default_settings(app._args)
if not os.path.exists(path):
merge_args_into_settings(app._oArgs, info)
merge_args_into_settings(app._args, info)
else:
aC = self._changed(app._oArgs, info)
aC = self._changed(app._args, info)
if aC:
title = 'Override profile with commandline - '
if path:
title += os.path.basename(path)
text = 'Override profile with command-line settings? \n'
# text += '\n'.join([str(key) +'=' +str(val) for
# key,val in self._changed(app._oArgs).items()])
# key,val in self._changed(app._args).items()])
text += repr(aC)
reply = util_ui.question(text, title)
if reply:
merge_args_into_settings(app._oArgs, info)
info['audio'] = getattr(app._oArgs, 'audio')
info['video'] = getattr(app._oArgs, 'video')
merge_args_into_settings(app._args, info)
info['audio'] = getattr(app._args, 'audio')
info['video'] = getattr(app._args, 'video')
super().__init__(info)
self._upgrade()

View File

@ -1,5 +1,5 @@
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
# You need a libs directory beside this directory
# You need a libs directory beside this directory
# and you need to link your libtoxcore.so and libtoxav.so
# and libtoxencryptsave.so into ../libs/
# Link all 3 to libtoxcore.so if you have only libtoxcore.so

View File

@ -14,6 +14,14 @@ except ImportError:
sLIBS_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)),
'libs')
# environment variable TOXCORE_LIBS overrides
d = os.environ.get('TOXCORE_LIBS', '')
if d and os.path.exists(d):
sLIBS_DIR = d
if os.environ.get('DEBUG', ''):
print ('DBUG: Setting TOXCORE_LIBS to ' +d)
del d
class LibToxCore:
def __init__(self):
@ -28,7 +36,6 @@ class LibToxCore:
# libtoxcore and libsodium may be installed in your os
# give libs/ precedence
libFile = os.path.join(sLIBS_DIR, libtoxcore)
assert os.path.isfile(libFile), libFile
if os.path.isfile(libFile):
self._libtoxcore = CDLL(libFile)
else:
@ -48,7 +55,6 @@ class LibToxAV:
self._libtoxav = CDLL('libtoxcore.dylib')
else:
libFile = os.path.join(sLIBS_DIR, 'libtoxav.so')
assert os.path.isfile(libFile), libFile
if os.path.isfile(libFile):
self._libtoxav = CDLL(libFile)
else:
@ -70,7 +76,6 @@ class LibToxEncryptSave:
self._lib_tox_encrypt_save = CDLL('libtoxcore.dylib')
else:
libFile = os.path.join(sLIBS_DIR, 'libtoxencryptsave.so')
assert os.path.isfile(libFile), libFile
if os.path.isfile(libFile):
self._lib_tox_encrypt_save = CDLL(libFile)
else:

View File

@ -11,11 +11,22 @@ except:
from toxav import ToxAV
from toxcore_enums_and_consts import *
# callbacks can be called in any thread so were being careful
# tox.py can be called by callbacks
def LOG_ERROR(a): print('EROR> '+a)
def LOG_WARN(a): print('WARN> '+a)
def LOG_INFO(a): print('INFO> '+a)
def LOG_DEBUG(a): print('DBUG> '+a)
def LOG_TRACE(a): pass # print('TRAC> '+a)
def LOG_INFO(a):
bVERBOSE = hasattr(__builtins__, 'app') and app.oArgs.loglevel <= 20
if bVERBOSE: print('INFO> '+a)
def LOG_DEBUG(a):
bVERBOSE = hasattr(__builtins__, 'app') and app.oArgs.loglevel <= 10
if bVERBOSE: print('DBUG> '+a)
def LOG_TRACE(a):
bVERBOSE = hasattr(__builtins__, 'app') and app.oArgs.loglevel < 10
if bVERBOSE: print('TRAC> '+a)
UINT32_MAX = 2 ** 32 -1
class ToxError(RuntimeError): pass
global aTIMES
aTIMES=dict()
@ -57,7 +68,6 @@ class ToxOptions(Structure):
]
class GroupChatSelfPeerInfo(Structure):
_fields_ = [
('nick', c_char_p),
@ -109,11 +119,11 @@ class Tox:
raise MemoryError('The function was unable to allocate enough '
'memory to store the internal structures for the Tox object.')
if tox_err_new == TOX_ERR_NEW['PORT_ALLOC']:
raise RuntimeError('The function was unable to bind to a port. This may mean that all ports have '
raise ToxError('The function was unable to bind to a port. This may mean that all ports have '
'already been bound, e.g. by other Tox instances, or it may mean a permission error.'
' You may be able to gather more information from errno.')
if tox_err_new == TOX_ERR_NEW['TCP_SERVER_ALLOC']:
raise RuntimeError('The function was unable to bind the tcp server port.')
raise ToxError('The function was unable to bind the tcp server port.')
if tox_err_new == TOX_ERR_NEW['PROXY_BAD_TYPE']:
raise ArgumentError('proxy_type was invalid.')
if tox_err_new == TOX_ERR_NEW['PROXY_BAD_HOST']:
@ -165,7 +175,7 @@ class Tox:
def kill(self):
if hasattr(self, 'AV'): del self.AV
LOG_DEBUG(f"tox_kill")
LOG_INFO(f"tox_kill")
try:
Tox.libtoxcore.tox_kill(self._tox_pointer)
except Exception as e:
@ -213,7 +223,7 @@ class Tox:
return result
if tox_err_options_new == TOX_ERR_OPTIONS_NEW['MALLOC']:
raise MemoryError('The function failed to allocate enough memory for the options struct.')
raise RuntimeError('The function did not return OK for the options struct.')
raise ToxError('The function did not return OK for the options struct.')
@staticmethod
def options_free(tox_options):
@ -295,7 +305,7 @@ class Tox:
raise ArgumentError('One of the arguments to the function was NULL when it was not expected.')
if tox_err_bootstrap == TOX_ERR_BOOTSTRAP['BAD_HOST']:
raise ArgumentError('The address could not be resolved to an IP '
'address, or the IP address passed was invalid.')
'address, or the address passed was invalid.')
if tox_err_bootstrap == TOX_ERR_BOOTSTRAP['BAD_PORT']:
raise ArgumentError('The port passed was invalid. The valid port range is (1, 65535).')
# me - this seems wrong - should be False
@ -405,6 +415,9 @@ class Tox:
# Internal client information (Tox address/id)
# -----------------------------------------------------------------------------------------------------------------
def self_get_toxid(self, address=None):
return self.self_get_address(address)
def self_get_address(self, address=None):
"""
Writes the Tox friend address of the client to a byte array. The address is not in human-readable format. If a
@ -652,7 +665,7 @@ class Tox:
raise ArgumentError('The friend was already there, but the nospam value was different.')
if tox_err_friend_add == TOX_ERR_FRIEND_ADD['MALLOC']:
raise MemoryError('A memory allocation failed when trying to increase the friend list size.')
raise RuntimeError('The function did not return OK for the friend add.')
raise ToxError('The function did not return OK for the friend add.')
def friend_add_norequest(self, public_key):
"""Add a friend without sending a friend request.
@ -698,7 +711,7 @@ class Tox:
raise ArgumentError('The friend was already there, but the nospam value was different.')
if tox_err_friend_add == TOX_ERR_FRIEND_ADD['MALLOC']:
raise MemoryError('A memory allocation failed when trying to increase the friend list size.')
raise RuntimeError('The function did not return OK for the friend add.')
raise ToxError('The function did not return OK for the friend add.')
def friend_delete(self, friend_number):
"""
@ -744,13 +757,14 @@ class Tox:
raise ArgumentError('One of the arguments to the function was NULL when it was not expected.')
if tox_err_friend_by_public_key == TOX_ERR_FRIEND_BY_PUBLIC_KEY['NOT_FOUND']:
raise ArgumentError('No friend with the given Public Key exists on the friend list.')
raise RuntimeError('The function did not return OK for the friend by public key.')
raise ToxError('The function did not return OK for the friend by public key.')
def friend_exists(self, friend_number):
"""
Checks if a friend with the given friend number exists and returns true if it does.
"""
return bool(Tox.libtoxcore.tox_friend_exists(self._tox_pointer, c_uint32(friend_number)))
# bool() -> TypeError: 'str' object cannot be interpreted as an integer
return Tox.libtoxcore.tox_friend_exists(self._tox_pointer, c_uint32(friend_number))
def self_get_friend_list_size(self):
"""
@ -819,7 +833,7 @@ class Tox:
return result
elif tox_err_last_online == TOX_ERR_FRIEND_GET_LAST_ONLINE['FRIEND_NOT_FOUND']:
raise ArgumentError('No friend with the given number exists on the friend list.')
raise RuntimeError('The function did not return OK')
raise ToxError('The function did not return OK')
# -----------------------------------------------------------------------------------------------------------------
# Friend-specific state queries (can also be received through callbacks)
@ -832,7 +846,7 @@ class Tox:
The return value is equal to the `length` argument received by the last `friend_name` callback.
"""
tox_err_friend_query = c_int()
LOG_DEBUG(f"tox_friend_get_name_size")
LOG_TRACE(f"tox_friend_get_name_size")
result = Tox.libtoxcore.tox_friend_get_name_size(self._tox_pointer,
c_uint32(friend_number),
byref(tox_err_friend_query))
@ -845,7 +859,7 @@ class Tox:
' NULL, these functions return an error in that case.')
elif tox_err_friend_query == TOX_ERR_FRIEND_QUERY['FRIEND_NOT_FOUND']:
raise ArgumentError('The friend_number did not designate a valid friend.')
raise RuntimeError('The function did not return OK')
raise ToxError('The function did not return OK')
def friend_get_name(self, friend_number, name=None):
"""
@ -874,7 +888,7 @@ class Tox:
' NULL, these functions return an error in that case.')
elif tox_err_friend_query == TOX_ERR_FRIEND_QUERY['FRIEND_NOT_FOUND']:
raise ArgumentError('The friend_number did not designate a valid friend.')
raise RuntimeError('The function did not return OK')
raise ToxError('The function did not return OK')
def callback_friend_name(self, callback):
"""
@ -907,7 +921,7 @@ class Tox:
:return: length of the friend's status message
"""
tox_err_friend_query = c_int()
LOG_DEBUG(f"tox_friend_get_status_message_size")
LOG_TRACE(f"tox_friend_get_status_message_size")
result = Tox.libtoxcore.tox_friend_get_status_message_size(self._tox_pointer, c_uint32(friend_number),
byref(tox_err_friend_query))
tox_err_friend_query = tox_err_friend_query.value
@ -949,7 +963,7 @@ class Tox:
' NULL, these functions return an error in that case.')
elif tox_err_friend_query == TOX_ERR_FRIEND_QUERY['FRIEND_NOT_FOUND']:
raise ArgumentError('The friend_number did not designate a valid friend.')
raise RuntimeError('The function did not return OK')
raise ToxError('The function did not return OK')
def callback_friend_status_message(self, callback):
"""
@ -1044,7 +1058,7 @@ class Tox:
' NULL, these functions return an error in that case.')
elif tox_err_friend_query == TOX_ERR_FRIEND_QUERY['FRIEND_NOT_FOUND']:
raise ArgumentError('The friend_number did not designate a valid friend.')
raise RuntimeError('The function did not return OK for friend get connection status.')
raise ToxError('The function did not return OK for friend get connection status.')
def callback_friend_connection_status(self, callback):
"""
@ -1138,27 +1152,31 @@ class Tox:
return bool(result)
if tox_err_set_typing == TOX_ERR_SET_TYPING['FRIEND_NOT_FOUND']:
raise ArgumentError('The friend number did not designate a valid friend.')
raise RuntimeError('The function did not return OK for set typing.')
raise ToxError('The function did not return OK for set typing.')
def friend_send_message(self, friend_number, message_type, message):
"""
Send a text chat message to an online friend.
"""Send a text chat message to an online friend.
This function creates a chat message packet and pushes it into the send queue.
The message length may not exceed TOX_MAX_MESSAGE_LENGTH. Larger messages must be split by the client and sent
as separate messages. Other clients can then reassemble the fragments. Messages may not be empty.
The message length may not exceed
TOX_MAX_MESSAGE_LENGTH. Larger messages must be split by the
client and sent as separate messages. Other clients can then
reassemble the fragments. Messages may not be empty.
The return value of this function is the message ID. If a read receipt is received, the triggered
`friend_read_receipt` event will be passed this message ID.
The return value of this function is the message ID. If a read
receipt is received, the triggered `friend_read_receipt` event
will be passed this message ID.
Message IDs are unique per friend. The first message ID is 0. Message IDs are incremented by 1 each time a
message is sent. If UINT32_MAX messages were sent, the next message ID is 0.
Message IDs are unique per friend. The first message ID is 0.
Message IDs are incremented by 1 each time a message is sent.
If UINT32_MAX messages were sent, the next message ID is 0.
:param friend_number: The friend number of the friend to send the message to.
:param message_type: Message type (TOX_MESSAGE_TYPE).
:param message: A non-None message text.
:return: message ID
"""
tox_err_friend_send_message = c_int()
LOG_DEBUG(f"tox_friend_send_message")
@ -1180,7 +1198,7 @@ class Tox:
raise ArgumentError('Message length exceeded TOX_MAX_MESSAGE_LENGTH.')
elif tox_err_friend_send_message == TOX_ERR_FRIEND_SEND_MESSAGE['EMPTY']:
raise ArgumentError('Attempted to send a zero-length message.')
raise RuntimeError('The function did not return OK for friend send message.')
raise ToxError('The function did not return OK for friend send message.')
def callback_friend_read_receipt(self, callback):
"""
@ -1310,15 +1328,15 @@ class Tox:
elif tox_err_file_control == TOX_ERR_FILE_CONTROL['NOT_FOUND']:
raise ArgumentError('No file transfer with the given file number was found for the given friend.')
elif tox_err_file_control == TOX_ERR_FILE_CONTROL['NOT_PAUSED']:
raise RuntimeError('A RESUME control was sent, but the file transfer is running normally.')
raise ToxError('A RESUME control was sent, but the file transfer is running normally.')
elif tox_err_file_control == TOX_ERR_FILE_CONTROL['DENIED']:
raise RuntimeError('A RESUME control was sent, but the file transfer was paused by the other party. Only '
raise ToxError('A RESUME control was sent, but the file transfer was paused by the other party. Only '
'the party that paused the transfer can resume it.')
elif tox_err_file_control == TOX_ERR_FILE_CONTROL['ALREADY_PAUSED']:
raise RuntimeError('A PAUSE control was sent, but the file transfer was already paused.')
raise ToxError('A PAUSE control was sent, but the file transfer was already paused.')
elif tox_err_file_control == TOX_ERR_FILE_CONTROL['SENDQ']:
raise RuntimeError('Packet queue is full.')
raise RuntimeError('The function did not return OK for file control.')
raise ToxError('Packet queue is full.')
raise ToxError('The function did not return OK for file control.')
def callback_file_recv_control(self, callback):
"""
@ -1381,8 +1399,8 @@ class Tox:
elif tox_err_file_seek == TOX_ERR_FILE_SEEK['INVALID_POSITION']:
raise ArgumentError('Seek position was invalid')
elif tox_err_file_seek == TOX_ERR_FILE_SEEK['SENDQ']:
raise RuntimeError('Packet queue is full.')
raise RuntimeError('The function did not return OK')
raise ToxError('Packet queue is full.')
raise ToxError('The function did not return OK')
def file_get_file_id(self, friend_number, file_number, file_id=None):
"""
@ -1490,9 +1508,9 @@ class Tox:
if err_file == TOX_ERR_FILE_SEND['NAME_TOO_LONG']:
raise ArgumentError('Filename length exceeded TOX_MAX_FILENAME_LENGTH bytes.')
if err_file == TOX_ERR_FILE_SEND['TOO_MANY']:
raise RuntimeError('Too many ongoing transfers. The maximum number of concurrent file transfers is 256 per'
raise ToxError('Too many ongoing transfers. The maximum number of concurrent file transfers is 256 per'
'friend per direction (sending and receiving).')
raise RuntimeError('The function did not return OK')
raise ToxError('The function did not return OK')
def file_send_chunk(self, friend_number, file_number, position, data):
"""
@ -1535,10 +1553,10 @@ class Tox:
'adjusted according to maximum transmission unit and the expected end of the file. '
'Trying to send less or more than requested will return this error.')
elif tox_err_file_send_chunk == TOX_ERR_FILE_SEND_CHUNK['SENDQ']:
raise RuntimeError('Packet queue is full.')
raise ToxError('Packet queue is full.')
elif tox_err_file_send_chunk == TOX_ERR_FILE_SEND_CHUNK['WRONG_POSITION']:
raise ArgumentError('Position parameter was wrong.')
raise RuntimeError('The function did not return OK')
raise ToxError('The function did not return OK')
def callback_file_chunk_request(self, callback):
"""
@ -1688,8 +1706,8 @@ class Tox:
elif tox_err_friend_custom_packet == TOX_ERR_FRIEND_CUSTOM_PACKET['TOO_LONG']:
raise ArgumentError('Packet data length exceeded TOX_MAX_CUSTOM_PACKET_SIZE.')
elif tox_err_friend_custom_packet == TOX_ERR_FRIEND_CUSTOM_PACKET['SENDQ']:
raise RuntimeError('Packet queue is full.')
raise RuntimeError('The function did not return OK')
raise ToxError('Packet queue is full.')
raise ToxError('The function did not return OK')
def friend_send_lossless_packet(self, friend_number, data):
"""
@ -1726,7 +1744,7 @@ class Tox:
elif tox_err_friend_custom_packet == TOX_ERR_FRIEND_CUSTOM_PACKET['TOO_LONG']:
raise ArgumentError('Packet data length exceeded TOX_MAX_CUSTOM_PACKET_SIZE.')
elif tox_err_friend_custom_packet == TOX_ERR_FRIEND_CUSTOM_PACKET['SENDQ']:
raise RuntimeError('Packet queue is full.')
raise ToxError('Packet queue is full.')
def callback_friend_lossy_packet(self, callback):
"""
@ -1808,8 +1826,8 @@ class Tox:
if tox_err_get_port == TOX_ERR_GET_PORT['OK']:
return result
if tox_err_get_port == TOX_ERR_GET_PORT['NOT_BOUND']:
raise RuntimeError('The instance was not bound to any port.')
raise RuntimeError('The function did not return OK')
raise ToxError('The instance was not bound to any port.')
raise ToxError('The function did not return OK')
def self_get_tcp_port(self):
"""
@ -1823,8 +1841,8 @@ class Tox:
if tox_err_get_port == TOX_ERR_GET_PORT['OK']:
return result
if tox_err_get_port == TOX_ERR_GET_PORT['NOT_BOUND']:
raise RuntimeError('The instance was not bound to any port.')
raise RuntimeError('The function did not return OK')
raise ToxError('The instance was not bound to any port.')
raise ToxError('The function did not return OK')
# -----------------------------------------------------------------------------------------------------------------
# Group chat instance management
@ -1865,18 +1883,26 @@ class Tox:
else:
nick_length = len(nick)
cnick = c_char_p(nick)
result = Tox.libtoxcore.tox_group_new(self._tox_pointer, privacy_state,
result = Tox.libtoxcore.tox_group_new(self._tox_pointer,
privacy_state,
group_name,
len(group_name),
cnick, nick_length,
cnick,
nick_length,
byref(error))
if error.value:
LOG_ERROR(f"group_new {error.value}")
raise RuntimeError("group_new {error.value}")
# -1 TOX_ERR_GROUP_NEW_TOO_LONG
# -2 TOX_ERR_GROUP_NEW_EMPTY
# -3 TOX_ERR_GROUP_NEW_INIT
# -4 TOX_ERR_GROUP_NEW_STATE
# -5 TOX_ERR_GROUP_NEW_ANNOUNCE
if error.value in TOX_ERR_GROUP_NEW:
LOG_ERROR(f"group_new {error.value} {TOX_ERR_GROUP_NEW[error.value]}")
raise ToxError(f"group_new {error.value}")
return result
def group_join(self, chat_id, password, nick, status):
def group_join(self, chat_id, password, nick, status=''):
"""Joins a group chat with specified Chat ID.
This function creates a new group chat object, adds it to the
@ -1917,8 +1943,8 @@ class Tox:
byref(error))
if error.value:
LOG_ERROR(f"group_join {error.value}")
raise RuntimeError("group_join {error.value}")
LOG_ERROR(f"group_join {error.value} {TOX_ERR_GROUP_JOIN[error.value]}")
raise ToxError(f"group_join {error.value} {TOX_ERR_GROUP_JOIN[error.value]}")
return result
def group_reconnect(self, group_number):
@ -1937,7 +1963,7 @@ class Tox:
result = Tox.libtoxcore.tox_group_reconnect(self._tox_pointer, group_number, byref(error))
if error.value:
LOG_ERROR(f"group_reconnect {error.value}")
raise RuntimeError(f"group_reconnect {error.value}")
raise ToxError(f"group_reconnect {error.value}")
return result
def group_is_connected(self, group_number):
@ -1946,7 +1972,7 @@ class Tox:
result = Tox.libtoxcore.tox_group_is_connected(self._tox_pointer, group_number, byref(error))
if error.value:
LOG_ERROR(f"group_is_connected {error.value}")
raise RuntimeError("group_is_connected {error.value}")
raise ToxError("group_is_connected {error.value}")
return result
def group_disconnect(self, group_number):
@ -1955,10 +1981,10 @@ class Tox:
result = Tox.libtoxcore.tox_group_disconnect(self._tox_pointer, group_number, byref(error))
if error.value:
LOG_ERROR(f"group_disconnect {error.value}")
raise RuntimeError("group_disconnect {error.value}")
raise ToxError("group_disconnect {error.value}")
return result
def group_leave(self, group_number, message=''):
def group_leave(self, group_number, message=None):
"""Leaves a group.
This function sends a parting packet containing a custom
@ -1979,10 +2005,10 @@ class Tox:
f = Tox.libtoxcore.tox_group_leave
f.restype = c_bool
result = f(self._tox_pointer, group_number, message,
len(message) if message is not None else 0, byref(error))
len(message) if message else 0, byref(error))
if error.value:
LOG_ERROR(f"group_leave {error.value}")
raise RuntimeError("group_leave {error.value}")
raise ToxError("group_leave {error.value}")
return result
# -----------------------------------------------------------------------------------------------------------------
@ -2008,7 +2034,7 @@ class Tox:
result = Tox.libtoxcore.tox_group_self_set_name(self._tox_pointer, group_number, name, len(name), byref(error))
if error.value:
LOG_ERROR(f"group_self_set_name {error.value}")
raise RuntimeError("group_self_set_name {error.value}")
raise ToxError("group_self_set_name {error.value}")
return result
def group_self_get_name_size(self, group_number):
@ -2021,11 +2047,11 @@ class Tox:
"""
error = c_int()
LOG_DEBUG(f"tox_group_self_get_name_size")
LOG_TRACE(f"tox_group_self_get_name_size")
result = Tox.libtoxcore.tox_group_self_get_name_size(self._tox_pointer, group_number, byref(error))
if error.value:
LOG_ERROR(f"group_self_get_name_size {error.value}")
raise RuntimeError("group_self_get_name_size {error.value}")
raise ToxError("group_self_get_name_size {error.value}")
return result
def group_self_get_name(self, group_number):
@ -2048,7 +2074,7 @@ class Tox:
result = Tox.libtoxcore.tox_group_self_get_name(self._tox_pointer, group_number, name, byref(error))
if error.value:
LOG_ERROR(f"group_self_get_name {error.value}")
raise RuntimeError("group_self_get_name {error.value}")
raise ToxError("group_self_get_name {error.value}")
return str(name[:size], 'utf-8', errors='ignore')
def group_self_set_status(self, group_number, status):
@ -2063,7 +2089,7 @@ class Tox:
result = Tox.libtoxcore.tox_group_self_set_status(self._tox_pointer, group_number, status, byref(error))
if error.value:
LOG_ERROR(f"group_self_set_status {error.value}")
raise RuntimeError("group_self_set_status {error.value}")
raise ToxError("group_self_set_status {error.value}")
return result
def group_self_get_status(self, group_number):
@ -2077,7 +2103,7 @@ class Tox:
result = Tox.libtoxcore.tox_group_self_get_status(self._tox_pointer, group_number, byref(error))
if error.value:
LOG_ERROR(f"group_self_get_status {error.value}")
raise RuntimeError("group_self_get_status {error.value}")
raise ToxError("group_self_get_status {error.value}")
return result
def group_self_get_role(self, group_number):
@ -2091,7 +2117,7 @@ class Tox:
result = Tox.libtoxcore.tox_group_self_get_role(self._tox_pointer, group_number, byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
return result
def group_self_get_peer_id(self, group_number):
@ -2105,7 +2131,7 @@ class Tox:
result = Tox.libtoxcore.tox_group_self_get_peer_id(self._tox_pointer, group_number, byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError("tox_group_self_get_peer_id {error.value}")
raise ToxError("tox_group_self_get_peer_id {error.value}")
return result
def group_self_get_public_key(self, group_number):
@ -2127,8 +2153,8 @@ class Tox:
result = Tox.libtoxcore.tox_group_self_get_public_key(self._tox_pointer, group_number,
key, byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
LOG_ERROR(f" {TOX_ERR_FRIEND_GET_PUBLIC_KEY[error.value]}")
raise ToxError(f"{TOX_ERR_FRIEND_GET_PUBLIC_KEY[error.value]}")
return bin_to_string(key, TOX_GROUP_PEER_PUBLIC_KEY_SIZE)
# -----------------------------------------------------------------------------------------------------------------
@ -2148,7 +2174,7 @@ class Tox:
result = Tox.libtoxcore.tox_group_peer_get_name_size(self._tox_pointer, group_number, peer_id, byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
LOG_TRACE(f"tox_group_peer_get_name_size")
return result
@ -2175,7 +2201,7 @@ class Tox:
result = Tox.libtoxcore.tox_group_peer_get_name(self._tox_pointer, group_number, peer_id, name, byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f"tox_group_peer_get_name {error.value}")
raise ToxError(f"tox_group_peer_get_name {error.value}")
sRet = str(name[:], 'utf-8', errors='ignore')
return sRet
@ -2193,7 +2219,7 @@ class Tox:
result = Tox.libtoxcore.tox_group_peer_get_status(self._tox_pointer, group_number, peer_id, byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
return result
def group_peer_get_role(self, group_number, peer_id):
@ -2210,7 +2236,7 @@ class Tox:
result = Tox.libtoxcore.tox_group_peer_get_role(self._tox_pointer, group_number, peer_id, byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
return result
def group_peer_get_public_key(self, group_number, peer_id):
@ -2234,7 +2260,7 @@ class Tox:
key, byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
return bin_to_string(key, TOX_GROUP_PEER_PUBLIC_KEY_SIZE)
def callback_group_peer_name(self, callback, user_data):
@ -2300,7 +2326,7 @@ class Tox:
else:
if error.value:
LOG_ERROR(f"group_set_topic {error.value}")
raise RuntimeError("group_set_topic {error.value}")
raise ToxError("group_set_topic {error.value}")
return result
def group_get_topic_size(self, group_number):
@ -2313,8 +2339,8 @@ class Tox:
"""
error = c_int()
LOG_TRACE(f"tox_group_get_topic_size")
try:
LOG_DEBUG(f"tox_group_get_topic_size")
result = Tox.libtoxcore.tox_group_get_topic_size(self._tox_pointer, group_number, byref(error))
except Exception as e:
LOG_WARN(f" Exception {e}")
@ -2322,8 +2348,7 @@ class Tox:
else:
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
LOG_DEBUG(f"tox_group_get_topic_size")
raise ToxError(f" {error.value}")
return result
def group_get_topic(self, group_number):
@ -2343,7 +2368,7 @@ class Tox:
result = Tox.libtoxcore.tox_group_get_topic(self._tox_pointer, group_number, topic, byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
return str(topic[:size], 'utf-8', errors='ignore')
def group_get_name_size(self, group_number):
@ -2352,11 +2377,10 @@ class Tox:
return value is unspecified.
"""
error = c_int()
LOG_DEBUG(f"tox_group_get_name_size")
result = Tox.libtoxcore.tox_group_get_name_size(self._tox_pointer, group_number, byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
LOG_TRACE(f"tox_group_get_name_size")
return int(result)
@ -2375,7 +2399,7 @@ class Tox:
name, byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
return str(name[:size], 'utf-8', errors='ignore')
def group_get_chat_id(self, group_number):
@ -2385,14 +2409,23 @@ class Tox:
:return chat id.
"""
LOG_INFO(f"tox_group_get_id group_number={group_number}")
error = c_int()
buff = create_string_buffer(TOX_GROUP_CHAT_ID_SIZE)
result = Tox.libtoxcore.tox_group_get_chat_id(self._tox_pointer,
group_number,
buff, byref(error))
if error.value:
LOG_ERROR(f"tox_group_get_chat_id {error.value}")
raise RuntimeError(f" {error.value}")
if error.value == 1:
LOG_ERROR(f"tox_group_get_chat_id ERROR GROUP_STATE_QUERIES_GROUP_NOT_FOUND group_number={group_number}")
else:
LOG_ERROR(f"tox_group_get_chat_id group_number={group_number} error={error.value}")
raise ToxError(f"tox_group_get_chat_id {error.value}")
#
# QObject::setParent: Cannot set parent, new parent is in a different thread
# QObject::installEventFilter(): Cannot filter events for objects in a different thread.
# QBasicTimer::start: Timers cannot be started from another thread
LOG_TRACE(f"tox_group_get_chat_id")
return bin_to_string(buff, TOX_GROUP_CHAT_ID_SIZE)
@ -2409,12 +2442,13 @@ class Tox:
return result
def groups_get_list(self):
groups_list_size = self.group_get_number_groups()
groups_list = create_string_buffer(sizeof(c_uint32) * groups_list_size)
groups_list = POINTER(c_uint32)(groups_list)
LOG_DEBUG(f"tox_groups_get_list")
Tox.libtoxcore.tox_groups_get_list(self._tox_pointer, groups_list)
return groups_list[0:groups_list_size]
raise NotImplementedError('tox_groups_get_list')
# groups_list_size = self.group_get_number_groups()
# groups_list = create_string_buffer(sizeof(c_uint32) * groups_list_size)
# groups_list = POINTER(c_uint32)(groups_list)
# LOG_DEBUG(f"tox_groups_get_list")
# Tox.libtoxcore.tox_groups_get_list(self._tox_pointer, groups_list)
# return groups_list[0:groups_list_size]
def group_get_privacy_state(self, group_number):
"""
@ -2432,7 +2466,7 @@ class Tox:
result = Tox.libtoxcore.tox_group_get_privacy_state(self._tox_pointer, group_number, byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
return result
def group_get_peer_limit(self, group_number):
@ -2451,7 +2485,7 @@ class Tox:
result = Tox.libtoxcore.tox_group_get_peer_limit(self._tox_pointer, group_number, byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
return result
def group_get_password_size(self, group_number):
@ -2461,11 +2495,11 @@ class Tox:
"""
error = c_int()
LOG_DEBUG(f"tox_group_get_password_size")
LOG_TRACE(f"tox_group_get_password_size")
result = Tox.libtoxcore.tox_group_get_password_size(self._tox_pointer, group_number, byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
return result
def group_get_password(self, group_number):
@ -2490,7 +2524,7 @@ class Tox:
password, byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
return str(password[:size], 'utf-8', errors='ignore')
def callback_group_topic(self, callback, user_data):
@ -2603,7 +2637,7 @@ class Tox:
len(data), byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
return result
def group_send_private_message(self, group_number, peer_id, message_type, message):
@ -2630,11 +2664,11 @@ class Tox:
message_type, message,
len(message), byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
LOG_ERROR(f"group_send_private_message {TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE[error.value]}")
raise ToxError(f"group_send_private_message {TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE[error.value]}")
return result
def group_send_message(self, group_number, type, message):
def group_send_message(self, group_number, type_, message):
"""
Send a text chat message to the group.
@ -2646,7 +2680,7 @@ class Tox:
then reassemble the fragments. Messages may not be empty.
:param group_number: The group number of the group the message is intended for.
:param type: Message type (normal, action, ...).
:param type_: Message type (normal, action, ...).
:param message: A non-NULL pointer to the first element of a byte array containing the message text.
:return True on success.
@ -2660,7 +2694,7 @@ class Tox:
# bool tox_group_send_message(const Tox *tox, uint32_t group_number, Tox_Message_Type type, const uint8_t *message, size_t length, uint32_t *message_id, Tox_Err_Group_Send_Message *error)
result = Tox.libtoxcore.tox_group_send_message(self._tox_pointer,
group_number,
type,
type_,
message,
len(message),
# dunno
@ -2668,7 +2702,7 @@ class Tox:
byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
return result
# -----------------------------------------------------------------------------------------------------------------
@ -2755,10 +2789,10 @@ class Tox:
if error.value:
s = sGetError(error.value, TOX_ERR_GROUP_INVITE_FRIEND)
LOG_ERROR(f"group_invite_friend {error.value} {s}")
raise RuntimeError(f"group_invite_friend {error.value} {s}")
raise ToxError(f"group_invite_friend {error.value} {s}")
return result
# API change
# API change - this no longer exists
# @staticmethod
# def group_self_peer_info_new():
# error = c_int()
@ -2767,7 +2801,8 @@ class Tox:
# result = f(byref(error))
# return result
def group_invite_accept(self, invite_data, friend_number, nick, status, password=None):
# status should be dropped
def group_invite_accept(self, invite_data, friend_number, nick, status='', password=None):
"""
Accept an invite to a group chat that the client previously received from a friend. The invite
is only valid while the inviter is present in the group.
@ -2780,21 +2815,38 @@ class Tox:
error = c_int()
f = Tox.libtoxcore.tox_group_invite_accept
f.restype = c_uint32
nick = bytes(nick, 'utf-8')
invite_data = bytes(invite_data, 'utf-8')
try:
nick = bytes(nick, 'utf-8')
except:
nick = b''
try:
if password is not None:
password = bytes(password, 'utf-8')
except:
password = None
invite_data = invite_data or b''
if False: # API change
peer_info = self.group_self_peer_info_new()
peer_info.contents.nick = c_char_p(nick)
peer_info.contents.nick_length = len(nick)
peer_info.contents.user_status = status
result = f(self._tox_pointer, c_uint32(friend_number), invite_data, len(invite_data),
nick, len(nick),
password, len(password) if password is not None else 0,
byref(error))
LOG_INFO(f"group_invite_accept friend_number={friend_number} nick={nick} {invite_data}")
try:
assert type(invite_data) == bytes
result = f(self._tox_pointer,
c_uint32(friend_number),
invite_data, len(invite_data),
c_char_p(nick), len(nick),
c_char_p(password), len(password) if password is not None else 0,
byref(error))
except Exception as e:
LOG_ERROR(f"group_invite_accept ERROR {e}")
raise ToxError(f"group_invite_accept ERROR {e}")
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
# The invite data is not in the expected format.
LOG_ERROR(f"group_invite_accept {TOX_ERR_GROUP_INVITE_ACCEPT[error.value]}")
raise ToxError(f"group_invite_accept {TOX_ERR_GROUP_INVITE_ACCEPT[error.value]} {error.value}")
return result
def callback_group_invite(self, callback, user_data):
@ -2815,7 +2867,6 @@ class Tox:
Tox.libtoxcore.tox_callback_group_invite(self._tox_pointer, POINTER(None)())
self.group_invite_cb = None
return
LOG_DEBUG(f"tox_callback_group_invite")
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, POINTER(c_uint8), c_size_t,
POINTER(c_uint8), c_size_t, c_void_p)
self.group_invite_cb = c_callback(callback)
@ -2953,7 +3004,7 @@ class Tox:
len(password), byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
return result
def group_founder_set_privacy_state(self, group_number, privacy_state):
@ -2978,7 +3029,7 @@ class Tox:
byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
return result
def group_founder_set_peer_limit(self, group_number, max_peers):
@ -3002,7 +3053,7 @@ class Tox:
byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
return result
# -----------------------------------------------------------------------------------------------------------------
@ -3029,7 +3080,7 @@ class Tox:
result = Tox.libtoxcore.tox_group_mod_set_role(self._tox_pointer, group_number, peer_id, role, byref(error))
if error.value:
LOG_ERROR(f" {error.value}")
raise RuntimeError(f" {error.value}")
raise ToxError(f" {error.value}")
return result
def callback_group_moderation(self, callback, user_data):
@ -3037,9 +3088,12 @@ class Tox:
Set the callback for the `group_moderation` event. Pass NULL to unset.
This event is triggered when a moderator or founder executes a moderation event.
(tox_data->tox, group_number, source_peer_number, target_peer_number,
(Tox_Group_Mod_Event)mod_type, tox_data->user_data);
TOX_GROUP_MOD_EVENT = [0,1,2,3,4] TOX_GROUP_MOD_EVENT['MODERATOR']
"""
LOG_DEBUG(f"callback_group_moderation")
# LOG_DEBUG(f"callback_group_moderation")
if callback is None:
self.group_moderation_cb = None
LOG_DEBUG(f"tox_callback_group_moderation")
@ -3056,6 +3110,9 @@ class Tox:
LOG_DEBUG(f"tox_callback_group_moderation")
def group_toggle_set_ignore(self, group_number, peer_id, ignore):
return group_set_ignore(self, group_number, peer_id, ignore)
def group_set_ignore(self, group_number, peer_id, ignore):
"""
Ignore or unignore a peer.
@ -3067,12 +3124,9 @@ class Tox:
"""
error = c_int()
LOG_DEBUG(f"tox_group_toggle_set_ignore")
result = Tox.libtoxcore.tox_group_toggle_set_ignore(self._tox_pointer, group_number, peer_id, ignore, byref(error))
LOG_DEBUG(f"tox_group_set_ignore")
result = Tox.libtoxcore.tox_group_set_ignore(self._tox_pointer, group_number, peer_id, ignore, byref(error))
if error.value:
LOG_ERROR(f"tox_group_toggle_set_ignore {error.value}")
raise RuntimeError("tox_group_toggle_set_ignore {error.value}")
LOG_ERROR(f"tox_group_set_ignore {error.value}")
raise ToxError("tox_group_set_ignore {error.value}")
return result
# ToDo from JF/toxcore
# tox_group_set_ignore

View File

@ -264,7 +264,7 @@ class ToxAV:
24000, or 48000.
"""
toxav_err_send_frame = c_int()
LOG_DEBUG(f"toxav_audio_send_frame")
LOG_TRACE(f"toxav_audio_send_frame")
assert sampling_rate in [8000, 12000, 16000, 24000, 48000]
result = self.libtoxav.toxav_audio_send_frame(self._toxav_pointer,
c_uint32(friend_number),
@ -307,7 +307,7 @@ class ToxAV:
:param v: V (Chroma) plane data.
"""
toxav_err_send_frame = c_int()
LOG_DEBUG(f"toxav_video_send_frame")
LOG_TRACE(f"toxav_video_send_frame")
result = self.libtoxav.toxav_video_send_frame(self._toxav_pointer, c_uint32(friend_number), c_uint16(width),
c_uint16(height), c_char_p(y), c_char_p(u), c_char_p(v),
byref(toxav_err_send_frame))
@ -393,7 +393,7 @@ class ToxAV:
self.libtoxav.toxav_callback_video_receive_frame(self._toxav_pointer, POINTER(None)(), user_data)
self.video_receive_frame_cb = None
return
LOG_DEBUG(f"toxav_callback_video_receive_frame")
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint16, c_uint16,
POINTER(c_uint8), POINTER(c_uint8), POINTER(c_uint8),

View File

@ -1,8 +1,5 @@
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
from ctypes import (ArgumentError, byref, c_bool, c_char_p, c_int, c_size_t,
create_string_buffer)
try:
from wrapper import libtox
from wrapper.toxencryptsave_enums_and_consts import *
@ -10,6 +7,10 @@ except:
import libtox
from toxencryptsave_enums_and_consts import *
from ctypes import (ArgumentError, byref, c_bool, c_char_p, c_int, c_size_t,
create_string_buffer)
class ToxEncryptSave:
def __init__(self):