initial commit - rewriting. ngc wrapper added, project structure updated

This commit is contained in:
ingvar1995 2018-01-26 23:21:46 +03:00
parent bb2a857ecf
commit 2de4eea357
57 changed files with 2420 additions and 957 deletions

View File

@ -1,9 +1,9 @@
from toxygen.profile import * from contacts.profile import *
from toxygen.tox_dns import tox_dns from network.tox_dns import tox_dns
from toxygen.history import History from db.history import History
from toxygen.smileys import SmileyLoader from toxygen.smileys import SmileyLoader
from toxygen.messages import * from messenger.messages import *
import toxygen.toxes as encr import user_data.toxes as encr
import toxygen.util as util import toxygen.util as util
import time import time
@ -23,15 +23,15 @@ class TestTox:
assert tox.self_get_status_message() == str(status_message, 'utf-8') assert tox.self_get_status_message() == str(status_message, 'utf-8')
class TestProfileHelper: class TestProfileManager:
def test_creation(self): def test_creation(self):
file_name, path = 'test.tox', os.path.dirname(os.path.realpath(__file__)) + '/' file_name, path = 'test.tox', os.path.dirname(os.path.realpath(__file__)) + '/'
data = b'test' data = b'test'
with open(path + file_name, 'wb') as fl: with open(path + file_name, 'wb') as fl:
fl.write(data) fl.write(data)
ph = ProfileHelper(path, file_name[:4]) ph = ProfileManager(path, file_name[:4])
assert ProfileHelper.get_path() == path assert ProfileManager.get_path() == path
assert ph.open_profile() == data assert ph.open_profile() == data
assert os.path.exists(path + 'avatars/') assert os.path.exists(path + 'avatars/')
@ -81,7 +81,7 @@ def create_singletons():
Settings._instance = Settings.get_default_settings() Settings._instance = Settings.get_default_settings()
if not os.path.exists(folder): if not os.path.exists(folder):
os.makedirs(folder) os.makedirs(folder)
ProfileHelper(folder, 'test') ProfileManager(folder, 'test')
def create_friend(name, status_message, number, tox_id): def create_friend(name, status_message, number, tox_id):

263
toxygen/app.py Normal file
View File

@ -0,0 +1,263 @@
class App:
def __init__(self, path_or_uri=None):
self.tox = self.ms = self.init = self.app = self.tray = self.mainloop = self.avloop = None
if path_or_uri is None:
self.uri = self.path = None
elif path_or_uri.startswith('tox:'):
self.path = None
self.uri = path_or_uri[4:]
else:
self.path = path_or_uri
self.uri = None
def enter_pass(self, data):
"""
Show password screen
"""
tmp = [data]
p = PasswordScreen(toxes.ToxES.get_instance(), tmp)
p.show()
self.app.lastWindowClosed.connect(self.app.quit)
self.app.exec_()
if tmp[0] == data:
raise SystemExit()
else:
return tmp[0]
def main(self):
"""
Main function of app. loads login screen if needed and starts main screen
"""
app = QtWidgets.QApplication(sys.argv)
app.setWindowIcon(QtGui.QIcon(curr_directory() + '/images/icon.png'))
self.app = app
if platform.system() == 'Linux':
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_X11InitThreads)
with open(curr_directory() + '/styles/dark_style.qss') as fl:
style = fl.read()
app.setStyleSheet(style)
encrypt_save = toxes.ToxES()
if self.path is not None:
path = os.path.dirname(self.path) + '/'
name = os.path.basename(self.path)[:-4]
data = ProfileManager(path, name).open_profile()
if encrypt_save.is_data_encrypted(data):
data = self.enter_pass(data)
settings = Settings(name)
self.tox = profile.tox_factory(data, settings)
else:
auto_profile = Settings.get_auto_profile()
if not auto_profile[0]:
# show login screen if default profile not found
current_locale = QtCore.QLocale()
curr_lang = current_locale.languageToString(current_locale.language())
langs = Settings.supported_languages()
if curr_lang in langs:
lang_path = langs[curr_lang]
translator = QtCore.QTranslator()
translator.load(curr_directory() + '/translations/' + lang_path)
app.installTranslator(translator)
app.translator = translator
ls = LoginScreen()
ls.setWindowIconText("Toxygen")
profiles = ProfileManager.find_profiles()
ls.update_select(map(lambda x: x[1], profiles))
_login = self.Login(profiles)
ls.update_on_close(_login.login_screen_close)
ls.show()
app.exec_()
if not _login.t:
return
elif _login.t == 1: # create new profile
_login.name = _login.name.strip()
name = _login.name if _login.name else 'toxygen_user'
pr = map(lambda x: x[1], ProfileManager.find_profiles())
if name in list(pr):
msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle(
QtWidgets.QApplication.translate("MainWindow", "Error"))
text = (QtWidgets.QApplication.translate("MainWindow",
'Profile with this name already exists'))
msgBox.setText(text)
msgBox.exec_()
return
self.tox = profile.tox_factory()
self.tox.self_set_name(bytes(_login.name, 'utf-8') if _login.name else b'Toxygen User')
self.tox.self_set_status_message(b'Toxing on Toxygen')
reply = QtWidgets.QMessageBox.question(None,
'Profile {}'.format(name),
QtWidgets.QApplication.translate("login",
'Do you want to set profile password?'),
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
set_pass = SetProfilePasswordScreen(encrypt_save)
set_pass.show()
self.app.lastWindowClosed.connect(self.app.quit)
self.app.exec_()
reply = QtWidgets.QMessageBox.question(None,
'Profile {}'.format(name),
QtWidgets.QApplication.translate("login",
'Do you want to save profile in default folder? If no, profile will be saved in program folder'),
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
path = Settings.get_default_path()
else:
path = curr_directory() + '/'
try:
ProfileManager(path, name).save_profile(self.tox.get_savedata())
except Exception as ex:
print(str(ex))
log('Profile creation exception: ' + str(ex))
msgBox = QtWidgets.QMessageBox()
msgBox.setText(QtWidgets.QApplication.translate("login",
'Profile saving error! Does Toxygen have permission to write to this directory?'))
msgBox.exec_()
return
path = Settings.get_default_path()
settings = Settings(name)
if curr_lang in langs:
settings['language'] = curr_lang
settings.save()
else: # load existing profile
path, name = _login.get_data()
if _login.default:
Settings.set_auto_profile(path, name)
data = ProfileManager(path, name).open_profile()
if encrypt_save.is_data_encrypted(data):
data = self.enter_pass(data)
settings = Settings(name)
self.tox = profile.tox_factory(data, settings)
else:
path, name = auto_profile
data = ProfileManager(path, name).open_profile()
if encrypt_save.is_data_encrypted(data):
data = self.enter_pass(data)
settings = Settings(name)
self.tox = profile.tox_factory(data, settings)
if Settings.is_active_profile(path, name): # profile is in use
reply = QtWidgets.QMessageBox.question(None,
'Profile {}'.format(name),
QtWidgets.QApplication.translate("login", 'Other instance of Toxygen uses this profile or profile was not properly closed. Continue?'),
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No)
if reply != QtWidgets.QMessageBox.Yes:
return
else:
settings.set_active_profile()
# application color scheme
for theme in settings.built_in_themes().keys():
if settings['theme'] == theme:
with open(curr_directory() + settings.built_in_themes()[theme]) as fl:
style = fl.read()
app.setStyleSheet(style)
lang = Settings.supported_languages()[settings['language']]
translator = QtCore.QTranslator()
translator.load(curr_directory() + '/translations/' + lang)
app.installTranslator(translator)
app.translator = translator
# tray icon
self.ms.show()
updating = False
if settings['update'] and updater.updater_available() and updater.connection_available(): # auto update
version = updater.check_for_updates()
if version is not None:
if settings['update'] == 2:
updater.download(version)
updating = True
else:
reply = QtWidgets.QMessageBox.question(None,
'Toxygen',
QtWidgets.QApplication.translate("login",
'Update for Toxygen was found. Download and install it?'),
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
updater.download(version)
updating = True
if updating:
data = self.tox.get_savedata()
ProfileManager.get_instance().save_profile(data)
settings.close()
del self.tox
return
plugin_helper = PluginLoader(self.tox, settings) # plugin support
plugin_helper.load()
start()
# init thread
self.init = self.InitThread(self.tox, self.ms, self.tray)
self.init.start()
# starting threads for tox iterate and toxav iterate
self.mainloop = self.ToxIterateThread(self.tox)
self.mainloop.start()
self.avloop = self.ToxAVIterateThread(self.tox.AV)
self.avloop.start()
if self.uri is not None:
self.ms.add_contact(self.uri)
app.lastWindowClosed.connect(app.quit)
app.exec_()
self.init.stop = True
self.mainloop.stop = True
self.avloop.stop = True
plugin_helper.stop()
stop()
self.mainloop.wait()
self.init.wait()
self.avloop.wait()
self.tray.hide()
data = self.tox.get_savedata()
ProfileManager.get_instance().save_profile(data)
settings.close()
del self.tox
def reset(self):
"""
Create new tox instance (new network settings)
:return: tox instance
"""
self.mainloop.stop = True
self.init.stop = True
self.avloop.stop = True
self.mainloop.wait()
self.init.wait()
self.avloop.wait()
data = self.tox.get_savedata()
ProfileManager.get_instance().save_profile(data)
del self.tox
# create new tox instance
self.tox = profile.tox_factory(data, Settings.get_instance())
# init thread
self.init = self.InitThread(self.tox, self.ms, self.tray)
self.init.start()
# starting threads for tox iterate and toxav iterate
self.mainloop = self.ToxIterateThread(self.tox)
self.mainloop.start()
self.avloop = self.ToxAVIterateThread(self.tox.AV)
self.avloop.start()
plugin_helper = PluginLoader.get_instance()
plugin_helper.set_tox(self.tox)
return self.tox

0
toxygen/av/__init__.py Normal file
View File

58
toxygen/av/call.py Normal file
View File

@ -0,0 +1,58 @@
class Call:
def __init__(self, out_audio, out_video, in_audio=False, in_video=False):
self._in_audio = in_audio
self._in_video = in_video
self._out_audio = out_audio
self._out_video = out_video
self._is_active = False
def get_is_active(self):
return self._is_active
def set_is_active(self, value):
self._is_active = value
is_active = property(get_is_active, set_is_active)
# -----------------------------------------------------------------------------------------------------------------
# Audio
# -----------------------------------------------------------------------------------------------------------------
def get_in_audio(self):
return self._in_audio
def set_in_audio(self, value):
self._in_audio = value
in_audio = property(get_in_audio, set_in_audio)
def get_out_audio(self):
return self._out_audio
def set_out_audio(self, value):
self._out_audio = value
out_audio = property(get_out_audio, set_out_audio)
# -----------------------------------------------------------------------------------------------------------------
# Video
# -----------------------------------------------------------------------------------------------------------------
def get_in_video(self):
return self._in_video
def set_in_video(self, value):
self._in_video = value
in_video = property(get_in_video, set_in_video)
def get_out_video(self):
return self._out_video
def set_out_video(self, value):
self._in_video = value
out_video = property(get_out_video, set_out_video)

View File

@ -1,73 +1,17 @@
import pyaudio import pyaudio
import time import time
import threading import threading
import settings from user_data import settings
from toxav_enums import * from wrapper.toxav_enums import *
import cv2 import cv2
import itertools import itertools
import numpy as np import numpy as np
import screen_sharing from av import screen_sharing
# TODO: play sound until outgoing call will be started or cancelled # TODO: play sound until outgoing call will be started or cancelled
class Call:
def __init__(self, out_audio, out_video, in_audio=False, in_video=False):
self._in_audio = in_audio
self._in_video = in_video
self._out_audio = out_audio
self._out_video = out_video
self._is_active = False
def get_is_active(self):
return self._is_active
def set_is_active(self, value):
self._is_active = value
is_active = property(get_is_active, set_is_active)
# -----------------------------------------------------------------------------------------------------------------
# Audio
# -----------------------------------------------------------------------------------------------------------------
def get_in_audio(self):
return self._in_audio
def set_in_audio(self, value):
self._in_audio = value
in_audio = property(get_in_audio, set_in_audio)
def get_out_audio(self):
return self._out_audio
def set_out_audio(self, value):
self._out_audio = value
out_audio = property(get_out_audio, set_out_audio)
# -----------------------------------------------------------------------------------------------------------------
# Video
# -----------------------------------------------------------------------------------------------------------------
def get_in_video(self):
return self._in_video
def set_in_video(self, value):
self._in_video = value
in_video = property(get_in_video, set_in_video)
def get_out_video(self):
return self._out_video
def set_out_video(self, value):
self._in_video = value
out_video = property(get_out_video, set_out_video)
class AV: class AV:
def __init__(self, toxav): def __init__(self, toxav):

View File

View File

@ -1,7 +1,7 @@
import random import random
import urllib.request import urllib.request
from util import log, curr_directory from util import log, curr_directory
import settings from user_data import settings
from PyQt5 import QtNetwork, QtCore from PyQt5 import QtNetwork, QtCore
import json import json

View File

@ -1,10 +1,10 @@
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtGui
from notifications import * from notifications import *
from settings import Settings from user_data.settings import Settings
from profile import Profile from contacts.profile import Profile
from toxcore_enums_and_consts import * from wrapper.toxcore_enums_and_consts import *
from toxav_enums import * from wrapper.toxav_enums import *
from tox import bin_to_string from wrapper.tox import bin_to_string
from plugin_support import PluginLoader from plugin_support import PluginLoader
import queue import queue
import threading import threading

View File

View File

@ -1,6 +1,6 @@
from settings import * from user_data.settings import *
from PyQt5 import QtCore, QtGui from PyQt5 import QtCore, QtGui
from toxcore_enums_and_consts import TOX_PUBLIC_KEY_SIZE from wrapper.toxcore_enums_and_consts import TOX_PUBLIC_KEY_SIZE
class BaseContact: class BaseContact:
@ -81,7 +81,7 @@ class BaseContact:
""" """
Tries to load avatar of contact or uses default avatar Tries to load avatar of contact or uses default avatar
""" """
prefix = ProfileHelper.get_path() + 'avatars/' prefix = ProfileManager.get_path() + 'avatars/'
avatar_path = prefix + '{}.png'.format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) avatar_path = prefix + '{}.png'.format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2])
if not os.path.isfile(avatar_path) or not os.path.getsize(avatar_path): # load default image if not os.path.isfile(avatar_path) or not os.path.getsize(avatar_path): # load default image
avatar_path = curr_directory() + '/images/avatar.png' avatar_path = curr_directory() + '/images/avatar.png'
@ -92,13 +92,13 @@ class BaseContact:
self._widget.avatar_label.repaint() self._widget.avatar_label.repaint()
def reset_avatar(self): def reset_avatar(self):
avatar_path = (ProfileHelper.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) avatar_path = (ProfileManager.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2])
if os.path.isfile(avatar_path): if os.path.isfile(avatar_path):
os.remove(avatar_path) os.remove(avatar_path)
self.load_avatar() self.load_avatar()
def set_avatar(self, avatar): def set_avatar(self, avatar):
avatar_path = (ProfileHelper.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) avatar_path = (ProfileManager.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2])
with open(avatar_path, 'wb') as f: with open(avatar_path, 'wb') as f:
f.write(avatar) f.write(avatar)
self.load_avatar() self.load_avatar()

View File

@ -1,8 +1,7 @@
from PyQt5 import QtCore, QtGui from db.history import *
from history import * from contacts import basecontact
import basecontact
import util import util
from messages import * from messenger.messages import *
import file_transfers as ft import file_transfers as ft
import re import re

View File

@ -1,5 +1,5 @@
import contact from contacts import contact
from messages import * from messenger.messages import *
import os import os

View File

@ -1,9 +1,11 @@
import contact from contacts import contact
import util import util
from PyQt5 import QtGui, QtCore from PyQt5 import QtGui, QtCore
import toxcore_enums_and_consts as constants from wrapper import toxcore_enums_and_consts as constants
# TODO: ngc
class GroupChat(contact.Contact): class GroupChat(contact.Contact):
def __init__(self, name, status_message, widget, tox, group_number): def __init__(self, name, status_message, widget, tox, group_number):

View File

@ -1,22 +1,21 @@
from list_items import * from ui.list_items import *
from PyQt5 import QtGui, QtWidgets from PyQt5 import QtWidgets
from friend import * from contacts.friend import *
from settings import * from user_data.settings import *
from toxcore_enums_and_consts import * from wrapper.toxcore_enums_and_consts import *
from ctypes import * from ctypes import *
from util import log, Singleton, curr_directory from util import log, Singleton, curr_directory
from tox_dns import tox_dns from network.tox_dns import tox_dns
from history import * from db.history import *
from file_transfers import * from file_transfers import *
import time import time
import calls from av import calls
import avwidgets
import plugin_support import plugin_support
import basecontact from contacts import basecontact
import items_factory from ui import items_factory, avwidgets
import cv2 import cv2
import threading import threading
from group_chat import * from contacts.group_chat import *
import re import re
@ -283,7 +282,7 @@ class Profile(basecontact.BaseContact, Singleton):
if friend.tox_id is None: if friend.tox_id is None:
avatar_path = curr_directory() + '/images/group.png' avatar_path = curr_directory() + '/images/group.png'
else: else:
avatar_path = (ProfileHelper.get_path() + 'avatars/{}.png').format(friend.tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) avatar_path = (ProfileManager.get_path() + 'avatars/{}.png').format(friend.tox_id[:TOX_PUBLIC_KEY_SIZE * 2])
if not os.path.isfile(avatar_path): # load default image if not os.path.isfile(avatar_path): # load default image
avatar_path = curr_directory() + '/images/avatar.png' avatar_path = curr_directory() + '/images/avatar.png'
os.chdir(os.path.dirname(avatar_path)) os.chdir(os.path.dirname(avatar_path))
@ -752,7 +751,7 @@ class Profile(basecontact.BaseContact, Singleton):
else: else:
self.set_active(0) self.set_active(0)
data = self._tox.get_savedata() data = self._tox.get_savedata()
ProfileHelper.get_instance().save_profile(data) ProfileManager.get_instance().save_profile(data)
def add_friend(self, tox_id): def add_friend(self, tox_id):
""" """
@ -785,7 +784,7 @@ class Profile(basecontact.BaseContact, Singleton):
num = self._tox.friend_by_public_key(tox_id) num = self._tox.friend_by_public_key(tox_id)
self.delete_friend(num) self.delete_friend(num)
data = self._tox.get_savedata() data = self._tox.get_savedata()
ProfileHelper.get_instance().save_profile(data) ProfileManager.get_instance().save_profile(data)
except: # not in friend list except: # not in friend list
pass pass
@ -801,7 +800,7 @@ class Profile(basecontact.BaseContact, Singleton):
if add_to_friend_list: if add_to_friend_list:
self.add_friend(tox_id) self.add_friend(tox_id)
data = self._tox.get_savedata() data = self._tox.get_savedata()
ProfileHelper.get_instance().save_profile(data) ProfileManager.get_instance().save_profile(data)
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Friend requests # Friend requests
@ -837,7 +836,7 @@ class Profile(basecontact.BaseContact, Singleton):
friend = Friend(message_getter, result, tox_id, '', item, tox_id) friend = Friend(message_getter, result, tox_id, '', item, tox_id)
self._contacts.append(friend) self._contacts.append(friend)
data = self._tox.get_savedata() data = self._tox.get_savedata()
ProfileHelper.get_instance().save_profile(data) ProfileManager.get_instance().save_profile(data)
return True return True
except Exception as ex: # wrong data except Exception as ex: # wrong data
log('Friend request failed with ' + str(ex)) log('Friend request failed with ' + str(ex))
@ -857,7 +856,7 @@ class Profile(basecontact.BaseContact, Singleton):
if reply == QtWidgets.QMessageBox.Yes: # accepted if reply == QtWidgets.QMessageBox.Yes: # accepted
self.add_friend(tox_id) self.add_friend(tox_id)
data = self._tox.get_savedata() data = self._tox.get_savedata()
ProfileHelper.get_instance().save_profile(data) ProfileManager.get_instance().save_profile(data)
except Exception as ex: # something is wrong except Exception as ex: # something is wrong
log('Accept friend request failed! ' + str(ex)) log('Accept friend request failed! ' + str(ex))
@ -1180,7 +1179,7 @@ class Profile(basecontact.BaseContact, Singleton):
""" """
:param friend_number: number of friend who should get new avatar :param friend_number: number of friend who should get new avatar
""" """
avatar_path = (ProfileHelper.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2]) avatar_path = (ProfileManager.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2])
if not os.path.isfile(avatar_path): # reset image if not os.path.isfile(avatar_path): # reset image
avatar_path = None avatar_path = None
sa = SendAvatar(avatar_path, self._tox, friend_number) sa = SendAvatar(avatar_path, self._tox, friend_number)

0
toxygen/db/__init__.py Normal file
View File

View File

@ -1,8 +1,8 @@
from sqlite3 import connect from sqlite3 import connect
import settings from user_data import settings
from os import chdir from os import chdir
import os.path import os.path
from toxes import ToxES from user_data.toxes import ToxES
PAGE_SIZE = 42 PAGE_SIZE = 42
@ -17,13 +17,15 @@ MESSAGE_OWNER = {
'NOT_SENT': 2 'NOT_SENT': 2
} }
# TODO: unique message id and ngc support
class History: class History:
def __init__(self, name): def __init__(self, name):
self._name = name self._name = name
chdir(settings.ProfileHelper.get_path()) chdir(settings.ProfileManager.get_path())
path = settings.ProfileHelper.get_path() + self._name + '.hstr' path = settings.ProfileManager.get_path() + self._name + '.hstr'
if os.path.exists(path): if os.path.exists(path):
decr = ToxES.get_instance() decr = ToxES.get_instance()
try: try:
@ -45,7 +47,7 @@ class History:
def save(self): def save(self):
encr = ToxES.get_instance() encr = ToxES.get_instance()
if encr.has_password(): if encr.has_password():
path = settings.ProfileHelper.get_path() + self._name + '.hstr' path = settings.ProfileManager.get_path() + self._name + '.hstr'
with open(path, 'rb') as fin: with open(path, 'rb') as fin:
data = fin.read() data = fin.read()
data = encr.pass_encrypt(bytes(data)) data = encr.pass_encrypt(bytes(data))
@ -53,7 +55,7 @@ class History:
fout.write(data) fout.write(data)
def export(self, directory): def export(self, directory):
path = settings.ProfileHelper.get_path() + self._name + '.hstr' path = settings.ProfileManager.get_path() + self._name + '.hstr'
new_path = directory + self._name + '.hstr' new_path = directory + self._name + '.hstr'
with open(path, 'rb') as fin: with open(path, 'rb') as fin:
data = fin.read() data = fin.read()
@ -64,7 +66,7 @@ class History:
fout.write(data) fout.write(data)
def add_friend_to_db(self, tox_id): def add_friend_to_db(self, tox_id):
chdir(settings.ProfileHelper.get_path()) chdir(settings.ProfileManager.get_path())
db = connect(self._name + '.hstr', timeout=TIMEOUT) db = connect(self._name + '.hstr', timeout=TIMEOUT)
try: try:
cursor = db.cursor() cursor = db.cursor()
@ -84,7 +86,7 @@ class History:
db.close() db.close()
def delete_friend_from_db(self, tox_id): def delete_friend_from_db(self, tox_id):
chdir(settings.ProfileHelper.get_path()) chdir(settings.ProfileManager.get_path())
db = connect(self._name + '.hstr', timeout=TIMEOUT) db = connect(self._name + '.hstr', timeout=TIMEOUT)
try: try:
cursor = db.cursor() cursor = db.cursor()
@ -98,7 +100,7 @@ class History:
db.close() db.close()
def friend_exists_in_db(self, tox_id): def friend_exists_in_db(self, tox_id):
chdir(settings.ProfileHelper.get_path()) chdir(settings.ProfileManager.get_path())
db = connect(self._name + '.hstr', timeout=TIMEOUT) db = connect(self._name + '.hstr', timeout=TIMEOUT)
cursor = db.cursor() cursor = db.cursor()
cursor.execute('SELECT 0 FROM friends WHERE tox_id=?', (tox_id, )) cursor.execute('SELECT 0 FROM friends WHERE tox_id=?', (tox_id, ))
@ -107,7 +109,7 @@ class History:
return result is not None return result is not None
def save_messages_to_db(self, tox_id, messages_iter): def save_messages_to_db(self, tox_id, messages_iter):
chdir(settings.ProfileHelper.get_path()) chdir(settings.ProfileManager.get_path())
db = connect(self._name + '.hstr', timeout=TIMEOUT) db = connect(self._name + '.hstr', timeout=TIMEOUT)
try: try:
cursor = db.cursor() cursor = db.cursor()
@ -121,7 +123,7 @@ class History:
db.close() db.close()
def update_messages(self, tox_id, unsent_time): def update_messages(self, tox_id, unsent_time):
chdir(settings.ProfileHelper.get_path()) chdir(settings.ProfileManager.get_path())
db = connect(self._name + '.hstr', timeout=TIMEOUT) db = connect(self._name + '.hstr', timeout=TIMEOUT)
try: try:
cursor = db.cursor() cursor = db.cursor()
@ -136,7 +138,7 @@ class History:
def delete_message(self, tox_id, time): def delete_message(self, tox_id, time):
start, end = str(time - 0.01), str(time + 0.01) start, end = str(time - 0.01), str(time + 0.01)
chdir(settings.ProfileHelper.get_path()) chdir(settings.ProfileManager.get_path())
db = connect(self._name + '.hstr', timeout=TIMEOUT) db = connect(self._name + '.hstr', timeout=TIMEOUT)
try: try:
cursor = db.cursor() cursor = db.cursor()
@ -150,7 +152,7 @@ class History:
db.close() db.close()
def delete_messages(self, tox_id): def delete_messages(self, tox_id):
chdir(settings.ProfileHelper.get_path()) chdir(settings.ProfileManager.get_path())
db = connect(self._name + '.hstr', timeout=TIMEOUT) db = connect(self._name + '.hstr', timeout=TIMEOUT)
try: try:
cursor = db.cursor() cursor = db.cursor()
@ -174,7 +176,7 @@ class History:
self._db = self._cursor = None self._db = self._cursor = None
def connect(self): def connect(self):
chdir(settings.ProfileHelper.get_path()) chdir(settings.ProfileManager.get_path())
self._db = connect(self._name + '.hstr', timeout=TIMEOUT) self._db = connect(self._name + '.hstr', timeout=TIMEOUT)
self._cursor = self._db.cursor() self._cursor = self._db.cursor()
self._cursor.execute('SELECT message, owner, unix_time, message_type FROM id' + self._tox_id + self._cursor.execute('SELECT message, owner, unix_time, message_type FROM id' + self._tox_id +

View File

@ -1,9 +1,9 @@
from toxcore_enums_and_consts import TOX_FILE_KIND, TOX_FILE_CONTROL from wrapper.toxcore_enums_and_consts import TOX_FILE_KIND, TOX_FILE_CONTROL
from os.path import basename, getsize, exists, dirname from os.path import basename, getsize, exists, dirname
from os import remove, rename, chdir from os import remove, rename, chdir
from time import time, sleep from time import time, sleep
from tox import Tox from wrapper.tox import Tox
import settings from user_data import settings
from PyQt5 import QtCore from PyQt5 import QtCore
@ -305,7 +305,7 @@ class ReceiveAvatar(ReceiveTransfer):
MAX_AVATAR_SIZE = 512 * 1024 MAX_AVATAR_SIZE = 512 * 1024
def __init__(self, tox, friend_number, size, file_number): def __init__(self, tox, friend_number, size, file_number):
path = settings.ProfileHelper.get_path() + 'avatars/{}.png'.format(tox.friend_get_public_key(friend_number)) path = settings.ProfileManager.get_path() + 'avatars/{}.png'.format(tox.friend_get_public_key(friend_number))
super(ReceiveAvatar, self).__init__(path + '.tmp', tox, friend_number, size, file_number) super(ReceiveAvatar, self).__init__(path + '.tmp', tox, friend_number, size, file_number)
if size > self.MAX_AVATAR_SIZE: if size > self.MAX_AVATAR_SIZE:
self.send_control(TOX_FILE_CONTROL['CANCEL']) self.send_control(TOX_FILE_CONTROL['CANCEL'])

0
toxygen/login.py Normal file
View File

View File

@ -1,434 +1,11 @@
import sys import sys
from loginscreen import LoginScreen from user_data.settings import *
import profile
from settings import *
from PyQt5 import QtCore, QtGui, QtWidgets
from bootstrap import generate_nodes, download_nodes_list
from mainscreen import MainWindow
from callbacks import init_callbacks, stop, start from callbacks import init_callbacks, stop, start
from util import curr_directory, program_version, remove from util import curr_directory, program_version, remove
import styles.style # reqired for styles loading
import platform
import toxes
from passwordscreen import PasswordScreen, UnlockAppScreen, SetProfilePasswordScreen
from plugin_support import PluginLoader
import updater import updater
import argparse
class Toxygen:
def __init__(self, path_or_uri=None):
super(Toxygen, self).__init__()
self.tox = self.ms = self.init = self.app = self.tray = self.mainloop = self.avloop = None
if path_or_uri is None:
self.uri = self.path = None
elif path_or_uri.startswith('tox:'):
self.path = None
self.uri = path_or_uri[4:]
else:
self.path = path_or_uri
self.uri = None
def enter_pass(self, data):
"""
Show password screen
"""
tmp = [data]
p = PasswordScreen(toxes.ToxES.get_instance(), tmp)
p.show()
self.app.lastWindowClosed.connect(self.app.quit)
self.app.exec_()
if tmp[0] == data:
raise SystemExit()
else:
return tmp[0]
def main(self):
"""
Main function of app. loads login screen if needed and starts main screen
"""
app = QtWidgets.QApplication(sys.argv)
app.setWindowIcon(QtGui.QIcon(curr_directory() + '/images/icon.png'))
self.app = app
if platform.system() == 'Linux':
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_X11InitThreads)
with open(curr_directory() + '/styles/dark_style.qss') as fl:
style = fl.read()
app.setStyleSheet(style)
encrypt_save = toxes.ToxES()
if self.path is not None:
path = os.path.dirname(self.path) + '/'
name = os.path.basename(self.path)[:-4]
data = ProfileHelper(path, name).open_profile()
if encrypt_save.is_data_encrypted(data):
data = self.enter_pass(data)
settings = Settings(name)
self.tox = profile.tox_factory(data, settings)
else:
auto_profile = Settings.get_auto_profile()
if not auto_profile[0]:
# show login screen if default profile not found
current_locale = QtCore.QLocale()
curr_lang = current_locale.languageToString(current_locale.language())
langs = Settings.supported_languages()
if curr_lang in langs:
lang_path = langs[curr_lang]
translator = QtCore.QTranslator()
translator.load(curr_directory() + '/translations/' + lang_path)
app.installTranslator(translator)
app.translator = translator
ls = LoginScreen()
ls.setWindowIconText("Toxygen")
profiles = ProfileHelper.find_profiles()
ls.update_select(map(lambda x: x[1], profiles))
_login = self.Login(profiles)
ls.update_on_close(_login.login_screen_close)
ls.show()
app.exec_()
if not _login.t:
return
elif _login.t == 1: # create new profile
_login.name = _login.name.strip()
name = _login.name if _login.name else 'toxygen_user'
pr = map(lambda x: x[1], ProfileHelper.find_profiles())
if name in list(pr):
msgBox = QtWidgets.QMessageBox()
msgBox.setWindowTitle(
QtWidgets.QApplication.translate("MainWindow", "Error"))
text = (QtWidgets.QApplication.translate("MainWindow",
'Profile with this name already exists'))
msgBox.setText(text)
msgBox.exec_()
return
self.tox = profile.tox_factory()
self.tox.self_set_name(bytes(_login.name, 'utf-8') if _login.name else b'Toxygen User')
self.tox.self_set_status_message(b'Toxing on Toxygen')
reply = QtWidgets.QMessageBox.question(None,
'Profile {}'.format(name),
QtWidgets.QApplication.translate("login",
'Do you want to set profile password?'),
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
set_pass = SetProfilePasswordScreen(encrypt_save)
set_pass.show()
self.app.lastWindowClosed.connect(self.app.quit)
self.app.exec_()
reply = QtWidgets.QMessageBox.question(None,
'Profile {}'.format(name),
QtWidgets.QApplication.translate("login",
'Do you want to save profile in default folder? If no, profile will be saved in program folder'),
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
path = Settings.get_default_path()
else:
path = curr_directory() + '/'
try:
ProfileHelper(path, name).save_profile(self.tox.get_savedata())
except Exception as ex:
print(str(ex))
log('Profile creation exception: ' + str(ex))
msgBox = QtWidgets.QMessageBox()
msgBox.setText(QtWidgets.QApplication.translate("login",
'Profile saving error! Does Toxygen have permission to write to this directory?'))
msgBox.exec_()
return
path = Settings.get_default_path()
settings = Settings(name)
if curr_lang in langs:
settings['language'] = curr_lang
settings.save()
else: # load existing profile
path, name = _login.get_data()
if _login.default:
Settings.set_auto_profile(path, name)
data = ProfileHelper(path, name).open_profile()
if encrypt_save.is_data_encrypted(data):
data = self.enter_pass(data)
settings = Settings(name)
self.tox = profile.tox_factory(data, settings)
else:
path, name = auto_profile
data = ProfileHelper(path, name).open_profile()
if encrypt_save.is_data_encrypted(data):
data = self.enter_pass(data)
settings = Settings(name)
self.tox = profile.tox_factory(data, settings)
if Settings.is_active_profile(path, name): # profile is in use
reply = QtWidgets.QMessageBox.question(None,
'Profile {}'.format(name),
QtWidgets.QApplication.translate("login", 'Other instance of Toxygen uses this profile or profile was not properly closed. Continue?'),
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No)
if reply != QtWidgets.QMessageBox.Yes:
return
else:
settings.set_active_profile()
# application color scheme
for theme in settings.built_in_themes().keys():
if settings['theme'] == theme:
with open(curr_directory() + settings.built_in_themes()[theme]) as fl:
style = fl.read()
app.setStyleSheet(style)
lang = Settings.supported_languages()[settings['language']]
translator = QtCore.QTranslator()
translator.load(curr_directory() + '/translations/' + lang)
app.installTranslator(translator)
app.translator = translator
# tray icon
self.tray = QtWidgets.QSystemTrayIcon(QtGui.QIcon(curr_directory() + '/images/icon.png'))
self.tray.setObjectName('tray')
self.ms = MainWindow(self.tox, self.reset, self.tray)
app.aboutToQuit.connect(self.ms.close_window)
class Menu(QtWidgets.QMenu):
def newStatus(self, status):
if not Settings.get_instance().locked:
profile.Profile.get_instance().set_status(status)
self.aboutToShowHandler()
self.hide()
def aboutToShowHandler(self):
status = profile.Profile.get_instance().status
act = self.act
if status is None or Settings.get_instance().locked:
self.actions()[1].setVisible(False)
else:
self.actions()[1].setVisible(True)
act.actions()[0].setChecked(False)
act.actions()[1].setChecked(False)
act.actions()[2].setChecked(False)
act.actions()[status].setChecked(True)
self.actions()[2].setVisible(not Settings.get_instance().locked)
def languageChange(self, *args, **kwargs):
self.actions()[0].setText(QtWidgets.QApplication.translate('tray', 'Open Toxygen'))
self.actions()[1].setText(QtWidgets.QApplication.translate('tray', 'Set status'))
self.actions()[2].setText(QtWidgets.QApplication.translate('tray', 'Exit'))
self.act.actions()[0].setText(QtWidgets.QApplication.translate('tray', 'Online'))
self.act.actions()[1].setText(QtWidgets.QApplication.translate('tray', 'Away'))
self.act.actions()[2].setText(QtWidgets.QApplication.translate('tray', 'Busy'))
m = Menu()
show = m.addAction(QtWidgets.QApplication.translate('tray', 'Open Toxygen'))
sub = m.addMenu(QtWidgets.QApplication.translate('tray', 'Set status'))
onl = sub.addAction(QtWidgets.QApplication.translate('tray', 'Online'))
away = sub.addAction(QtWidgets.QApplication.translate('tray', 'Away'))
busy = sub.addAction(QtWidgets.QApplication.translate('tray', 'Busy'))
onl.setCheckable(True)
away.setCheckable(True)
busy.setCheckable(True)
m.act = sub
exit = m.addAction(QtWidgets.QApplication.translate('tray', 'Exit'))
def show_window():
s = Settings.get_instance()
def show():
if not self.ms.isActiveWindow():
self.ms.setWindowState(self.ms.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive)
self.ms.activateWindow()
self.ms.show()
if not s.locked:
show()
else:
def correct_pass():
show()
s.locked = False
s.unlockScreen = False
if not s.unlockScreen:
s.unlockScreen = True
self.p = UnlockAppScreen(toxes.ToxES.get_instance(), correct_pass)
self.p.show()
def tray_activated(reason):
if reason == QtWidgets.QSystemTrayIcon.DoubleClick:
show_window()
def close_app():
if not Settings.get_instance().locked:
settings.closing = True
self.ms.close()
show.triggered.connect(show_window)
exit.triggered.connect(close_app)
m.aboutToShow.connect(lambda: m.aboutToShowHandler())
onl.triggered.connect(lambda: m.newStatus(0))
away.triggered.connect(lambda: m.newStatus(1))
busy.triggered.connect(lambda: m.newStatus(2))
self.tray.setContextMenu(m)
self.tray.show()
self.tray.activated.connect(tray_activated)
self.ms.show()
updating = False
if settings['update'] and updater.updater_available() and updater.connection_available(): # auto update
version = updater.check_for_updates()
if version is not None:
if settings['update'] == 2:
updater.download(version)
updating = True
else:
reply = QtWidgets.QMessageBox.question(None,
'Toxygen',
QtWidgets.QApplication.translate("login",
'Update for Toxygen was found. Download and install it?'),
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
updater.download(version)
updating = True
if updating:
data = self.tox.get_savedata()
ProfileHelper.get_instance().save_profile(data)
settings.close()
del self.tox
return
plugin_helper = PluginLoader(self.tox, settings) # plugin support
plugin_helper.load()
start()
# init thread
self.init = self.InitThread(self.tox, self.ms, self.tray)
self.init.start()
# starting threads for tox iterate and toxav iterate
self.mainloop = self.ToxIterateThread(self.tox)
self.mainloop.start()
self.avloop = self.ToxAVIterateThread(self.tox.AV)
self.avloop.start()
if self.uri is not None:
self.ms.add_contact(self.uri)
app.lastWindowClosed.connect(app.quit)
app.exec_()
self.init.stop = True
self.mainloop.stop = True
self.avloop.stop = True
plugin_helper.stop()
stop()
self.mainloop.wait()
self.init.wait()
self.avloop.wait()
self.tray.hide()
data = self.tox.get_savedata()
ProfileHelper.get_instance().save_profile(data)
settings.close()
del self.tox
def reset(self):
"""
Create new tox instance (new network settings)
:return: tox instance
"""
self.mainloop.stop = True
self.init.stop = True
self.avloop.stop = True
self.mainloop.wait()
self.init.wait()
self.avloop.wait()
data = self.tox.get_savedata()
ProfileHelper.get_instance().save_profile(data)
del self.tox
# create new tox instance
self.tox = profile.tox_factory(data, Settings.get_instance())
# init thread
self.init = self.InitThread(self.tox, self.ms, self.tray)
self.init.start()
# starting threads for tox iterate and toxav iterate
self.mainloop = self.ToxIterateThread(self.tox)
self.mainloop.start()
self.avloop = self.ToxAVIterateThread(self.tox.AV)
self.avloop.start()
plugin_helper = PluginLoader.get_instance()
plugin_helper.set_tox(self.tox)
return self.tox
# -----------------------------------------------------------------------------------------------------------------
# Inner classes
# -----------------------------------------------------------------------------------------------------------------
class InitThread(QtCore.QThread):
def __init__(self, tox, ms, tray):
QtCore.QThread.__init__(self)
self.tox, self.ms, self.tray = tox, ms, tray
self.stop = False
def run(self):
# initializing callbacks
init_callbacks(self.tox, self.ms, self.tray)
# download list of nodes if needed
download_nodes_list()
# bootstrap
try:
for data in generate_nodes():
if self.stop:
return
self.tox.bootstrap(*data)
self.tox.add_tcp_relay(*data)
except:
pass
for _ in range(10):
if self.stop:
return
self.msleep(1000)
while not self.tox.self_get_connection_status():
try:
for data in generate_nodes():
if self.stop:
return
self.tox.bootstrap(*data)
self.tox.add_tcp_relay(*data)
except:
pass
finally:
self.msleep(5000)
class ToxIterateThread(QtCore.QThread):
def __init__(self, tox):
QtCore.QThread.__init__(self)
self.tox = tox
self.stop = False
def run(self):
while not self.stop:
self.tox.iterate()
self.msleep(self.tox.iteration_interval())
class ToxAVIterateThread(QtCore.QThread):
def __init__(self, toxav):
QtCore.QThread.__init__(self)
self.toxav = toxav
self.stop = False
def run(self):
while not self.stop:
self.toxav.iterate()
self.msleep(self.toxav.iteration_interval())
class Login: class Login:
@ -462,7 +39,12 @@ def reset():
def main(): def main():
if len(sys.argv) == 1: parser = argparse.ArgumentParser()
parser.add_argument('--version')
parser.add_argument('--clean')
parser.add_argument('--reset')
args = parser.parse_args()
if not len(args):
toxygen = Toxygen() toxygen = Toxygen()
else: # started with argument(s) else: # started with argument(s)
arg = sys.argv[1] arg = sys.argv[1]

View File

View File

View File

@ -1,7 +1,7 @@
import json import json
import urllib.request import urllib.request
from util import log from util import log
import settings from user_data import settings
from PyQt5 import QtNetwork, QtCore from PyQt5 import QtNetwork, QtCore

View File

View File

@ -1,10 +1,10 @@
import util import util
import profile from contacts import profile
import os import os
import importlib import importlib
import inspect import inspect
import plugins.plugin_super_class as pl import plugins.plugin_super_class as pl
import toxes from user_data import toxes
import sys import sys

62
toxygen/threads.py Normal file
View File

@ -0,0 +1,62 @@
class InitThread(QtCore.QThread):
def __init__(self, tox, ms, tray):
QtCore.QThread.__init__(self)
self.tox, self.ms, self.tray = tox, ms, tray
self.stop = False
def run(self):
# initializing callbacks
init_callbacks(self.tox, self.ms, self.tray)
# download list of nodes if needed
download_nodes_list()
# bootstrap
try:
for data in generate_nodes():
if self.stop:
return
self.tox.bootstrap(*data)
self.tox.add_tcp_relay(*data)
except:
pass
for _ in range(10):
if self.stop:
return
self.msleep(1000)
while not self.tox.self_get_connection_status():
try:
for data in generate_nodes():
if self.stop:
return
self.tox.bootstrap(*data)
self.tox.add_tcp_relay(*data)
except:
pass
finally:
self.msleep(5000)
class ToxIterateThread(QtCore.QThread):
def __init__(self, tox):
QtCore.QThread.__init__(self)
self.tox = tox
self.stop = False
def run(self):
while not self.stop:
self.tox.iterate()
self.msleep(self.tox.iteration_interval())
class ToxAVIterateThread(QtCore.QThread):
def __init__(self, toxav):
QtCore.QThread.__init__(self)
self.toxav = toxav
self.stop = False
def run(self):
while not self.stop:
self.toxav.iterate()
self.msleep(self.toxav.iteration_interval())

View File

@ -1,220 +0,0 @@
TOX_USER_STATUS = {
'NONE': 0,
'AWAY': 1,
'BUSY': 2,
}
TOX_MESSAGE_TYPE = {
'NORMAL': 0,
'ACTION': 1,
}
TOX_PROXY_TYPE = {
'NONE': 0,
'HTTP': 1,
'SOCKS5': 2,
}
TOX_SAVEDATA_TYPE = {
'NONE': 0,
'TOX_SAVE': 1,
'SECRET_KEY': 2,
}
TOX_ERR_OPTIONS_NEW = {
'OK': 0,
'MALLOC': 1,
}
TOX_ERR_NEW = {
'OK': 0,
'NULL': 1,
'MALLOC': 2,
'PORT_ALLOC': 3,
'PROXY_BAD_TYPE': 4,
'PROXY_BAD_HOST': 5,
'PROXY_BAD_PORT': 6,
'PROXY_NOT_FOUND': 7,
'LOAD_ENCRYPTED': 8,
'LOAD_BAD_FORMAT': 9,
}
TOX_ERR_BOOTSTRAP = {
'OK': 0,
'NULL': 1,
'BAD_HOST': 2,
'BAD_PORT': 3,
}
TOX_CONNECTION = {
'NONE': 0,
'TCP': 1,
'UDP': 2,
}
TOX_ERR_SET_INFO = {
'OK': 0,
'NULL': 1,
'TOO_LONG': 2,
}
TOX_ERR_FRIEND_ADD = {
'OK': 0,
'NULL': 1,
'TOO_LONG': 2,
'NO_MESSAGE': 3,
'OWN_KEY': 4,
'ALREADY_SENT': 5,
'BAD_CHECKSUM': 6,
'SET_NEW_NOSPAM': 7,
'MALLOC': 8,
}
TOX_ERR_FRIEND_DELETE = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
}
TOX_ERR_FRIEND_BY_PUBLIC_KEY = {
'OK': 0,
'NULL': 1,
'NOT_FOUND': 2,
}
TOX_ERR_FRIEND_GET_PUBLIC_KEY = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
}
TOX_ERR_FRIEND_GET_LAST_ONLINE = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
}
TOX_ERR_FRIEND_QUERY = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
}
TOX_ERR_SET_TYPING = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
}
TOX_ERR_FRIEND_SEND_MESSAGE = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
'FRIEND_NOT_CONNECTED': 3,
'SENDQ': 4,
'TOO_LONG': 5,
'EMPTY': 6,
}
TOX_FILE_KIND = {
'DATA': 0,
'AVATAR': 1,
}
TOX_FILE_CONTROL = {
'RESUME': 0,
'PAUSE': 1,
'CANCEL': 2,
}
TOX_ERR_FILE_CONTROL = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
'FRIEND_NOT_CONNECTED': 2,
'NOT_FOUND': 3,
'NOT_PAUSED': 4,
'DENIED': 5,
'ALREADY_PAUSED': 6,
'SENDQ': 7,
}
TOX_ERR_FILE_SEEK = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
'FRIEND_NOT_CONNECTED': 2,
'NOT_FOUND': 3,
'DENIED': 4,
'INVALID_POSITION': 5,
'SENDQ': 6,
}
TOX_ERR_FILE_GET = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
'NOT_FOUND': 3,
}
TOX_ERR_FILE_SEND = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
'FRIEND_NOT_CONNECTED': 3,
'NAME_TOO_LONG': 4,
'TOO_MANY': 5,
}
TOX_ERR_FILE_SEND_CHUNK = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
'FRIEND_NOT_CONNECTED': 3,
'NOT_FOUND': 4,
'NOT_TRANSFERRING': 5,
'INVALID_LENGTH': 6,
'SENDQ': 7,
'WRONG_POSITION': 8,
}
TOX_ERR_FRIEND_CUSTOM_PACKET = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
'FRIEND_NOT_CONNECTED': 3,
'INVALID': 4,
'EMPTY': 5,
'TOO_LONG': 6,
'SENDQ': 7,
}
TOX_ERR_GET_PORT = {
'OK': 0,
'NOT_BOUND': 1,
}
TOX_CHAT_CHANGE = {
'PEER_ADD': 0,
'PEER_DEL': 1,
'PEER_NAME': 2
}
TOX_GROUPCHAT_TYPE = {
'TEXT': 0,
'AV': 1
}
TOX_PUBLIC_KEY_SIZE = 32
TOX_ADDRESS_SIZE = TOX_PUBLIC_KEY_SIZE + 6
TOX_MAX_FRIEND_REQUEST_LENGTH = 1016
TOX_MAX_MESSAGE_LENGTH = 1372
TOX_MAX_NAME_LENGTH = 128
TOX_MAX_STATUS_MESSAGE_LENGTH = 1007
TOX_SECRET_KEY_SIZE = 32
TOX_FILE_ID_LENGTH = 32
TOX_HASH_LENGTH = 32
TOX_MAX_CUSTOM_PACKET_SIZE = 1373

83
toxygen/tray.py Normal file
View File

@ -0,0 +1,83 @@
self.tray = QtWidgets.QSystemTrayIcon(QtGui.QIcon(curr_directory() + '/images/icon.png'))
self.tray.setObjectName('tray')
class Menu(QtWidgets.QMenu):
def newStatus(self, status):
if not Settings.get_instance().locked:
profile.Profile.get_instance().set_status(status)
self.aboutToShowHandler()
self.hide()
def aboutToShowHandler(self):
status = profile.Profile.get_instance().status
act = self.act
if status is None or Settings.get_instance().locked:
self.actions()[1].setVisible(False)
else:
self.actions()[1].setVisible(True)
act.actions()[0].setChecked(False)
act.actions()[1].setChecked(False)
act.actions()[2].setChecked(False)
act.actions()[status].setChecked(True)
self.actions()[2].setVisible(not Settings.get_instance().locked)
def languageChange(self, *args, **kwargs):
self.actions()[0].setText(QtWidgets.QApplication.translate('tray', 'Open Toxygen'))
self.actions()[1].setText(QtWidgets.QApplication.translate('tray', 'Set status'))
self.actions()[2].setText(QtWidgets.QApplication.translate('tray', 'Exit'))
self.act.actions()[0].setText(QtWidgets.QApplication.translate('tray', 'Online'))
self.act.actions()[1].setText(QtWidgets.QApplication.translate('tray', 'Away'))
self.act.actions()[2].setText(QtWidgets.QApplication.translate('tray', 'Busy'))
m = Menu()
show = m.addAction(QtWidgets.QApplication.translate('tray', 'Open Toxygen'))
sub = m.addMenu(QtWidgets.QApplication.translate('tray', 'Set status'))
onl = sub.addAction(QtWidgets.QApplication.translate('tray', 'Online'))
away = sub.addAction(QtWidgets.QApplication.translate('tray', 'Away'))
busy = sub.addAction(QtWidgets.QApplication.translate('tray', 'Busy'))
onl.setCheckable(True)
away.setCheckable(True)
busy.setCheckable(True)
m.act = sub
exit = m.addAction(QtWidgets.QApplication.translate('tray', 'Exit'))
def show_window():
s = Settings.get_instance()
def show():
if not self.ms.isActiveWindow():
self.ms.setWindowState(self.ms.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive)
self.ms.activateWindow()
self.ms.show()
if not s.locked:
show()
else:
def correct_pass():
show()
s.locked = False
s.unlockScreen = False
if not s.unlockScreen:
s.unlockScreen = True
self.p = UnlockAppScreen(toxes.ToxES.get_instance(), correct_pass)
self.p.show()
def tray_activated(reason):
if reason == QtWidgets.QSystemTrayIcon.DoubleClick:
show_window()
def close_app():
if not Settings.get_instance().locked:
settings.closing = True
self.ms.close()
show.triggered.connect(show_window)
exit.triggered.connect(close_app)
m.aboutToShow.connect(lambda: m.aboutToShowHandler())
onl.triggered.connect(lambda: m.newStatus(0))
away.triggered.connect(lambda: m.newStatus(1))
busy.triggered.connect(lambda: m.newStatus(2))
self.tray.setContextMenu(m)
self.tray.show()
self.tray.activated.connect(tray_activated)

0
toxygen/ui/__init__.py Normal file
View File

View File

@ -1,10 +1,10 @@
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
import widgets from ui import widgets
import profile from contacts import profile
import util import util
import pyaudio import pyaudio
import wave import wave
import settings from user_data import settings
from util import curr_directory from util import curr_directory

View File

@ -1,5 +1,4 @@
from PyQt5 import QtWidgets, QtCore from ui.list_items import *
from list_items import *
class ItemsFactory: class ItemsFactory:

View File

@ -1,12 +1,12 @@
from toxcore_enums_and_consts import * from wrapper.toxcore_enums_and_consts import *
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
import profile 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_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 util import curr_directory, convert_time, curr_time
from widgets import DataLabel, create_menu from ui.widgets import DataLabel, create_menu
import html as h import html as h
import smileys import smileys
import settings from user_data import settings
import re import re
@ -60,7 +60,7 @@ class MessageEdit(QtWidgets.QTextBrowser):
def quote_text(self): def quote_text(self):
text = self.textCursor().selection().toPlainText() text = self.textCursor().selection().toPlainText()
if text: if text:
import mainscreen from ui import mainscreen
window = mainscreen.MainWindow.get_instance() window = mainscreen.MainWindow.get_instance()
text = '>' + '\n>'.join(text.split('\n')) text = '>' + '\n>'.join(text.split('\n'))
if window.messageEdit.toPlainText(): if window.messageEdit.toPlainText():
@ -70,7 +70,7 @@ class MessageEdit(QtWidgets.QTextBrowser):
def on_anchor_clicked(self, url): def on_anchor_clicked(self, url):
text = str(url.toString()) text = str(url.toString())
if text.startswith('tox:'): if text.startswith('tox:'):
import menu from ui import menu
self.add_contact = menu.AddContact(text[4:]) self.add_contact = menu.AddContact(text[4:])
self.add_contact.show() self.add_contact.show()
else: else:

View File

@ -1,5 +1,4 @@
from PyQt5 import QtWidgets, QtCore from ui.widgets import *
from widgets import *
class NickEdit(LineEdit): class NickEdit(LineEdit):

View File

@ -1,11 +1,10 @@
from menu import * from ui.menu import *
from profile import * from contacts.profile import *
from list_items import * from ui.list_items import *
from widgets import MultilineEdit, ComboBox from ui.widgets import MultilineEdit, ComboBox
import plugin_support import plugin_support
from mainscreen_widgets import * from ui.mainscreen_widgets import *
import settings from user_data import toxes, settings
import toxes
class MainWindow(QtWidgets.QMainWindow, Singleton): class MainWindow(QtWidgets.QMainWindow, Singleton):

View File

@ -1,6 +1,6 @@
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
from widgets import RubberBandWindow, create_menu, QRightClickButton, CenteredWidget, LineEdit from ui.widgets import RubberBandWindow, create_menu, QRightClickButton, CenteredWidget, LineEdit
from profile import Profile from contacts.profile import Profile
import smileys import smileys
import util import util
@ -333,7 +333,7 @@ class WelcomeScreen(CenteredWidget):
QtCore.QTimer.singleShot(1000, self.show) QtCore.QTimer.singleShot(1000, self.show)
def not_show(self): def not_show(self):
import settings from user_data import settings
s = settings.Settings.get_instance() s = settings.Settings.get_instance()
s['show_welcome_screen'] = False s['show_welcome_screen'] = False
s.save() s.save()

View File

@ -1,10 +1,10 @@
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
from settings import * from user_data.settings import *
from profile import Profile from contacts.profile import Profile
from util import curr_directory, copy from util import curr_directory, copy
from widgets import CenteredWidget, DataLabel, LineEdit, RubberBandWindow from ui.widgets import CenteredWidget, DataLabel, LineEdit, RubberBandWindow
import pyaudio import pyaudio
import toxes from user_data import toxes
import plugin_support import plugin_support
import updater import updater
@ -160,7 +160,7 @@ class ProfileSettings(CenteredWidget):
self.default = QtWidgets.QPushButton(self) self.default = QtWidgets.QPushButton(self)
self.default.setGeometry(QtCore.QRect(40, 550, 620, 30)) self.default.setGeometry(QtCore.QRect(40, 550, 620, 30))
path, name = Settings.get_auto_profile() path, name = Settings.get_auto_profile()
self.auto = path + name == ProfileHelper.get_path() + Settings.get_instance().name self.auto = path + name == ProfileManager.get_path() + Settings.get_instance().name
self.default.clicked.connect(self.auto_profile) self.default.clicked.connect(self.auto_profile)
self.retranslateUi() self.retranslateUi()
if profile.status is not None: if profile.status is not None:
@ -199,7 +199,7 @@ class ProfileSettings(CenteredWidget):
if self.auto: if self.auto:
Settings.reset_auto_profile() Settings.reset_auto_profile()
else: else:
Settings.set_auto_profile(ProfileHelper.get_path(), Settings.get_instance().name) Settings.set_auto_profile(ProfileManager.get_path(), Settings.get_instance().name)
self.auto = not self.auto self.auto = not self.auto
if self.auto: if self.auto:
self.default.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Mark as not default profile")) self.default.setText(QtWidgets.QApplication.translate("ProfileSettingsForm", "Mark as not default profile"))
@ -275,7 +275,7 @@ class ProfileSettings(CenteredWidget):
settings.export(directory) settings.export(directory)
profile = Profile.get_instance() profile = Profile.get_instance()
profile.export_db(directory) profile.export_db(directory)
ProfileHelper.get_instance().export_profile(directory, reply == QtWidgets.QMessageBox.Yes) ProfileManager.get_instance().export_profile(directory, reply == QtWidgets.QMessageBox.Yes)
def closeEvent(self, event): def closeEvent(self, event):
profile = Profile.get_instance() profile = Profile.get_instance()

View File

@ -1,4 +1,4 @@
from widgets import CenteredWidget, LineEdit from ui.widgets import CenteredWidget, LineEdit
from PyQt5 import QtCore, QtWidgets from PyQt5 import QtCore, QtWidgets

View File

View File

@ -1,6 +1,6 @@
import util import util
import os import os
import settings from user_data import settings
import platform import platform
import urllib import urllib
from PyQt5 import QtNetwork, QtCore from PyQt5 import QtNetwork, QtCore

View File

View File

@ -0,0 +1,70 @@
class ProfileManager():
"""
Class with methods for search, load and save profiles
"""
def __init__(self, path, name):
path = append_slash(path)
self._path = path + name + '.tox'
self._directory = path
# create /avatars if not exists:
directory = path + 'avatars'
if not os.path.exists(directory):
os.makedirs(directory)
def open_profile(self):
with open(self._path, 'rb') as fl:
data = fl.read()
if data:
return data
else:
raise IOError('Save file has zero size!')
def get_dir(self):
return self._directory
def save_profile(self, data):
inst = ToxES.get_instance()
if inst.has_password():
data = inst.pass_encrypt(data)
with open(self._path, 'wb') as fl:
fl.write(data)
print('Profile saved successfully')
def export_profile(self, new_path, use_new_path):
path = new_path + os.path.basename(self._path)
with open(self._path, 'rb') as fin:
data = fin.read()
with open(path, 'wb') as fout:
fout.write(data)
print('Profile exported successfully')
copy(self._directory + 'avatars', new_path + 'avatars')
if use_new_path:
self._path = new_path + os.path.basename(self._path)
self._directory = new_path
Settings.get_instance().update_path()
@staticmethod
def find_profiles():
"""
Find available tox profiles
"""
path = Settings.get_default_path()
result = []
# check default path
if not os.path.exists(path):
os.makedirs(path)
for fl in os.listdir(path):
if fl.endswith('.tox'):
name = fl[:-4]
result.append((path, name))
path = curr_directory()
# check current directory
for fl in os.listdir(path):
if fl.endswith('.tox'):
name = fl[:-4]
result.append((path + '/', name))
return result
@staticmethod
def get_path():
return ProfileManager.get_instance().get_dir()

View File

@ -3,7 +3,7 @@ import json
import os import os
from util import Singleton, curr_directory, log, copy, append_slash from util import Singleton, curr_directory, log, copy, append_slash
import pyaudio import pyaudio
from toxes import ToxES from user_data.toxes import ToxES
import smileys import smileys
@ -14,7 +14,7 @@ class Settings(dict, Singleton):
def __init__(self, name): def __init__(self, name):
Singleton.__init__(self) Singleton.__init__(self)
self.path = ProfileHelper.get_path() + str(name) + '.json' self.path = ProfileManager.get_path() + str(name) + '.json'
self.name = name self.name = name
if os.path.isfile(self.path): if os.path.isfile(self.path):
with open(self.path, 'rb') as fl: with open(self.path, 'rb') as fl:
@ -184,7 +184,7 @@ class Settings(dict, Singleton):
fl.write(text) fl.write(text)
def close(self): def close(self):
profile_path = ProfileHelper.get_path() profile_path = ProfileManager.get_path()
path = str(profile_path + str(self.name) + '.lock') path = str(profile_path + str(self.name) + '.lock')
if os.path.isfile(path): if os.path.isfile(path):
os.remove(path) os.remove(path)
@ -193,7 +193,7 @@ class Settings(dict, Singleton):
""" """
Mark current profile as active Mark current profile as active
""" """
profile_path = ProfileHelper.get_path() profile_path = ProfileManager.get_path()
path = str(profile_path + str(self.name) + '.lock') path = str(profile_path + str(self.name) + '.lock')
with open(path, 'w') as fl: with open(path, 'w') as fl:
fl.write('active') fl.write('active')
@ -204,7 +204,7 @@ class Settings(dict, Singleton):
fl.write(text) fl.write(text)
def update_path(self): def update_path(self):
self.path = ProfileHelper.get_path() + self.name + '.json' self.path = ProfileManager.get_path() + self.name + '.json'
@staticmethod @staticmethod
def get_global_settings_path(): def get_global_settings_path():
@ -219,75 +219,3 @@ class Settings(dict, Singleton):
else: else:
return os.getenv('HOME') + '/.config/tox/' return os.getenv('HOME') + '/.config/tox/'
class ProfileHelper(Singleton):
"""
Class with methods for search, load and save profiles
"""
def __init__(self, path, name):
Singleton.__init__(self)
path = append_slash(path)
self._path = path + name + '.tox'
self._directory = path
# create /avatars if not exists:
directory = path + 'avatars'
if not os.path.exists(directory):
os.makedirs(directory)
def open_profile(self):
with open(self._path, 'rb') as fl:
data = fl.read()
if data:
return data
else:
raise IOError('Save file has zero size!')
def get_dir(self):
return self._directory
def save_profile(self, data):
inst = ToxES.get_instance()
if inst.has_password():
data = inst.pass_encrypt(data)
with open(self._path, 'wb') as fl:
fl.write(data)
print('Profile saved successfully')
def export_profile(self, new_path, use_new_path):
path = new_path + os.path.basename(self._path)
with open(self._path, 'rb') as fin:
data = fin.read()
with open(path, 'wb') as fout:
fout.write(data)
print('Profile exported successfully')
copy(self._directory + 'avatars', new_path + 'avatars')
if use_new_path:
self._path = new_path + os.path.basename(self._path)
self._directory = new_path
Settings.get_instance().update_path()
@staticmethod
def find_profiles():
"""
Find available tox profiles
"""
path = Settings.get_default_path()
result = []
# check default path
if not os.path.exists(path):
os.makedirs(path)
for fl in os.listdir(path):
if fl.endswith('.tox'):
name = fl[:-4]
result.append((path, name))
path = curr_directory()
# check current directory
for fl in os.listdir(path):
if fl.endswith('.tox'):
name = fl[:-4]
result.append((path + '/', name))
return result
@staticmethod
def get_path():
return ProfileHelper.get_instance().get_dir()

View File

@ -1,12 +1,8 @@
import util
import toxencryptsave
class ToxES:
class ToxES(util.Singleton): def __init__(self, toxencryptsave):
self._toxencryptsave = toxencryptsave
def __init__(self):
super().__init__()
self._toxencryptsave = toxencryptsave.ToxEncryptSave()
self._passphrase = None self._passphrase = None
def set_password(self, passphrase): def set_password(self, passphrase):

0
toxygen/util/__init__.py Normal file
View File

View File

@ -5,7 +5,7 @@ import sys
import re import re
program_version = '0.4.1' program_version = '0.5.0'
def cached(func): def cached(func):

View File

View File

@ -1,7 +1,7 @@
from ctypes import * from ctypes import *
from toxcore_enums_and_consts import * from wrapper.toxcore_enums_and_consts import *
from toxav import ToxAV from wrapper.toxav import ToxAV
from libtox import LibToxCore from wrapper.libtox import LibToxCore
class ToxOptions(Structure): class ToxOptions(Structure):
@ -1515,87 +1515,841 @@ class Tox:
raise RuntimeError('The instance was not bound to any port.') raise RuntimeError('The instance was not bound to any port.')
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Group chats # Group chat instance management
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
def del_groupchat(self, groupnumber): def group_new(self, privacy_state, group_name):
result = Tox.libtoxcore.tox_del_groupchat(self._tox_pointer, c_int(groupnumber), None) """
Creates a new group chat.
This function creates a new group chat object and adds it to the chats array.
The client should initiate its peer list with self info after calling this function, as
the peer_join callback will not be triggered.
:param privacy_state: The privacy state of the group. If this is set to TOX_GROUP_PRIVACY_STATE_PUBLIC,
the group will attempt to announce itself to the DHT and anyone with the Chat ID may join.
Otherwise a friend invite will be required to join the group.
:param group_name: The name of the group. The name must be non-NULL.
:return group number on success, UINT32_MAX on failure.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_new(self._tox_pointer, privacy_state, group_name,
len(group_name), byref(error))
return result return result
def group_peername(self, groupnumber, peernumber): def group_join(self, chat_id, password):
buffer = create_string_buffer(TOX_MAX_NAME_LENGTH) """
result = Tox.libtoxcore.tox_group_peername(self._tox_pointer, c_int(groupnumber), c_int(peernumber), Joins a group chat with specified Chat ID.
buffer, None) This function creates a new group chat object, adds it to the chats array, and sends
return str(buffer[:result], 'utf-8') a DHT announcement to find peers in the group associated with chat_id. Once a peer has been
found a join attempt will be initiated.
:param chat_id: The Chat ID of the group you wish to join. This must be TOX_GROUP_CHAT_ID_SIZE bytes.
:param password: The password required to join the group. Set to NULL if no password is required.
:return groupnumber on success, UINT32_MAX on failure.
"""
def invite_friend(self, friendnumber, groupnumber): error = c_int()
result = Tox.libtoxcore.tox_invite_friend(self._tox_pointer, c_int(friendnumber), result = Tox.libtoxcore.tox_group_join(self._tox_pointer, string_to_bin(chat_id),
c_int(groupnumber), None) password,
len(password) if password is not None else 0,
byref(error))
return result return result
def join_groupchat(self, friendnumber, data): def group_reconnect(self, groupnumber):
result = Tox.libtoxcore.tox_join_groupchat(self._tox_pointer, """
c_int(friendnumber), c_char_p(data), c_uint16(len(data)), None) Reconnects to a group.
This function disconnects from all peers in the group, then attempts to reconnect with the group.
The caller's state is not changed (i.e. name, status, role, chat public key etc.)
:param groupnumber: The group number of the group we wish to reconnect to.
:return True on success.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_reconnect(self._tox_pointer, groupnumber, byref(error))
return result return result
def group_message_send(self, groupnumber, message): def group_leave(self, groupnumber, message):
result = Tox.libtoxcore.tox_group_message_send(self._tox_pointer, c_int(groupnumber), c_char_p(message), """
c_uint16(len(message)), None) Leaves a group.
This function sends a parting packet containing a custom (non-obligatory) message to all
peers in a group, and deletes the group from the chat array. All group state information is permanently
lost, including keys and role credentials.
:param groupnumber: The group number of the group we wish to leave.
:param message: The parting message to be sent to all the peers. Set to NULL if we do not wish to
send a parting message.
:return True if the group chat instance was successfully deleted.
"""
error = c_int()
f = Tox.libtoxcore.tox_group_leave
f.restype = c_bool
result = f(self._tox_pointer, groupnumber, message,
len(message) if message is not None else 0, byref(error))
return result return result
def group_action_send(self, groupnumber, action): # -----------------------------------------------------------------------------------------------------------------
result = Tox.libtoxcore.tox_group_action_send(self._tox_pointer, # Group user-visible client information (nickname/status/role/public key)
c_int(groupnumber), c_char_p(action), # -----------------------------------------------------------------------------------------------------------------
c_uint16(len(action)), None)
def group_self_set_name(self, groupnumber, name):
"""
Set the client's nickname for the group instance designated by the given group number.
Nickname length cannot exceed TOX_MAX_NAME_LENGTH. If length is equal to zero or name is a NULL
pointer, the function call will fail.
:param name: A byte array containing the new nickname.
:return True on success.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_self_set_name(self._tox_pointer, groupnumber, name, len(name), byref(error))
return result return result
def group_set_title(self, groupnumber, title): def group_self_get_name_size(self, groupnumber):
result = Tox.libtoxcore.tox_group_set_title(self._tox_pointer, c_int(groupnumber), """
c_char_p(title), c_uint8(len(title)), None) Return the length of the client's current nickname for the group instance designated
by groupnumber as passed to tox_group_self_set_name.
If no nickname was set before calling this function, the name is empty,
and this function returns 0.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_self_get_name_size(self._tox_pointer, groupnumber, byref(error))
return result return result
def group_get_title(self, groupnumber): def group_self_get_name(self, groupnumber):
buffer = create_string_buffer(TOX_MAX_NAME_LENGTH) """
result = Tox.libtoxcore.tox_group_get_title(self._tox_pointer, Write the nickname set by tox_group_self_set_name to a byte array.
c_int(groupnumber), buffer, If no nickname was set before calling this function, the name is empty,
c_uint32(TOX_MAX_NAME_LENGTH), None) and this function has no effect.
return str(buffer[:result], 'utf-8') Call tox_group_self_get_name_size to find out how much memory to allocate for the result.
:return nickname
"""
def group_number_peers(self, groupnumber): error = c_int()
result = Tox.libtoxcore.tox_group_number_peers(self._tox_pointer, c_int(groupnumber), None) size = self.group_self_get_name_size(groupnumber)
name = create_string_buffer(size)
result = Tox.libtoxcore.tox_group_self_get_name(self._tox_pointer, groupnumber, name, byref(error))
return str(name[:size], 'utf-8')
def group_self_set_status(self, groupnumber, status):
"""
Set the client's status for the group instance. Status must be a TOX_USER_STATUS.
:return True on success.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_self_set_status(self._tox_pointer, groupnumber, status, byref(error))
return result return result
def add_av_groupchat(self): def group_self_get_status(self, groupnumber):
result = self.AV.libtoxav.toxav_add_av_groupchat(self._tox_pointer, None, None) """
returns the client's status for the group instance on success.
return value is unspecified on failure.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_self_get_status(self._tox_pointer, groupnumber, byref(error))
return result return result
def join_av_groupchat(self, friendnumber, data): def group_self_get_role(self, groupnumber):
result = self.AV.libtoxav.toxav_join_av_groupchat(self._tox_pointer, c_int32(friendnumber), """
c_char_p(data), c_uint16(len(data)), returns the client's role for the group instance on success.
None, None) return value is unspecified on failure.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_self_get_role(self._tox_pointer, groupnumber, byref(error))
return result return result
def callback_group_invite(self, callback, user_data=None): def group_self_get_peer_id(self, groupnumber):
c_callback = CFUNCTYPE(None, c_void_p, c_int32, c_uint8, POINTER(c_uint8), c_uint16, c_void_p) """
self.group_invite_cb = c_callback(callback) returns the client's peer id for the group instance on success.
Tox.libtoxcore.tox_callback_group_invite(self._tox_pointer, self.group_invite_cb, user_data) return value is unspecified on failure.
"""
def callback_group_message(self, callback, user_data=None): error = c_int()
c_callback = CFUNCTYPE(None, c_void_p, c_int, c_int, c_char_p, c_uint16, c_void_p) result = Tox.libtoxcore.tox_group_self_get_peer_id(self._tox_pointer, groupnumber, byref(error))
return result
def group_self_get_public_key(self, groupnumber):
"""
Write the client's group public key designated by the given group number to a byte array.
This key will be permanently tied to the client's identity for this particular group until
the client explicitly leaves the group or gets kicked/banned. This key is the only way for
other peers to reliably identify the client across client restarts.
`public_key` should have room for at least TOX_GROUP_PEER_PUBLIC_KEY_SIZE bytes.
:return public key
"""
error = c_int()
key = create_string_buffer(TOX_GROUP_PEER_PUBLIC_KEY_SIZE)
result = Tox.libtoxcore.tox_group_self_get_public_key(self._tox_pointer, groupnumber,
key, byref(error))
return bin_to_string(key, TOX_GROUP_PEER_PUBLIC_KEY_SIZE)
# -----------------------------------------------------------------------------------------------------------------
# Peer-specific group state queries.
# -----------------------------------------------------------------------------------------------------------------
def group_peer_get_name_size(self, groupnumber, peer_id):
"""
Return the length of the peer's name. If the group number or ID is invalid, the
return value is unspecified.
The return value is equal to the `length` argument received by the last
`group_peer_name` callback.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_peer_get_name_size(self._tox_pointer, groupnumber, peer_id, byref(error))
return result
def group_peer_get_name(self, groupnumber, peer_id):
"""
Write the name of the peer designated by the given ID to a byte
array.
Call tox_group_peer_get_name_size to determine the allocation size for the `name` parameter.
The data written to `name` is equal to the data received by the last
`group_peer_name` callback.
:param groupnumber: The group number of the group we wish to query.
:param peer_id: The ID of the peer whose name we want to retrieve.
:return name.
"""
error = c_int()
size = self.group_peer_get_name_size(groupnumber, peer_id)
name = create_string_buffer(size)
result = Tox.libtoxcore.tox_group_peer_get_name(self._tox_pointer, groupnumber, peer_id, name, byref(error))
return str(name[:], 'utf-8')
def group_peer_get_status(self, groupnumber, peer_id):
"""
Return the peer's user status (away/busy/...). If the ID or group number is
invalid, the return value is unspecified.
The status returned is equal to the last status received through the
`group_peer_status` callback.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_peer_get_status(self._tox_pointer, groupnumber, peer_id, byref(error))
return result
def group_peer_get_role(self, groupnumber, peer_id):
"""
Return the peer's role (user/moderator/founder...). If the ID or group number is
invalid, the return value is unspecified.
The role returned is equal to the last role received through the
`group_moderation` callback.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_peer_get_role(self._tox_pointer, groupnumber, peer_id, byref(error))
return result
def group_peer_get_public_key(self, groupnumber, peer_id):
"""
Write the group public key with the designated peer_id for the designated group number to public_key.
This key will be parmanently tied to a particular peer until they explicitly leave the group or
get kicked/banned, and is the only way to reliably identify the same peer across client restarts.
`public_key` should have room for at least TOX_GROUP_PEER_PUBLIC_KEY_SIZE bytes.
:return public key
"""
error = c_int()
key = create_string_buffer(TOX_GROUP_PEER_PUBLIC_KEY_SIZE)
result = Tox.libtoxcore.tox_group_peer_get_public_key(self._tox_pointer, groupnumber, peer_id,
key, byref(error))
return bin_to_string(key, TOX_GROUP_PEER_PUBLIC_KEY_SIZE)
def callback_group_peer_name(self, callback, user_data):
"""
Set the callback for the `group_peer_name` event. Pass NULL to unset.
This event is triggered when a peer changes their nickname.
"""
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_char_p, c_size_t, c_void_p)
self.group_peer_name_cb = c_callback(callback)
Tox.libtoxcore.tox_callback_group_peer_name(self._tox_pointer, self.group_peer_name_cb, user_data)
def callback_group_peer_status(self, callback, user_data):
"""
Set the callback for the `group_peer_status` event. Pass NULL to unset.
This event is triggered when a peer changes their status.
"""
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_int, c_void_p)
self.group_peer_status_cb = c_callback(callback)
Tox.libtoxcore.tox_callback_group_peer_status(self._tox_pointer, self.group_peer_status_cb, user_data)
# -----------------------------------------------------------------------------------------------------------------
# Group chat state queries and events.
# -----------------------------------------------------------------------------------------------------------------
def group_set_topic(self, groupnumber, topic):
"""
Set the group topic and broadcast it to the rest of the group.
topic length cannot be longer than TOX_GROUP_MAX_TOPIC_LENGTH. If length is equal to zero or
topic is set to NULL, the topic will be unset.
:return True on success.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_set_topic(self._tox_pointer, groupnumber, topic, len(topic), byref(error))
return result
def group_get_topic_size(self, groupnumber):
"""
Return the length of the group topic. If the group number is invalid, the
return value is unspecified.
The return value is equal to the `length` argument received by the last
`group_topic` callback.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_get_topic_size(self._tox_pointer, groupnumber, byref(error))
return result
def group_get_topic(self, groupnumber):
"""
Write the topic designated by the given group number to a byte array.
Call tox_group_get_topic_size to determine the allocation size for the `topic` parameter.
The data written to `topic` is equal to the data received by the last
`group_topic` callback.
:return topic
"""
error = c_int()
size = self.group_get_topic_size(groupnumber)
topic = create_string_buffer(size)
result = Tox.libtoxcore.tox_group_get_topic(self._tox_pointer, groupnumber, topic, byref(error))
return str(topic[:size], 'utf-8')
def group_get_name_size(self, groupnumber):
"""
Return the length of the group name. If the group number is invalid, the
return value is unspecified.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_get_name_size(self._tox_pointer, groupnumber, byref(error))
return result
def group_get_name(self, groupnumber):
"""
Write the name of the group designated by the given group number to a byte array.
Call tox_group_get_name_size to determine the allocation size for the `name` parameter.
:return true on success.
"""
error = c_int()
size = self.group_get_name_size(groupnumber)
name = create_string_buffer(size)
result = Tox.libtoxcore.tox_group_get_name(self._tox_pointer, groupnumber,
name, byref(error))
return str(name[:size], 'utf-8')
def group_get_chat_id(self, groupnumber):
"""
Write the Chat ID designated by the given group number to a byte array.
`chat_id` should have room for at least TOX_GROUP_CHAT_ID_SIZE bytes.
:return chat id.
"""
error = c_int()
buff = create_string_buffer(TOX_GROUP_CHAT_ID_SIZE)
result = Tox.libtoxcore.tox_group_get_chat_id(self._tox_pointer, groupnumber,
buff, byref(error))
return bin_to_string(buff, TOX_GROUP_CHAT_ID_SIZE)
def group_get_number_groups(self):
"""
Return the number of groups in the Tox chats array.
"""
result = Tox.libtoxcore.tox_group_get_number_groups(self._tox_pointer)
return result
def group_get_privacy_state(self, groupnumber):
"""
Return the privacy state of the group designated by the given group number. If group number
is invalid, the return value is unspecified.
The value returned is equal to the data received by the last
`group_privacy_state` callback.
see the `Group chat founder controls` section for the respective set function.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_get_privacy_state(self._tox_pointer, groupnumber, byref(error))
return result
def group_get_peer_limit(self, groupnumber):
"""
Return the maximum number of peers allowed for the group designated by the given group number.
If the group number is invalid, the return value is unspecified.
The value returned is equal to the data received by the last
`group_peer_limit` callback.
see the `Group chat founder controls` section for the respective set function.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_get_peer_limit(self._tox_pointer, groupnumber, byref(error))
return result
def group_get_password_size(self, groupnumber):
"""
Return the length of the group password. If the group number is invalid, the
return value is unspecified.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_get_password_size(self._tox_pointer, groupnumber, byref(error))
return result
def group_get_password(self, groupnumber):
"""
Write the password for the group designated by the given group number to a byte array.
Call tox_group_get_password_size to determine the allocation size for the `password` parameter.
The data received is equal to the data received by the last
`group_password` callback.
see the `Group chat founder controls` section for the respective set function.
:return password
"""
error = c_int()
size = self.group_get_password_size(groupnumber)
password = create_string_buffer(size)
result = Tox.libtoxcore.tox_group_get_password(self._tox_pointer, groupnumber,
password, byref(error))
return str(password[:size], 'utf-8')
def callback_group_topic(self, callback, user_data):
"""
Set the callback for the `group_topic` event. Pass NULL to unset.
This event is triggered when a peer changes the group topic.
"""
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_char_p, c_size_t, c_void_p)
self.group_topic_cb = c_callback(callback)
Tox.libtoxcore.tox_callback_group_topic(self._tox_pointer, self.group_topic_cb, user_data)
def callback_group_privacy_state(self, callback, user_data):
"""
Set the callback for the `group_privacy_state` event. Pass NULL to unset.
This event is triggered when the group founder changes the privacy state.
"""
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_int, c_void_p)
self.group_privacy_state_cb = c_callback(callback)
Tox.libtoxcore.tox_callback_group_privacy_state(self._tox_pointer, self.group_privacy_state_cb, user_data)
def callback_group_peer_limit(self, callback, user_data):
"""
Set the callback for the `group_peer_limit` event. Pass NULL to unset.
This event is triggered when the group founder changes the maximum peer limit.
"""
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_void_p)
self.group_peer_limit_cb = c_callback(callback)
Tox.libtoxcore.tox_callback_group_peer_limit(self._tox_pointer, self.group_peer_limit_cb, user_data)
def callback_group_password(self, callback, user_data):
"""
Set the callback for the `group_password` event. Pass NULL to unset.
This event is triggered when the group founder changes the group password.
"""
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_char_p, c_size_t, c_void_p)
self.group_password_cb = c_callback(callback)
Tox.libtoxcore.tox_callback_group_password(self._tox_pointer, self.group_password_cb, user_data)
# -----------------------------------------------------------------------------------------------------------------
# Group message sending
# -----------------------------------------------------------------------------------------------------------------
def group_send_custom_packet(self, groupnumber, lossless, data):
"""
Send a custom packet to the group.
If lossless is true the packet will be lossless. Lossless packet behaviour is comparable
to TCP (reliability, arrive in order) but with packets instead of a stream.
If lossless is false, the packet will be lossy. Lossy packets behave like UDP packets,
meaning they might never reach the other side or might arrive more than once (if someone
is messing with the connection) or might arrive in the wrong order.
Unless latency is an issue or message reliability is not important, it is recommended that you use
lossless custom packets.
:param groupnumber: The group number of the group the message is intended for.
:param lossless: True if the packet should be lossless.
:param data A byte array containing the packet data.
:return True on success.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_send_custom_packet(self._tox_pointer, groupnumber, lossless, data,
len(data), byref(error))
return result
def group_send_private_message(self, groupnumber, peer_id, message):
"""
Send a text chat message to the specified peer in the specified group.
This function creates a group private 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.
:param groupnumber: The group number of the group the message is intended for.
:param peer_id: The ID of the peer the message is intended for.
:param message: A non-NULL pointer to the first element of a byte array containing the message text.
:return True on success.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_send_private_message(self._tox_pointer, groupnumber, peer_id, message,
len(message), byref(error))
return result
def group_send_message(self, groupnumber, type, message):
"""
Send a text chat message to the group.
This function creates a group 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.
:param groupnumber: The group number of the group the message is intended for.
: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.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_send_message(self._tox_pointer, groupnumber, type, message, len(message),
byref(error))
return result
# -----------------------------------------------------------------------------------------------------------------
# Group message receiving
# -----------------------------------------------------------------------------------------------------------------
def callback_group_message(self, callback, user_data):
"""
Set the callback for the `group_message` event. Pass NULL to unset.
This event is triggered when the client receives a group message.
Callback: python function with params:
tox Tox* instance
groupnumber The group number of the group the message is intended for.
peer_id The ID of the peer who sent the message.
type The type of message (normal, action, ...).
message The message data.
length The length of the message.
user_data - user data
"""
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_int, c_char_p, c_size_t, c_void_p)
self.group_message_cb = c_callback(callback) self.group_message_cb = c_callback(callback)
Tox.libtoxcore.tox_callback_group_message(self._tox_pointer, self.group_message_cb, user_data) Tox.libtoxcore.tox_callback_group_message(self._tox_pointer, self.group_message_cb, user_data)
def callback_group_action(self, callback, user_data=None): def callback_group_private_message(self, callback, user_data):
c_callback = CFUNCTYPE(None, c_void_p, c_int, c_int, c_char_p, c_uint16, c_void_p) """
self.group_action_cb = c_callback(callback) Set the callback for the `group_private_message` event. Pass NULL to unset.
Tox.libtoxcore.tox_callback_group_action(self._tox_pointer, self.group_action_cb, user_data) This event is triggered when the client receives a private message.
"""
def callback_group_title(self, callback, user_data=None): c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_char_p, c_size_t, c_void_p)
c_callback = CFUNCTYPE(None, c_void_p, c_int, c_int, c_char_p, c_uint8, c_void_p) self.group_private_message_cb = c_callback(callback)
self.group_title_cb = c_callback(callback) Tox.libtoxcore.tox_callback_group_private_message(self._tox_pointer, self.group_private_message_cb, user_data)
Tox.libtoxcore.tox_callback_group_title(self._tox_pointer, self.group_title_cb, user_data)
def callback_group_namelist_change(self, callback, user_data=None): def callback_group_custom_packet(self, callback, user_data):
c_callback = CFUNCTYPE(None, c_void_p, c_int, c_int, c_uint8, c_void_p) """
self.group_namelist_change_cb = c_callback(callback) Set the callback for the `group_custom_packet` event. Pass NULL to unset.
Tox.libtoxcore.tox_callback_group_namelist_change(self._tox_pointer, self.group_namelist_change_cb, user_data) This event is triggered when the client receives a custom packet.
"""
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, POINTER(c_uint8), c_void_p)
self.group_custom_packet_cb = c_callback(callback)
Tox.libtoxcore.tox_callback_group_custom_packet(self._tox_pointer, self.group_custom_packet_cb, user_data)
# -----------------------------------------------------------------------------------------------------------------
# Group chat inviting and join/part events
# -----------------------------------------------------------------------------------------------------------------
def group_invite_friend(self, groupnumber, friend_number):
"""
Invite a friend to a group.
This function creates an invite request packet and pushes it to the send queue.
:param groupnumber: The group number of the group the message is intended for.
:param friend_number: The friend number of the friend the invite is intended for.
:return True on success.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_invite_friend(self._tox_pointer, groupnumber, friend_number, byref(error))
return result
def group_invite_accept(self, invite_data, friend_number, 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.
:param invite_data: The invite data received from the `group_invite` event.
:param password: The password required to join the group. Set to NULL if no password is required.
:return the groupnumber on success, UINT32_MAX on failure.
"""
error = c_int()
f = Tox.libtoxcore.tox_group_invite_accept
f.restype = c_uint32
result = f(self._tox_pointer, friend_number, invite_data, len(invite_data), password,
len(password) if password is not None else 0, byref(error))
print('Invite accept. Result:', result, 'Error:', error.value)
return result
def callback_group_invite(self, callback, user_data):
"""
Set the callback for the `group_invite` event. Pass NULL to unset.
This event is triggered when the client receives a group invite from a friend. The client must store
invite_data which is used to join the group via tox_group_invite_accept.
Callback: python function with params:
tox - Tox*
friend_number The friend number of the contact who sent the invite.
invite_data The invite data.
length The length of invite_data.
user_data - user data
"""
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, POINTER(c_uint8), c_size_t, c_void_p)
self.group_invite_cb = c_callback(callback)
Tox.libtoxcore.tox_callback_group_invite(self._tox_pointer, self.group_invite_cb, user_data)
def callback_group_peer_join(self, callback, user_data):
"""
Set the callback for the `group_peer_join` event. Pass NULL to unset.
This event is triggered when a peer other than self joins the group.
Callback: python function with params:
tox - Tox*
group_number - group number
peer_id - peer id
user_data - user data
"""
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_void_p)
self.group_peer_join_cb = c_callback(callback)
Tox.libtoxcore.tox_callback_group_peer_join(self._tox_pointer, self.group_peer_join_cb, user_data)
def callback_group_peer_exit(self, callback, user_data):
"""
Set the callback for the `group_peer_exit` event. Pass NULL to unset.
This event is triggered when a peer other than self exits the group.
"""
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_char_p, c_size_t, c_void_p)
self.group_peer_exit_cb = c_callback(callback)
Tox.libtoxcore.tox_callback_group_peer_exit(self._tox_pointer, self.group_peer_exit_cb, user_data)
def callback_group_self_join(self, callback, user_data):
"""
Set the callback for the `group_self_join` event. Pass NULL to unset.
This event is triggered when the client has successfully joined a group. Use this to initialize
any group information the client may need.
Callback: python fucntion with params:
tox - *Tox
group_number - group number
user_data - user data
"""
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_void_p)
self.group_self_join_cb = c_callback(callback)
Tox.libtoxcore.tox_callback_group_self_join(self._tox_pointer, self.group_self_join_cb, user_data)
def callback_group_join_fail(self, callback, user_data):
"""
Set the callback for the `group_join_fail` event. Pass NULL to unset.
This event is triggered when the client fails to join a group.
"""
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_int, c_void_p)
self.group_join_fail_cb = c_callback(callback)
Tox.libtoxcore.tox_callback_group_join_fail(self._tox_pointer, self.group_join_fail_cb, user_data)
# -----------------------------------------------------------------------------------------------------------------
# Group chat founder controls (these only work for the group founder)
# -----------------------------------------------------------------------------------------------------------------
def group_founder_set_password(self, groupnumber, password):
"""
Set or unset the group password.
This function sets the groups password, creates a new group shared state including the change,
and distributes it to the rest of the group.
:param groupnumber: The group number of the group for which we wish to set the password.
:param password: The password we want to set. Set password to NULL to unset the password.
:return True on success.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_founder_set_password(self._tox_pointer, groupnumber, password,
len(password), byref(error))
return result
def group_founder_set_privacy_state(self, groupnumber, privacy_state):
"""
Set the group privacy state.
This function sets the group's privacy state, creates a new group shared state
including the change, and distributes it to the rest of the group.
If an attempt is made to set the privacy state to the same state that the group is already
in, the function call will be successful and no action will be taken.
:param groupnumber: The group number of the group for which we wish to change the privacy state.
:param privacy_state: The privacy state we wish to set the group to.
:return true on success.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_founder_set_privacy_state(self._tox_pointer, groupnumber, privacy_state,
byref(error))
return result
def group_founder_set_peer_limit(self, groupnumber, max_peers):
"""
Set the group peer limit.
This function sets a limit for the number of peers who may be in the group, creates a new
group shared state including the change, and distributes it to the rest of the group.
:param groupnumber: The group number of the group for which we wish to set the peer limit.
:param max_peers: The maximum number of peers to allow in the group.
:return True on success.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_founder_set_peer_limit(self._tox_pointer, groupnumber,
max_peers, byref(error))
return result
# -----------------------------------------------------------------------------------------------------------------
# Group chat moderation
# -----------------------------------------------------------------------------------------------------------------
def group_toggle_ignore(self, groupnumber, peer_id, ignore):
"""
Ignore or unignore a peer.
:param groupnumber: The group number of the group the in which you wish to ignore a peer.
:param peer_id: The ID of the peer who shall be ignored or unignored.
:param ignore: True to ignore the peer, false to unignore the peer.
:return True on success.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_toggle_ignore(self._tox_pointer, groupnumber, peer_id, ignore, byref(error))
return result
def group_mod_set_role(self, groupnumber, peer_id, role):
"""
Set a peer's role.
This function will first remove the peer's previous role and then assign them a new role.
It will also send a packet to the rest of the group, requesting that they perform
the role reassignment. Note: peers cannot be set to the founder role.
:param groupnumber: The group number of the group the in which you wish set the peer's role.
:param peer_id: The ID of the peer whose role you wish to set.
:param role: The role you wish to set the peer to.
:return True on success.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_mod_set_role(self._tox_pointer, groupnumber, peer_id, role, byref(error))
return result
def group_mod_remove_peer(self, groupnumber, peer_id, set_ban):
"""
Kick/ban a peer.
This function will remove a peer from the caller's peer list and optionally add their IP address
to the ban list. It will also send a packet to all group members requesting them
to do the same.
:param groupnumber: The group number of the group the ban is intended for.
:param peer_id: The ID of the peer who will be kicked and/or added to the ban list.
:param set_ban: Set to true if a ban shall be set on the peer's IP address.
:return True on success.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_mod_remove_peer(self._tox_pointer, groupnumber, peer_id,
set_ban, byref(error))
return result
def group_mod_remove_ban(self, groupnumber, ban_id):
"""
Removes a ban.
This function removes a ban entry from the ban list, and sends a packet to the rest of
the group requesting that they do the same.
:param groupnumber: The group number of the group in which the ban is to be removed.
:param ban_id: The ID of the ban entry that shall be removed.
:return True on success
"""
error = c_int()
result = Tox.libtoxcore.tox_group_mod_remove_ban(self._tox_pointer, groupnumber, ban_id, byref(error))
return result
def callback_group_moderation(self, callback, user_data):
"""
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.
"""
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_uint32, c_int, c_void_p)
self.group_moderation_cb = c_callback(callback)
Tox.libtoxcore.tox_callback_group_moderation(self._tox_pointer, self.group_moderation_cb, user_data)
# -----------------------------------------------------------------------------------------------------------------
# Group chat ban list queries
# -----------------------------------------------------------------------------------------------------------------
def group_ban_get_list_size(self, groupnumber):
"""
Return the number of entries in the ban list for the group designated by
the given group number. If the group number is invalid, the return value is unspecified.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_ban_get_list_size(self._tox_pointer, groupnumber, byref(error))
return result
def group_ban_get_list(self, groupnumber):
"""
Copy a list of valid ban list ID's into an array.
Call tox_group_ban_get_list_size to determine the number of elements to allocate.
return true on success.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_ban_get_list(self._tox_pointer, groupnumber, POINTER(c_uint32)(
create_string_buffer(sizeof(c_uint32) * self.group_ban_get_list_size(groupnumber)), byref(error)))
return result
def group_ban_get_name_size(self, groupnumber, ban_id):
"""
Return the length of the name for the ban list entry designated by ban_id, in the
group designated by the given group number. If either groupnumber or ban_id is invalid,
the return value is unspecified.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_ban_get_name_size(self._tox_pointer, groupnumber, ban_id, byref(error))
return result
def group_ban_get_name(self, groupnumber, ban_id):
"""
Write the name of the ban entry designated by ban_id in the group designated by the
given group number to a byte array.
Call tox_group_ban_get_name_size to find out how much memory to allocate for the result.
:return name
"""
error = c_int()
size = self.group_ban_get_name_size(groupnumber, ban_id)
name = create_string_buffer()
result = Tox.libtoxcore.tox_group_ban_get_name(self._tox_pointer, groupnumber, ban_id,
name, byref(error))
return str(name[:size], 'utf-8')
def group_ban_get_time_set(self, groupnumber, ban_id):
"""
Return a time stamp indicating the time the ban was set, for the ban list entry
designated by ban_id, in the group designated by the given group number.
If either groupnumber or ban_id is invalid, the return value is unspecified.
"""
error = c_int()
result = Tox.libtoxcore.tox_group_ban_get_time_set(self._tox_pointer, groupnumber, ban_id, byref(error))
return result

View File

@ -1,7 +1,7 @@
from ctypes import c_int, POINTER, c_void_p, byref, ArgumentError, c_uint32, CFUNCTYPE, c_size_t, c_uint8, c_uint16 from ctypes import c_int, POINTER, c_void_p, byref, ArgumentError, c_uint32, CFUNCTYPE, c_size_t, c_uint8, c_uint16
from ctypes import c_char_p, c_int32, c_bool, cast from ctypes import c_char_p, c_int32, c_bool, cast
from libtox import LibToxAV from wrapper.libtox import LibToxAV
from toxav_enums import * from wrapper.toxav_enums import *
class ToxAV: class ToxAV:

View File

@ -0,0 +1,944 @@
TOX_USER_STATUS = {
'NONE': 0,
'AWAY': 1,
'BUSY': 2,
}
TOX_MESSAGE_TYPE = {
'NORMAL': 0,
'ACTION': 1,
}
TOX_PROXY_TYPE = {
'NONE': 0,
'HTTP': 1,
'SOCKS5': 2,
}
TOX_SAVEDATA_TYPE = {
'NONE': 0,
'TOX_SAVE': 1,
'SECRET_KEY': 2,
}
TOX_ERR_OPTIONS_NEW = {
'OK': 0,
'MALLOC': 1,
}
TOX_ERR_NEW = {
'OK': 0,
'NULL': 1,
'MALLOC': 2,
'PORT_ALLOC': 3,
'PROXY_BAD_TYPE': 4,
'PROXY_BAD_HOST': 5,
'PROXY_BAD_PORT': 6,
'PROXY_NOT_FOUND': 7,
'LOAD_ENCRYPTED': 8,
'LOAD_BAD_FORMAT': 9,
}
TOX_ERR_BOOTSTRAP = {
'OK': 0,
'NULL': 1,
'BAD_HOST': 2,
'BAD_PORT': 3,
}
TOX_CONNECTION = {
'NONE': 0,
'TCP': 1,
'UDP': 2,
}
TOX_ERR_SET_INFO = {
'OK': 0,
'NULL': 1,
'TOO_LONG': 2,
}
TOX_ERR_FRIEND_ADD = {
'OK': 0,
'NULL': 1,
'TOO_LONG': 2,
'NO_MESSAGE': 3,
'OWN_KEY': 4,
'ALREADY_SENT': 5,
'BAD_CHECKSUM': 6,
'SET_NEW_NOSPAM': 7,
'MALLOC': 8,
}
TOX_ERR_FRIEND_DELETE = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
}
TOX_ERR_FRIEND_BY_PUBLIC_KEY = {
'OK': 0,
'NULL': 1,
'NOT_FOUND': 2,
}
TOX_ERR_FRIEND_GET_PUBLIC_KEY = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
}
TOX_ERR_FRIEND_GET_LAST_ONLINE = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
}
TOX_ERR_FRIEND_QUERY = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
}
TOX_ERR_SET_TYPING = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
}
TOX_ERR_FRIEND_SEND_MESSAGE = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
'FRIEND_NOT_CONNECTED': 3,
'SENDQ': 4,
'TOO_LONG': 5,
'EMPTY': 6,
}
TOX_FILE_KIND = {
'DATA': 0,
'AVATAR': 1,
}
TOX_FILE_CONTROL = {
'RESUME': 0,
'PAUSE': 1,
'CANCEL': 2,
}
TOX_ERR_FILE_CONTROL = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
'FRIEND_NOT_CONNECTED': 2,
'NOT_FOUND': 3,
'NOT_PAUSED': 4,
'DENIED': 5,
'ALREADY_PAUSED': 6,
'SENDQ': 7,
}
TOX_ERR_FILE_SEEK = {
'OK': 0,
'FRIEND_NOT_FOUND': 1,
'FRIEND_NOT_CONNECTED': 2,
'NOT_FOUND': 3,
'DENIED': 4,
'INVALID_POSITION': 5,
'SENDQ': 6,
}
TOX_ERR_FILE_GET = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
'NOT_FOUND': 3,
}
TOX_ERR_FILE_SEND = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
'FRIEND_NOT_CONNECTED': 3,
'NAME_TOO_LONG': 4,
'TOO_MANY': 5,
}
TOX_ERR_FILE_SEND_CHUNK = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
'FRIEND_NOT_CONNECTED': 3,
'NOT_FOUND': 4,
'NOT_TRANSFERRING': 5,
'INVALID_LENGTH': 6,
'SENDQ': 7,
'WRONG_POSITION': 8,
}
TOX_ERR_FRIEND_CUSTOM_PACKET = {
'OK': 0,
'NULL': 1,
'FRIEND_NOT_FOUND': 2,
'FRIEND_NOT_CONNECTED': 3,
'INVALID': 4,
'EMPTY': 5,
'TOO_LONG': 6,
'SENDQ': 7,
}
TOX_ERR_GET_PORT = {
'OK': 0,
'NOT_BOUND': 1,
}
TOX_GROUP_PRIVACY_STATE = {
#
# The group is considered to be public. Anyone may join the group using the Chat ID.
#
# If the group is in this state, even if the Chat ID is never explicitly shared
# with someone outside of the group, information including the Chat ID, IP addresses,
# and peer ID's (but not Tox ID's) is visible to anyone with access to a node
# storing a DHT entry for the given group.
#
'TOX_GROUP_PRIVACY_STATE_PUBLIC': 0,
#
# The group is considered to be private. The only way to join the group is by having
# someone in your contact list send you an invite.
#
# If the group is in this state, no group information (mentioned above) is present in the DHT;
# the DHT is not used for any purpose at all. If a public group is set to private,
# all DHT information related to the group will expire shortly.
#
'TOX_GROUP_PRIVACY_STATE_PRIVATE': 1
}
TOX_GROUP_ROLE = {
#
# May kick and ban all other peers as well as set their role to anything (except founder).
# Founders may also set the group password, toggle the privacy state, and set the peer limit.
#
'TOX_GROUP_ROLE_FOUNDER': 0,
#
# May kick, ban and set the user and observer roles for peers below this role.
# May also set the group topic.
#
'TOX_GROUP_ROLE_MODERATOR': 1,
#
# May communicate with other peers normally.
#
'TOX_GROUP_ROLE_USER': 2,
#
# May observe the group and ignore peers; may not communicate with other peers or with the group.
#
'TOX_GROUP_ROLE_OBSERVER': 3
}
TOX_ERR_GROUP_NEW = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_NEW_OK': 0,
#
# The group name exceeded TOX_GROUP_MAX_GROUP_NAME_LENGTH.
#
'TOX_ERR_GROUP_NEW_TOO_LONG': 1,
#
# group_name is NULL or length is zero.
#
'TOX_ERR_GROUP_NEW_EMPTY': 2,
#
# TOX_GROUP_PRIVACY_STATE is an invalid type.
#
'TOX_ERR_GROUP_NEW_PRIVACY': 3,
#
# The group instance failed to initialize.
#
'TOX_ERR_GROUP_NEW_INIT': 4,
#
# The group state failed to initialize. This usually indicates that something went wrong
# related to cryptographic signing.
#
'TOX_ERR_GROUP_NEW_STATE': 5,
#
# The group failed to announce to the DHT. This indicates a network related error.
#
'TOX_ERR_GROUP_NEW_ANNOUNCE': 6,
}
TOX_ERR_GROUP_JOIN = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_JOIN_OK': 0,
#
# The group instance failed to initialize.
#
'TOX_ERR_GROUP_JOIN_INIT': 1,
#
# The chat_id pointer is set to NULL or a group with chat_id already exists. This usually
# happens if the client attempts to create multiple sessions for the same group.
#
'TOX_ERR_GROUP_JOIN_BAD_CHAT_ID': 2,
#
# Password length exceeded TOX_GROUP_MAX_PASSWORD_SIZE.
#
'TOX_ERR_GROUP_JOIN_TOO_LONG': 3,
}
TOX_ERR_GROUP_RECONNECT = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_RECONNECT_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_RECONNECT_GROUP_NOT_FOUND': 1,
}
TOX_ERR_GROUP_LEAVE = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_LEAVE_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_LEAVE_GROUP_NOT_FOUND': 1,
#
# Message length exceeded 'TOX_GROUP_MAX_PART_LENGTH.
#
'TOX_ERR_GROUP_LEAVE_TOO_LONG': 2,
#
# The parting packet failed to send.
#
'TOX_ERR_GROUP_LEAVE_FAIL_SEND': 3,
#
# The group chat instance failed to be deleted. This may occur due to memory related errors.
#
'TOX_ERR_GROUP_LEAVE_DELETE_FAIL': 4,
}
TOX_ERR_GROUP_SELF_QUERY = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_SELF_QUERY_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_SELF_QUERY_GROUP_NOT_FOUND': 1,
}
TOX_ERR_GROUP_SELF_NAME_SET = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_SELF_NAME_SET_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_SELF_NAME_SET_GROUP_NOT_FOUND': 1,
#
# Name length exceeded 'TOX_MAX_NAME_LENGTH.
#
'TOX_ERR_GROUP_SELF_NAME_SET_TOO_LONG': 2,
#
# The length given to the set function is zero or name is a NULL pointer.
#
'TOX_ERR_GROUP_SELF_NAME_SET_INVALID': 3,
#
# The name is already taken by another peer in the group.
#
'TOX_ERR_GROUP_SELF_NAME_SET_TAKEN': 4,
#
# The packet failed to send.
#
'TOX_ERR_GROUP_SELF_NAME_SET_FAIL_SEND': 5
}
TOX_ERR_GROUP_SELF_STATUS_SET = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_SELF_STATUS_SET_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_SELF_STATUS_SET_GROUP_NOT_FOUND': 1,
#
# An invalid type was passed to the set function.
#
'TOX_ERR_GROUP_SELF_STATUS_SET_INVALID': 2,
#
# The packet failed to send.
#
'TOX_ERR_GROUP_SELF_STATUS_SET_FAIL_SEND': 3
}
TOX_ERR_GROUP_PEER_QUERY = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_PEER_QUERY_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_PEER_QUERY_GROUP_NOT_FOUND': 1,
#
# The ID passed did not designate a valid peer.
#
'TOX_ERR_GROUP_PEER_QUERY_PEER_NOT_FOUND': 2
}
TOX_ERR_GROUP_STATE_QUERIES = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_STATE_QUERIES_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_STATE_QUERIES_GROUP_NOT_FOUND': 1
}
TOX_ERR_GROUP_TOPIC_SET = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_TOPIC_SET_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_TOPIC_SET_GROUP_NOT_FOUND': 1,
#
# Topic length exceeded 'TOX_GROUP_MAX_TOPIC_LENGTH.
#
'TOX_ERR_GROUP_TOPIC_SET_TOO_LONG': 2,
#
# The caller does not have the required permissions to set the topic.
#
'TOX_ERR_GROUP_TOPIC_SET_PERMISSIONS': 3,
#
# The packet could not be created. This error is usually related to cryptographic signing.
#
'TOX_ERR_GROUP_TOPIC_SET_FAIL_CREATE': 4,
#
# The packet failed to send.
#
'TOX_ERR_GROUP_TOPIC_SET_FAIL_SEND': 5
}
TOX_ERR_GROUP_SEND_MESSAGE = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_SEND_MESSAGE_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_SEND_MESSAGE_GROUP_NOT_FOUND': 1,
#
# Message length exceeded 'TOX_MAX_MESSAGE_LENGTH.
#
'TOX_ERR_GROUP_SEND_MESSAGE_TOO_LONG': 2,
#
# The message pointer is null or length is zero.
#
'TOX_ERR_GROUP_SEND_MESSAGE_EMPTY': 3,
#
# The message type is invalid.
#
'TOX_ERR_GROUP_SEND_MESSAGE_BAD_TYPE': 4,
#
# The caller does not have the required permissions to send group messages.
#
'TOX_ERR_GROUP_SEND_MESSAGE_PERMISSIONS': 5,
#
# Packet failed to send.
#
'TOX_ERR_GROUP_SEND_MESSAGE_FAIL_SEND': 6
}
TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_GROUP_NOT_FOUND': 1,
#
# The ID passed did not designate a valid peer.
#
'TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_PEER_NOT_FOUND': 2,
#
# Message length exceeded 'TOX_MAX_MESSAGE_LENGTH.
#
'TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_TOO_LONG': 3,
#
# The message pointer is null or length is zero.
#
'TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_EMPTY': 4,
#
# The caller does not have the required permissions to send group messages.
#
'TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_PERMISSIONS': 5,
#
# Packet failed to send.
#
'TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_FAIL_SEND': 6
}
TOX_ERR_GROUP_SEND_CUSTOM_PACKET = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_SEND_CUSTOM_PACKET_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_SEND_CUSTOM_PACKET_GROUP_NOT_FOUND': 1,
#
# Message length exceeded 'TOX_MAX_MESSAGE_LENGTH.
#
'TOX_ERR_GROUP_SEND_CUSTOM_PACKET_TOO_LONG': 2,
#
# The message pointer is null or length is zero.
#
'TOX_ERR_GROUP_SEND_CUSTOM_PACKET_EMPTY': 3,
#
# The caller does not have the required permissions to send group messages.
#
'TOX_ERR_GROUP_SEND_CUSTOM_PACKET_PERMISSIONS': 4
}
TOX_ERR_GROUP_INVITE_FRIEND = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_INVITE_FRIEND_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_INVITE_FRIEND_GROUP_NOT_FOUND': 1,
#
# The friend number passed did not designate a valid friend.
#
'TOX_ERR_GROUP_INVITE_FRIEND_FRIEND_NOT_FOUND': 2,
#
# Creation of the invite packet failed. This indicates a network related error.
#
'TOX_ERR_GROUP_INVITE_FRIEND_INVITE_FAIL': 3,
#
# Packet failed to send.
#
'TOX_ERR_GROUP_INVITE_FRIEND_FAIL_SEND': 4
}
TOX_ERR_GROUP_INVITE_ACCEPT = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_INVITE_ACCEPT_OK': 0,
#
# The invite data is not in the expected format.
#
'TOX_ERR_GROUP_INVITE_ACCEPT_BAD_INVITE': 1,
#
# The group instance failed to initialize.
#
'TOX_ERR_GROUP_INVITE_ACCEPT_INIT_FAILED': 2,
#
# Password length exceeded 'TOX_GROUP_MAX_PASSWORD_SIZE.
#
'TOX_ERR_GROUP_INVITE_ACCEPT_TOO_LONG': 3
}
TOX_GROUP_JOIN_FAIL = {
#
# You are using the same nickname as someone who is already in the group.
#
'TOX_GROUP_JOIN_FAIL_NAME_TAKEN': 0,
#
# The group peer limit has been reached.
#
'TOX_GROUP_JOIN_FAIL_PEER_LIMIT': 1,
#
# You have supplied an invalid password.
#
'TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD': 2,
#
# The join attempt failed due to an unspecified error. This often occurs when the group is
# not found in the DHT.
#
'TOX_GROUP_JOIN_FAIL_UNKNOWN': 3
}
TOX_ERR_GROUP_FOUNDER_SET_PASSWORD = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_GROUP_NOT_FOUND': 1,
#
# The caller does not have the required permissions to set the password.
#
'TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_PERMISSIONS': 2,
#
# Password length exceeded 'TOX_GROUP_MAX_PASSWORD_SIZE.
#
'TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_TOO_LONG': 3,
#
# The packet failed to send.
#
'TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_FAIL_SEND': 4
}
TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_GROUP_NOT_FOUND': 1,
#
# 'TOX_GROUP_PRIVACY_STATE is an invalid type.
#
'TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_INVALID': 2,
#
# The caller does not have the required permissions to set the privacy state.
#
'TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_PERMISSIONS': 3,
#
# The privacy state could not be set. This may occur due to an error related to
# cryptographic signing of the new shared state.
#
'TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_FAIL_SET': 4,
#
# The packet failed to send.
#
'TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_FAIL_SEND': 5
}
TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_GROUP_NOT_FOUND': 1,
#
# The caller does not have the required permissions to set the peer limit.
#
'TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_PERMISSIONS': 2,
#
# The peer limit could not be set. This may occur due to an error related to
# cryptographic signing of the new shared state.
#
'TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_FAIL_SET': 3,
#
# The packet failed to send.
#
'TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_FAIL_SEND': 4
}
TOX_ERR_GROUP_TOGGLE_IGNORE = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_TOGGLE_IGNORE_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_TOGGLE_IGNORE_GROUP_NOT_FOUND': 1,
#
# The ID passed did not designate a valid peer.
#
'TOX_ERR_GROUP_TOGGLE_IGNORE_PEER_NOT_FOUND': 2
}
TOX_ERR_GROUP_MOD_SET_ROLE = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_MOD_SET_ROLE_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_MOD_SET_ROLE_GROUP_NOT_FOUND': 1,
#
# The ID passed did not designate a valid peer. Note: you cannot set your own role.
#
'TOX_ERR_GROUP_MOD_SET_ROLE_PEER_NOT_FOUND': 2,
#
# The caller does not have the required permissions for this action.
#
'TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS': 3,
#
# The role assignment is invalid. This will occur if you try to set a peer's role to
# the role they already have.
#
'TOX_ERR_GROUP_MOD_SET_ROLE_ASSIGNMENT': 4,
#
# The role was not successfully set. This may occur if something goes wrong with role setting': ,
# or if the packet fails to send.
#
'TOX_ERR_GROUP_MOD_SET_ROLE_FAIL_ACTION': 5
}
TOX_ERR_GROUP_MOD_REMOVE_PEER = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_MOD_REMOVE_PEER_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_MOD_REMOVE_PEER_GROUP_NOT_FOUND': 1,
#
# The ID passed did not designate a valid peer.
#
'TOX_ERR_GROUP_MOD_REMOVE_PEER_PEER_NOT_FOUND': 2,
#
# The caller does not have the required permissions for this action.
#
'TOX_ERR_GROUP_MOD_REMOVE_PEER_PERMISSIONS': 3,
#
# The peer could not be removed from the group.
#
# If a ban was set': , this error indicates that the ban entry could not be created.
# This is usually due to the peer's IP address already occurring in the ban list. It may also
# be due to the entry containing invalid peer information': , or a failure to cryptographically
# authenticate the entry.
#
'TOX_ERR_GROUP_MOD_REMOVE_PEER_FAIL_ACTION': 4,
#
# The packet failed to send.
#
'TOX_ERR_GROUP_MOD_REMOVE_PEER_FAIL_SEND': 5
}
TOX_ERR_GROUP_MOD_REMOVE_BAN = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_MOD_REMOVE_BAN_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_MOD_REMOVE_BAN_GROUP_NOT_FOUND': 1,
#
# The caller does not have the required permissions for this action.
#
'TOX_ERR_GROUP_MOD_REMOVE_BAN_PERMISSIONS': 2,
#
# The ban entry could not be removed. This may occur if ban_id does not designate
# a valid ban entry.
#
'TOX_ERR_GROUP_MOD_REMOVE_BAN_FAIL_ACTION': 3,
#
# The packet failed to send.
#
'TOX_ERR_GROUP_MOD_REMOVE_BAN_FAIL_SEND': 4
}
TOX_GROUP_MOD_EVENT = {
#
# A peer has been kicked from the group.
#
'TOX_GROUP_MOD_EVENT_KICK': 0,
#
# A peer has been banned from the group.
#
'TOX_GROUP_MOD_EVENT_BAN': 1,
#
# A peer as been given the observer role.
#
'TOX_GROUP_MOD_EVENT_OBSERVER': 2,
#
# A peer has been given the user role.
#
'TOX_GROUP_MOD_EVENT_USER': 3,
#
# A peer has been given the moderator role.
#
'TOX_GROUP_MOD_EVENT_MODERATOR': 4,
}
TOX_ERR_GROUP_BAN_QUERY = {
#
# The function returned successfully.
#
'TOX_ERR_GROUP_BAN_QUERY_OK': 0,
#
# The group number passed did not designate a valid group.
#
'TOX_ERR_GROUP_BAN_QUERY_GROUP_NOT_FOUND': 1,
#
# The ban_id does not designate a valid ban list entry.
#
'TOX_ERR_GROUP_BAN_QUERY_BAD_ID': 2,
}
TOX_PUBLIC_KEY_SIZE = 32
TOX_ADDRESS_SIZE = TOX_PUBLIC_KEY_SIZE + 6
TOX_MAX_FRIEND_REQUEST_LENGTH = 1016
TOX_MAX_MESSAGE_LENGTH = 1372
TOX_GROUP_MAX_TOPIC_LENGTH = 512
TOX_GROUP_MAX_PART_LENGTH = 128
TOX_GROUP_MAX_GROUP_NAME_LENGTH = 48
TOX_GROUP_MAX_PASSWORD_SIZE = 32
TOX_GROUP_CHAT_ID_SIZE = 32
TOX_GROUP_PEER_PUBLIC_KEY_SIZE = 32
TOX_MAX_NAME_LENGTH = 128
TOX_MAX_STATUS_MESSAGE_LENGTH = 1007
TOX_SECRET_KEY_SIZE = 32
TOX_FILE_ID_LENGTH = 32
TOX_HASH_LENGTH = 32
TOX_MAX_CUSTOM_PACKET_SIZE = 1373

View File

@ -1,6 +1,6 @@
import libtox from wrapper import libtox
from ctypes import c_size_t, create_string_buffer, byref, c_int, ArgumentError, c_char_p, c_bool from ctypes import c_size_t, create_string_buffer, byref, c_int, ArgumentError, c_char_p, c_bool
from toxencryptsave_enums_and_consts import * from wrapper.toxencryptsave_enums_and_consts import *
class ToxEncryptSave: class ToxEncryptSave: