Compare commits
22 Commits
develop
...
groupchats
Author | SHA1 | Date | |
---|---|---|---|
|
098f295cb0 | ||
|
2fc90880b8 | ||
|
1ab59ee422 | ||
|
735c88d5bf | ||
|
2745caa531 | ||
|
4abd72e278 | ||
|
f775203f4c | ||
|
8a53fc8727 | ||
|
bb4e80ca09 | ||
|
3602b3433e | ||
|
dc96f66d8c | ||
|
bae87c8d72 | ||
|
4f42098d56 | ||
|
f13274882a | ||
|
c8bdb32e86 | ||
|
3ad7d20827 | ||
|
3aba7dffd2 | ||
|
9b0c6e63ce | ||
|
6703cbd301 | ||
|
40d0b03227 | ||
|
c0601444d9 | ||
|
c767ebe530 |
114
toxygen/basecontact.py
Normal file
114
toxygen/basecontact.py
Normal file
@ -0,0 +1,114 @@
|
||||
import os
|
||||
from settings import *
|
||||
try:
|
||||
from PySide import QtCore, QtGui
|
||||
except ImportError:
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from toxcore_enums_and_consts import TOX_PUBLIC_KEY_SIZE
|
||||
|
||||
|
||||
class BaseContact:
|
||||
"""
|
||||
Class encapsulating TOX contact
|
||||
Properties: name (alias of contact or name), status_message, status (connection status)
|
||||
widget - widget for update
|
||||
"""
|
||||
|
||||
def __init__(self, name, status_message, widget, tox_id):
|
||||
"""
|
||||
:param name: name, example: 'Toxygen user'
|
||||
:param status_message: status message, example: 'Toxing on Toxygen'
|
||||
:param widget: ContactItem instance
|
||||
:param tox_id: tox id of contact
|
||||
"""
|
||||
self._name, self._status_message = name, status_message
|
||||
self._status, self._widget = None, widget
|
||||
self._widget.name.setText(name)
|
||||
self._widget.status_message.setText(status_message)
|
||||
self._tox_id = tox_id
|
||||
self.load_avatar()
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Name - current name or alias of user
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_name(self):
|
||||
return self._name
|
||||
|
||||
def set_name(self, value):
|
||||
self._name = str(value, 'utf-8')
|
||||
self._widget.name.setText(self._name)
|
||||
self._widget.name.repaint()
|
||||
|
||||
name = property(get_name, set_name)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Status message or group topic
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_status_message(self):
|
||||
return self._status_message
|
||||
|
||||
def set_status_message(self, value):
|
||||
self._status_message = str(value, 'utf-8')
|
||||
self._widget.status_message.setText(self._status_message)
|
||||
self._widget.status_message.repaint()
|
||||
|
||||
status_message = property(get_status_message, set_status_message)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Status
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_status(self):
|
||||
return self._status
|
||||
|
||||
def set_status(self, value):
|
||||
self._status = value
|
||||
self._widget.connection_status.update(value)
|
||||
|
||||
status = property(get_status, set_status)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# TOX ID. WARNING: for friend it will return public key, for profile - full address
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_tox_id(self):
|
||||
return self._tox_id
|
||||
|
||||
tox_id = property(get_tox_id)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Avatars
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def load_avatar(self, default_path='avatar.png'):
|
||||
"""
|
||||
Tries to load avatar of contact or uses default avatar
|
||||
"""
|
||||
avatar_path = '{}.png'.format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2])
|
||||
os.chdir(ProfileHelper.get_path() + 'avatars/')
|
||||
if not os.path.isfile(avatar_path): # load default image
|
||||
avatar_path = default_path
|
||||
os.chdir(curr_directory() + '/images/')
|
||||
width = self._widget.avatar_label.width()
|
||||
pixmap = QtGui.QPixmap(QtCore.QSize(width, width))
|
||||
pixmap.load(avatar_path)
|
||||
self._widget.avatar_label.setScaledContents(False)
|
||||
self._widget.avatar_label.setPixmap(pixmap.scaled(width, width, QtCore.Qt.KeepAspectRatio))
|
||||
self._widget.avatar_label.repaint()
|
||||
|
||||
def reset_avatar(self):
|
||||
avatar_path = (ProfileHelper.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2])
|
||||
if os.path.isfile(avatar_path):
|
||||
os.remove(avatar_path)
|
||||
self.load_avatar()
|
||||
|
||||
def set_avatar(self, avatar):
|
||||
avatar_path = (ProfileHelper.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2])
|
||||
with open(avatar_path, 'wb') as f:
|
||||
f.write(avatar)
|
||||
self.load_avatar()
|
||||
|
||||
def get_pixmap(self):
|
||||
return self._widget.avatar_label.pixmap()
|
@ -287,6 +287,49 @@ def callback_audio(toxav, friend_number, samples, audio_samples_per_channel, aud
|
||||
rate)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Callbacks - group chats
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def group_message(window, tray, tox):
|
||||
"""
|
||||
New message in group chat
|
||||
"""
|
||||
def wrapped(tox_link, group_number, peer_id, message_type, message, length, user_data):
|
||||
profile = Profile.get_instance()
|
||||
settings = Settings.get_instance()
|
||||
message = str(message[:length], 'utf-8')
|
||||
invoke_in_main_thread(profile.new_message, group_number, message_type, message, True, peer_id)
|
||||
if not window.isActiveWindow():
|
||||
bl = settings['notify_all_gc'] or profile.name in message
|
||||
name = tox.group_peer_get_name(group_number, peer_id)
|
||||
if settings['notifications'] and profile.status != TOX_USER_STATUS['BUSY'] and (not settings.locked) and bl:
|
||||
invoke_in_main_thread(tray_notification, name, message, tray, window)
|
||||
if settings['sound_notifications'] and bl and profile.status != TOX_USER_STATUS['BUSY']:
|
||||
sound_notification(SOUND_NOTIFICATION['MESSAGE'])
|
||||
invoke_in_main_thread(tray.setIcon, QtGui.QIcon(curr_directory() + '/images/icon_new_messages.png'))
|
||||
return wrapped
|
||||
|
||||
|
||||
def group_invite(tox, friend_number, invite_data, length, user_data):
|
||||
invoke_in_main_thread(Profile.get_instance().process_group_invite,
|
||||
friend_number,
|
||||
bytes(invite_data[:length]))
|
||||
|
||||
|
||||
def group_self_join(tox, group_number, user_data):
|
||||
pr = Profile.get_instance()
|
||||
gc = pr.get_gc_by_number(group_number)
|
||||
invoke_in_main_thread(gc.set_status, TOX_USER_STATUS['NONE'])
|
||||
if not pr.is_active_a_friend() and pr.get_active_number() == group_number:
|
||||
invoke_in_main_thread(pr.set_active)
|
||||
|
||||
|
||||
def group_peer_join(tox, group_number, peer_id, user_data):
|
||||
gc = Profile.get_instance().get_gc_by_number(group_number)
|
||||
gc.add_peer(peer_id)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Callbacks - initialization
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
@ -323,3 +366,8 @@ def init_callbacks(tox, window, tray):
|
||||
tox.callback_friend_lossless_packet(lossless_packet, 0)
|
||||
tox.callback_friend_lossy_packet(lossy_packet, 0)
|
||||
|
||||
tox.callback_group_message(group_message(window, tray, tox), 0)
|
||||
tox.callback_group_invite(group_invite, 0)
|
||||
tox.callback_group_self_join(group_self_join, 0)
|
||||
tox.callback_group_peer_join(group_peer_join, 0)
|
||||
|
||||
|
@ -1,114 +1,212 @@
|
||||
import os
|
||||
from settings import *
|
||||
try:
|
||||
from PySide import QtCore, QtGui
|
||||
except ImportError:
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from toxcore_enums_and_consts import TOX_PUBLIC_KEY_SIZE
|
||||
import basecontact
|
||||
from messages import *
|
||||
from history import *
|
||||
import file_transfers as ft
|
||||
import util
|
||||
|
||||
|
||||
class Contact:
|
||||
class Contact(basecontact.BaseContact):
|
||||
"""
|
||||
Class encapsulating TOX contact
|
||||
Properties: name (alias of contact or name), status_message, status (connection status)
|
||||
widget - widget for update
|
||||
"""
|
||||
|
||||
def __init__(self, name, status_message, widget, tox_id):
|
||||
def __init__(self, number, message_getter, name, status_message, widget, tox_id):
|
||||
"""
|
||||
:param name: name, example: 'Toxygen user'
|
||||
:param status_message: status message, example: 'Toxing on Toxygen'
|
||||
:param widget: ContactItem instance
|
||||
:param tox_id: tox id of contact
|
||||
"""
|
||||
self._name, self._status_message = name, status_message
|
||||
self._status, self._widget = None, widget
|
||||
self._widget.name.setText(name)
|
||||
self._widget.status_message.setText(status_message)
|
||||
self._tox_id = tox_id
|
||||
self.load_avatar()
|
||||
super().__init__(name, status_message, widget, tox_id)
|
||||
self._message_getter = message_getter
|
||||
self._new_messages = False
|
||||
self._visible = True
|
||||
self._alias = False
|
||||
self._number = number
|
||||
self._corr = []
|
||||
self._unsaved_messages = 0
|
||||
self._history_loaded = self._new_actions = False
|
||||
self._curr_text = ''
|
||||
|
||||
def __del__(self):
|
||||
self.set_visibility(False)
|
||||
del self._widget
|
||||
if hasattr(self, '_message_getter'):
|
||||
del self._message_getter
|
||||
|
||||
def load_corr(self, first_time=True):
|
||||
"""
|
||||
:param first_time: friend became active, load first part of messages
|
||||
"""
|
||||
if (first_time and self._history_loaded) or (not hasattr(self, '_message_getter')):
|
||||
return
|
||||
data = list(self._message_getter.get(PAGE_SIZE))
|
||||
if data is not None and len(data):
|
||||
data.reverse()
|
||||
else:
|
||||
return
|
||||
data = list(map(lambda tupl: TextMessage(*tupl), data))
|
||||
self._corr = data + self._corr
|
||||
self._history_loaded = True
|
||||
|
||||
def get_corr_for_saving(self):
|
||||
"""
|
||||
Get data to save in db
|
||||
:return: list of unsaved messages or []
|
||||
"""
|
||||
messages = list(filter(lambda x: x.get_type() <= 1, self._corr))
|
||||
return list(map(lambda x: x.get_data(), messages[-self._unsaved_messages:])) if self._unsaved_messages else []
|
||||
|
||||
def get_corr(self):
|
||||
return self._corr[:]
|
||||
|
||||
def append_message(self, message):
|
||||
"""
|
||||
:param message: text or file transfer message
|
||||
"""
|
||||
self._corr.append(message)
|
||||
if message.get_type() <= 1:
|
||||
self._unsaved_messages += 1
|
||||
|
||||
def get_last_message_text(self):
|
||||
messages = list(filter(lambda x: x.get_type() <= 1 and x.get_owner() != MESSAGE_OWNER['FRIEND'], self._corr))
|
||||
if messages:
|
||||
return messages[-1].get_data()[0]
|
||||
else:
|
||||
return ''
|
||||
|
||||
def get_unsent_messages(self):
|
||||
"""
|
||||
:return list of unsent messages
|
||||
"""
|
||||
messages = filter(lambda x: x.get_owner() == MESSAGE_OWNER['NOT_SENT'], self._corr)
|
||||
return list(messages)
|
||||
|
||||
def get_unsent_messages_for_saving(self):
|
||||
"""
|
||||
:return list of unsent messages for saving
|
||||
"""
|
||||
messages = filter(lambda x: x.get_type() <= 1 and x.get_owner() == MESSAGE_OWNER['NOT_SENT'], self._corr)
|
||||
return list(map(lambda x: x.get_data(), messages))
|
||||
|
||||
def delete_message(self, time):
|
||||
elem = list(filter(lambda x: type(x) is TextMessage and x.get_data()[2] == time, self._corr))[0]
|
||||
tmp = list(filter(lambda x: x.get_type() <= 1, self._corr))
|
||||
if elem in tmp[-self._unsaved_messages:]:
|
||||
self._unsaved_messages -= 1
|
||||
self._corr.remove(elem)
|
||||
|
||||
def delete_old_messages(self):
|
||||
old = filter(lambda x: x.get_type() in (2, 3) and (x.get_status() >= 2 or x.get_status() is None),
|
||||
self._corr[:-SAVE_MESSAGES])
|
||||
old = list(old)
|
||||
l = max(len(self._corr) - SAVE_MESSAGES, 0) - len(old)
|
||||
self._unsaved_messages -= l
|
||||
self._corr = old + self._corr[-SAVE_MESSAGES:]
|
||||
|
||||
def mark_as_sent(self):
|
||||
try:
|
||||
message = list(filter(lambda x: x.get_owner() == MESSAGE_OWNER['NOT_SENT'], self._corr))[0]
|
||||
message.mark_as_sent()
|
||||
except Exception as ex:
|
||||
util.log('Mark as sent ex: ' + str(ex))
|
||||
|
||||
def clear_corr(self, save_unsent=False):
|
||||
"""
|
||||
Clear messages list
|
||||
"""
|
||||
if hasattr(self, '_message_getter'):
|
||||
del self._message_getter
|
||||
# don't delete data about active file transfer
|
||||
if not save_unsent:
|
||||
self._corr = list(filter(lambda x: x.get_type() in (2, 3) and
|
||||
x.get_status() in ft.ACTIVE_FILE_TRANSFERS, self._corr))
|
||||
self._unsaved_messages = 0
|
||||
else:
|
||||
self._corr = list(filter(lambda x: (x.get_type() in (2, 3) and x.get_status() in ft.ACTIVE_FILE_TRANSFERS)
|
||||
or (x.get_type() <= 1 and x.get_owner() == MESSAGE_OWNER['NOT_SENT']),
|
||||
self._corr))
|
||||
self._unsaved_messages = len(self.get_unsent_messages())
|
||||
|
||||
def get_curr_text(self):
|
||||
return self._curr_text
|
||||
|
||||
def set_curr_text(self, value):
|
||||
self._curr_text = value
|
||||
|
||||
curr_text = property(get_curr_text, set_curr_text)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# name - current name or alias of user
|
||||
# Visibility in friends' list
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_name(self):
|
||||
return self._name
|
||||
def get_visibility(self):
|
||||
return self._visible
|
||||
|
||||
def set_visibility(self, value):
|
||||
self._visible = value
|
||||
|
||||
visibility = property(get_visibility, set_visibility)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Unread messages and actions
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_actions(self):
|
||||
return self._new_actions
|
||||
|
||||
def set_actions(self, value):
|
||||
self._new_actions = value
|
||||
self._widget.connection_status.update(self.status, value)
|
||||
|
||||
actions = property(get_actions, set_actions) # unread messages, incoming files, av calls
|
||||
|
||||
def get_messages(self):
|
||||
return self._new_messages
|
||||
|
||||
def inc_messages(self):
|
||||
self._new_messages += 1
|
||||
self._new_actions = True
|
||||
self._widget.connection_status.update(self.status, True)
|
||||
self._widget.messages.update(self._new_messages)
|
||||
|
||||
def reset_messages(self):
|
||||
self._new_actions = False
|
||||
self._new_messages = 0
|
||||
self._widget.messages.update(self._new_messages)
|
||||
self._widget.connection_status.update(self.status, False)
|
||||
|
||||
messages = property(get_messages)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Number (can be used in toxcore)
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_number(self):
|
||||
return self._number
|
||||
|
||||
def set_number(self, value):
|
||||
self._number = value
|
||||
|
||||
number = property(get_number, set_number)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Alias support
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def set_name(self, value):
|
||||
self._name = str(value, 'utf-8')
|
||||
self._widget.name.setText(self._name)
|
||||
self._widget.name.repaint()
|
||||
|
||||
name = property(get_name, set_name)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Status message
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_status_message(self):
|
||||
return self._status_message
|
||||
|
||||
def set_status_message(self, value):
|
||||
self._status_message = str(value, 'utf-8')
|
||||
self._widget.status_message.setText(self._status_message)
|
||||
self._widget.status_message.repaint()
|
||||
|
||||
status_message = property(get_status_message, set_status_message)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Status
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_status(self):
|
||||
return self._status
|
||||
|
||||
def set_status(self, value):
|
||||
self._status = value
|
||||
self._widget.connection_status.update(value)
|
||||
|
||||
status = property(get_status, set_status)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# TOX ID. WARNING: for friend it will return public key, for profile - full address
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_tox_id(self):
|
||||
return self._tox_id
|
||||
|
||||
tox_id = property(get_tox_id)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Avatars
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def load_avatar(self):
|
||||
"""
|
||||
Tries to load avatar of contact or uses default avatar
|
||||
Set new name or ignore if alias exists
|
||||
:param value: new name
|
||||
"""
|
||||
avatar_path = '{}.png'.format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2])
|
||||
os.chdir(ProfileHelper.get_path() + 'avatars/')
|
||||
if not os.path.isfile(avatar_path): # load default image
|
||||
avatar_path = 'avatar.png'
|
||||
os.chdir(curr_directory() + '/images/')
|
||||
width = self._widget.avatar_label.width()
|
||||
pixmap = QtGui.QPixmap(QtCore.QSize(width, width))
|
||||
pixmap.load(avatar_path)
|
||||
self._widget.avatar_label.setScaledContents(False)
|
||||
self._widget.avatar_label.setPixmap(pixmap.scaled(width, width, QtCore.Qt.KeepAspectRatio))
|
||||
self._widget.avatar_label.repaint()
|
||||
if not self._alias:
|
||||
super(Contact, self).set_name(value)
|
||||
|
||||
def reset_avatar(self):
|
||||
avatar_path = (ProfileHelper.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2])
|
||||
if os.path.isfile(avatar_path):
|
||||
os.remove(avatar_path)
|
||||
self.load_avatar()
|
||||
|
||||
def set_avatar(self, avatar):
|
||||
avatar_path = (ProfileHelper.get_path() + 'avatars/{}.png').format(self._tox_id[:TOX_PUBLIC_KEY_SIZE * 2])
|
||||
with open(avatar_path, 'wb') as f:
|
||||
f.write(avatar)
|
||||
self.load_avatar()
|
||||
|
||||
def get_pixmap(self):
|
||||
return self._widget.avatar_label.pixmap()
|
||||
def set_alias(self, alias):
|
||||
self._alias = bool(alias)
|
||||
|
@ -1,8 +1,5 @@
|
||||
import contact
|
||||
from messages import *
|
||||
from history import *
|
||||
import util
|
||||
import file_transfers as ft
|
||||
|
||||
|
||||
class Friend(contact.Contact):
|
||||
@ -10,28 +7,15 @@ class Friend(contact.Contact):
|
||||
Friend in list of friends. Can be hidden, properties 'has unread messages' and 'has alias' added
|
||||
"""
|
||||
|
||||
def __init__(self, message_getter, number, *args):
|
||||
def __init__(self, *args):
|
||||
"""
|
||||
:param message_getter: gets messages from db
|
||||
:param number: number of friend.
|
||||
"""
|
||||
super(Friend, self).__init__(*args)
|
||||
self._number = number
|
||||
self._new_messages = False
|
||||
self._visible = True
|
||||
self._alias = False
|
||||
self._message_getter = message_getter
|
||||
self._corr = []
|
||||
self._unsaved_messages = 0
|
||||
self._history_loaded = self._new_actions = False
|
||||
self._receipts = 0
|
||||
self._curr_text = ''
|
||||
|
||||
def __del__(self):
|
||||
self.set_visibility(False)
|
||||
del self._widget
|
||||
if hasattr(self, '_message_getter'):
|
||||
del self._message_getter
|
||||
super().__del__()
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# History support
|
||||
@ -50,100 +34,6 @@ class Friend(contact.Contact):
|
||||
self._receipts -= 1
|
||||
self.mark_as_sent()
|
||||
|
||||
def load_corr(self, first_time=True):
|
||||
"""
|
||||
:param first_time: friend became active, load first part of messages
|
||||
"""
|
||||
if (first_time and self._history_loaded) or (not hasattr(self, '_message_getter')):
|
||||
return
|
||||
data = list(self._message_getter.get(PAGE_SIZE))
|
||||
if data is not None and len(data):
|
||||
data.reverse()
|
||||
else:
|
||||
return
|
||||
data = list(map(lambda tupl: TextMessage(*tupl), data))
|
||||
self._corr = data + self._corr
|
||||
self._history_loaded = True
|
||||
|
||||
def get_corr_for_saving(self):
|
||||
"""
|
||||
Get data to save in db
|
||||
:return: list of unsaved messages or []
|
||||
"""
|
||||
messages = list(filter(lambda x: x.get_type() <= 1, self._corr))
|
||||
return list(map(lambda x: x.get_data(), messages[-self._unsaved_messages:])) if self._unsaved_messages else []
|
||||
|
||||
def get_corr(self):
|
||||
return self._corr[:]
|
||||
|
||||
def append_message(self, message):
|
||||
"""
|
||||
:param message: text or file transfer message
|
||||
"""
|
||||
self._corr.append(message)
|
||||
if message.get_type() <= 1:
|
||||
self._unsaved_messages += 1
|
||||
|
||||
def get_last_message_text(self):
|
||||
messages = list(filter(lambda x: x.get_type() <= 1 and x.get_owner() != MESSAGE_OWNER['FRIEND'], self._corr))
|
||||
if messages:
|
||||
return messages[-1].get_data()[0]
|
||||
else:
|
||||
return ''
|
||||
|
||||
def get_unsent_messages(self):
|
||||
"""
|
||||
:return list of unsent messages
|
||||
"""
|
||||
messages = filter(lambda x: x.get_owner() == MESSAGE_OWNER['NOT_SENT'], self._corr)
|
||||
return list(messages)
|
||||
|
||||
def get_unsent_messages_for_saving(self):
|
||||
"""
|
||||
:return list of unsent messages for saving
|
||||
"""
|
||||
messages = filter(lambda x: x.get_type() <= 1 and x.get_owner() == MESSAGE_OWNER['NOT_SENT'], self._corr)
|
||||
return list(map(lambda x: x.get_data(), messages))
|
||||
|
||||
def delete_message(self, time):
|
||||
elem = list(filter(lambda x: type(x) is TextMessage and x.get_data()[2] == time, self._corr))[0]
|
||||
tmp = list(filter(lambda x: x.get_type() <= 1, self._corr))
|
||||
if elem in tmp[-self._unsaved_messages:]:
|
||||
self._unsaved_messages -= 1
|
||||
self._corr.remove(elem)
|
||||
|
||||
def mark_as_sent(self):
|
||||
try:
|
||||
message = list(filter(lambda x: x.get_owner() == MESSAGE_OWNER['NOT_SENT'], self._corr))[0]
|
||||
message.mark_as_sent()
|
||||
except Exception as ex:
|
||||
util.log('Mark as sent ex: ' + str(ex))
|
||||
|
||||
def clear_corr(self, save_unsent=False):
|
||||
"""
|
||||
Clear messages list
|
||||
"""
|
||||
if hasattr(self, '_message_getter'):
|
||||
del self._message_getter
|
||||
# don't delete data about active file transfer
|
||||
if not save_unsent:
|
||||
self._corr = list(filter(lambda x: x.get_type() in (2, 3) and
|
||||
x.get_status() in ft.ACTIVE_FILE_TRANSFERS, self._corr))
|
||||
self._unsaved_messages = 0
|
||||
else:
|
||||
self._corr = list(filter(lambda x: (x.get_type() in (2, 3) and x.get_status() in ft.ACTIVE_FILE_TRANSFERS)
|
||||
or (x.get_type() <= 1 and x.get_owner() == MESSAGE_OWNER['NOT_SENT']),
|
||||
self._corr))
|
||||
self._unsaved_messages = len(self.get_unsent_messages())
|
||||
|
||||
def get_curr_text(self):
|
||||
return self._curr_text
|
||||
|
||||
def set_curr_text(self, value):
|
||||
self._curr_text = value
|
||||
|
||||
curr_text = property(get_curr_text, set_curr_text)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# File transfers support
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
@ -172,72 +62,3 @@ class Friend(contact.Contact):
|
||||
|
||||
def delete_one_unsent_file(self, time):
|
||||
self._corr = list(filter(lambda x: not (type(x) is UnsentFile and x.get_data()[2] == time), self._corr))
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Alias support
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def set_name(self, value):
|
||||
"""
|
||||
Set new name or ignore if alias exists
|
||||
:param value: new name
|
||||
"""
|
||||
if not self._alias:
|
||||
super(Friend, self).set_name(value)
|
||||
|
||||
def set_alias(self, alias):
|
||||
self._alias = bool(alias)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Visibility in friends' list
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_visibility(self):
|
||||
return self._visible
|
||||
|
||||
def set_visibility(self, value):
|
||||
self._visible = value
|
||||
|
||||
visibility = property(get_visibility, set_visibility)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Unread messages from friend
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_actions(self):
|
||||
return self._new_actions
|
||||
|
||||
def set_actions(self, value):
|
||||
self._new_actions = value
|
||||
self._widget.connection_status.update(self.status, value)
|
||||
|
||||
actions = property(get_actions, set_actions) # unread messages, incoming files, av calls
|
||||
|
||||
def get_messages(self):
|
||||
return self._new_messages
|
||||
|
||||
def inc_messages(self):
|
||||
self._new_messages += 1
|
||||
self._new_actions = True
|
||||
self._widget.connection_status.update(self.status, True)
|
||||
self._widget.messages.update(self._new_messages)
|
||||
|
||||
def reset_messages(self):
|
||||
self._new_actions = False
|
||||
self._new_messages = 0
|
||||
self._widget.messages.update(self._new_messages)
|
||||
self._widget.connection_status.update(self.status, False)
|
||||
|
||||
messages = property(get_messages)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Friend's number (can be used in toxcore)
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_number(self):
|
||||
return self._number
|
||||
|
||||
def set_number(self, value):
|
||||
self._number = value
|
||||
|
||||
number = property(get_number, set_number)
|
||||
|
36
toxygen/groupchat.py
Normal file
36
toxygen/groupchat.py
Normal file
@ -0,0 +1,36 @@
|
||||
import contact
|
||||
|
||||
|
||||
class GroupChat(contact.Contact):
|
||||
|
||||
def __init__(self, tox, *args):
|
||||
super().__init__(*args)
|
||||
self._tox = tox
|
||||
|
||||
def load_avatar(self, default_path='group.png'):
|
||||
super().load_avatar(default_path)
|
||||
|
||||
def set_status(self, value):
|
||||
print('In gc set_status')
|
||||
super().set_status(value)
|
||||
self.name = bytes(self._tox.group_get_name(self._number), 'utf-8')
|
||||
self._tox_id = self._tox.group_get_chat_id(self._number)
|
||||
self.status_message = bytes(self._tox.group_get_topic(self._number), 'utf-8')
|
||||
|
||||
def add_peer(self, peer_id):
|
||||
print(peer_id)
|
||||
print(self._tox.group_peer_get_name(self._number, peer_id))
|
||||
|
||||
# TODO: get peers list and add other methods
|
||||
|
||||
def get_peers_list(self):
|
||||
return []
|
||||
|
||||
|
||||
class Peer:
|
||||
|
||||
def __init__(self, peer_id, name, status, role):
|
||||
self._data = (peer_id, name, status, role)
|
||||
|
||||
def get_data(self):
|
||||
return self._data
|
@ -8,6 +8,8 @@ from toxencryptsave import ToxEncryptSave
|
||||
|
||||
PAGE_SIZE = 42
|
||||
|
||||
SAVE_MESSAGES = 150
|
||||
|
||||
MESSAGE_OWNER = {
|
||||
'ME': 0,
|
||||
'FRIEND': 1,
|
||||
|
BIN
toxygen/images/group.png
Executable file
BIN
toxygen/images/group.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
@ -29,6 +29,8 @@ class MainWindow(QtGui.QMainWindow):
|
||||
|
||||
self.menuProfile = QtGui.QMenu(self.menubar)
|
||||
self.menuProfile.setObjectName("menuProfile")
|
||||
self.menuGroupChats = QtGui.QMenu(self.menubar)
|
||||
self.menuGroupChats.setObjectName("menuGroupChats")
|
||||
self.menuSettings = QtGui.QMenu(self.menubar)
|
||||
self.menuSettings.setObjectName("menuSettings")
|
||||
self.menuPlugins = QtGui.QMenu(self.menubar)
|
||||
@ -56,6 +58,12 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.pluginData = QtGui.QAction(MainWindow)
|
||||
self.importPlugin = QtGui.QAction(MainWindow)
|
||||
self.lockApp = QtGui.QAction(MainWindow)
|
||||
self.createGC = QtGui.QAction(MainWindow)
|
||||
self.joinGC = QtGui.QAction(MainWindow)
|
||||
self.gcRequests = QtGui.QAction(MainWindow)
|
||||
self.menuGroupChats.addAction(self.createGC)
|
||||
self.menuGroupChats.addAction(self.joinGC)
|
||||
self.menuGroupChats.addAction(self.gcRequests)
|
||||
self.menuProfile.addAction(self.actionAdd_friend)
|
||||
self.menuProfile.addAction(self.actionSettings)
|
||||
self.menuProfile.addAction(self.lockApp)
|
||||
@ -68,6 +76,7 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.menuPlugins.addAction(self.importPlugin)
|
||||
self.menuAbout.addAction(self.actionAbout_program)
|
||||
self.menubar.addAction(self.menuProfile.menuAction())
|
||||
self.menubar.addAction(self.menuGroupChats.menuAction())
|
||||
self.menubar.addAction(self.menuSettings.menuAction())
|
||||
self.menubar.addAction(self.menuPlugins.menuAction())
|
||||
self.menubar.addAction(self.menuAbout.menuAction())
|
||||
@ -75,14 +84,18 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.actionAbout_program.triggered.connect(self.about_program)
|
||||
self.actionNetwork.triggered.connect(self.network_settings)
|
||||
self.actionAdd_friend.triggered.connect(self.add_contact)
|
||||
self.actionSettings.triggered.connect(self.profilesettings)
|
||||
self.actionSettings.triggered.connect(self.profile_settings)
|
||||
self.actionPrivacy_settings.triggered.connect(self.privacy_settings)
|
||||
self.actionInterface_settings.triggered.connect(self.interface_settings)
|
||||
self.actionNotifications.triggered.connect(self.notification_settings)
|
||||
self.audioSettings.triggered.connect(self.audio_settings)
|
||||
self.pluginData.triggered.connect(self.plugins_menu)
|
||||
|
||||
self.lockApp.triggered.connect(self.lock_app)
|
||||
self.importPlugin.triggered.connect(self.import_plugin)
|
||||
self.createGC.triggered.connect(self.create_groupchat)
|
||||
self.joinGC.triggered.connect(self.join_groupchat)
|
||||
|
||||
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||
|
||||
def languageChange(self, *args, **kwargs):
|
||||
@ -94,7 +107,11 @@ class MainWindow(QtGui.QMainWindow):
|
||||
return super(MainWindow, self).event(event)
|
||||
|
||||
def retranslateUi(self):
|
||||
self.joinGC.setText(QtGui.QApplication.translate("MainWindow", "Join group chat", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.lockApp.setText(QtGui.QApplication.translate("MainWindow", "Lock", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.menuGroupChats.setTitle(QtGui.QApplication.translate("MainWindow", "Group chats", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.createGC.setText(QtGui.QApplication.translate("MainWindow", "Create group chat", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.gcRequests.setText(QtGui.QApplication.translate("MainWindow", "Groupchat requests", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.menuPlugins.setTitle(QtGui.QApplication.translate("MainWindow", "Plugins", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.pluginData.setText(QtGui.QApplication.translate("MainWindow", "List of plugins", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.menuProfile.setTitle(QtGui.QApplication.translate("MainWindow", "Profile", None, QtGui.QApplication.UnicodeUTF8))
|
||||
@ -193,9 +210,9 @@ class MainWindow(QtGui.QMainWindow):
|
||||
Form.status_message.setObjectName("status_message")
|
||||
self.connection_status = Form.connection_status = StatusCircle(Form)
|
||||
Form.connection_status.setGeometry(QtCore.QRect(230, 35, 32, 32))
|
||||
self.avatar_label.mouseReleaseEvent = self.profilesettings
|
||||
self.status_message.mouseReleaseEvent = self.profilesettings
|
||||
self.name.mouseReleaseEvent = self.profilesettings
|
||||
self.avatar_label.mouseReleaseEvent = self.profile_settings
|
||||
self.status_message.mouseReleaseEvent = self.profile_settings
|
||||
self.name.mouseReleaseEvent = self.profile_settings
|
||||
self.connection_status.raise_()
|
||||
Form.connection_status.setObjectName("connection_status")
|
||||
|
||||
@ -220,6 +237,11 @@ class MainWindow(QtGui.QMainWindow):
|
||||
font.setBold(False)
|
||||
self.account_status.setFont(font)
|
||||
self.account_status.setObjectName("account_status")
|
||||
|
||||
self.account_status.mouseReleaseEvent = self.show_chat_menu
|
||||
self.account_name.mouseReleaseEvent = self.show_chat_menu
|
||||
self.account_avatar.mouseReleaseEvent = self.show_chat_menu
|
||||
|
||||
self.callButton = QtGui.QPushButton(Form)
|
||||
self.callButton.setGeometry(QtCore.QRect(550, 30, 50, 50))
|
||||
self.callButton.setObjectName("callButton")
|
||||
@ -377,7 +399,7 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.a_c = AddContact(link)
|
||||
self.a_c.show()
|
||||
|
||||
def profilesettings(self, *args):
|
||||
def profile_settings(self, *args):
|
||||
self.p_s = ProfileSettings()
|
||||
self.p_s.show()
|
||||
|
||||
@ -439,6 +461,19 @@ class MainWindow(QtGui.QMainWindow):
|
||||
120))
|
||||
self.menu.show()
|
||||
|
||||
def create_groupchat(self):
|
||||
self.gc = AddGroupchat()
|
||||
self.gc.show()
|
||||
|
||||
def join_groupchat(self):
|
||||
self.gc = JoinGroupchat()
|
||||
self.gc.show()
|
||||
|
||||
def show_chat_menu(self):
|
||||
pr = Profile.get_instance()
|
||||
if not pr.is_active_a_friend():
|
||||
pass # TODO: show list of users in chat
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Messages, calls and file transfers
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
@ -449,6 +484,8 @@ class MainWindow(QtGui.QMainWindow):
|
||||
|
||||
def send_file(self):
|
||||
self.menu.hide()
|
||||
if not self.profile.is_active_a_friend():
|
||||
return
|
||||
if self.profile.active_friend + 1:
|
||||
choose = QtGui.QApplication.translate("MainWindow", 'Choose file', None, QtGui.QApplication.UnicodeUTF8)
|
||||
name = QtGui.QFileDialog.getOpenFileName(self, choose, options=QtGui.QFileDialog.DontUseNativeDialog)
|
||||
@ -457,6 +494,8 @@ class MainWindow(QtGui.QMainWindow):
|
||||
|
||||
def send_screenshot(self, hide=False):
|
||||
self.menu.hide()
|
||||
if not self.profile.is_active_a_friend():
|
||||
return
|
||||
if self.profile.active_friend + 1:
|
||||
self.sw = ScreenShotWindow(self)
|
||||
self.sw.show()
|
||||
@ -475,6 +514,8 @@ class MainWindow(QtGui.QMainWindow):
|
||||
|
||||
def send_sticker(self):
|
||||
self.menu.hide()
|
||||
if not self.profile.is_active_a_friend():
|
||||
return
|
||||
if self.profile.active_friend + 1:
|
||||
self.sticker = StickerWindow(self)
|
||||
self.sticker.setGeometry(QtCore.QRect(self.x() if Settings.get_instance()['mirror_mode'] else 270 + self.x(),
|
||||
@ -511,35 +552,60 @@ class MainWindow(QtGui.QMainWindow):
|
||||
def friend_right_click(self, pos):
|
||||
item = self.friends_list.itemAt(pos)
|
||||
num = self.friends_list.indexFromItem(item).row()
|
||||
friend = Profile.get_instance().get_friend(num)
|
||||
friend = Profile.get_instance().get_friend_or_gc(num)
|
||||
settings = Settings.get_instance()
|
||||
allowed = friend.tox_id in settings['auto_accept_from_friends']
|
||||
auto = QtGui.QApplication.translate("MainWindow", 'Disallow auto accept', None, QtGui.QApplication.UnicodeUTF8) if allowed else QtGui.QApplication.translate("MainWindow", 'Allow auto accept', None, QtGui.QApplication.UnicodeUTF8)
|
||||
if item is not None:
|
||||
self.listMenu = QtGui.QMenu()
|
||||
set_alias_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Set alias', None, QtGui.QApplication.UnicodeUTF8))
|
||||
clear_history_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Clear history', None, QtGui.QApplication.UnicodeUTF8))
|
||||
copy_menu = self.listMenu.addMenu(QtGui.QApplication.translate("MainWindow", 'Copy', None, QtGui.QApplication.UnicodeUTF8))
|
||||
copy_name_item = copy_menu.addAction(QtGui.QApplication.translate("MainWindow", 'Name', None, QtGui.QApplication.UnicodeUTF8))
|
||||
copy_status_item = copy_menu.addAction(QtGui.QApplication.translate("MainWindow", 'Status message', None, QtGui.QApplication.UnicodeUTF8))
|
||||
copy_key_item = copy_menu.addAction(QtGui.QApplication.translate("MainWindow", 'Public key', None, QtGui.QApplication.UnicodeUTF8))
|
||||
if type(friend) is Friend:
|
||||
arr = Profile.get_instance().get_all_gc()
|
||||
if arr:
|
||||
gc_menu = self.listMenu.addMenu(QtGui.QApplication.translate("MainWindow", 'Invite to group chat', None, QtGui.QApplication.UnicodeUTF8))
|
||||
for gc in arr:
|
||||
item = gc_menu.addAction(gc.name)
|
||||
self.connect(item, QtCore.SIGNAL("triggered()"),
|
||||
lambda: Profile.get_instance().invite_friend(gc.number, friend.number))
|
||||
|
||||
auto_accept_item = self.listMenu.addAction(auto)
|
||||
remove_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Remove friend', None, QtGui.QApplication.UnicodeUTF8))
|
||||
notes_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Notes', None, QtGui.QApplication.UnicodeUTF8))
|
||||
set_alias_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Set alias', None, QtGui.QApplication.UnicodeUTF8))
|
||||
clear_history_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Clear history', None, QtGui.QApplication.UnicodeUTF8))
|
||||
copy_menu = self.listMenu.addMenu(QtGui.QApplication.translate("MainWindow", 'Copy', None, QtGui.QApplication.UnicodeUTF8))
|
||||
copy_name_item = copy_menu.addAction(QtGui.QApplication.translate("MainWindow", 'Name', None, QtGui.QApplication.UnicodeUTF8))
|
||||
copy_status_item = copy_menu.addAction(QtGui.QApplication.translate("MainWindow", 'Status message', None, QtGui.QApplication.UnicodeUTF8))
|
||||
copy_key_item = copy_menu.addAction(QtGui.QApplication.translate("MainWindow", 'Public key', None, QtGui.QApplication.UnicodeUTF8))
|
||||
|
||||
auto_accept_item = self.listMenu.addAction(auto)
|
||||
remove_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Remove friend', None, QtGui.QApplication.UnicodeUTF8))
|
||||
notes_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Notes', None, QtGui.QApplication.UnicodeUTF8))
|
||||
|
||||
submenu = plugin_support.PluginLoader.get_instance().get_menu(self.listMenu, num)
|
||||
if len(submenu):
|
||||
plug = self.listMenu.addMenu(QtGui.QApplication.translate("MainWindow", 'Plugins', None, QtGui.QApplication.UnicodeUTF8))
|
||||
plug.addActions(submenu)
|
||||
self.connect(remove_item, QtCore.SIGNAL("triggered()"), lambda: self.remove_friend(num))
|
||||
self.connect(auto_accept_item, QtCore.SIGNAL("triggered()"), lambda: self.auto_accept(num, not allowed))
|
||||
else:
|
||||
copy_menu = self.listMenu.addMenu(
|
||||
QtGui.QApplication.translate("MainWindow", 'Copy', None, QtGui.QApplication.UnicodeUTF8))
|
||||
copy_name_item = copy_menu.addAction(
|
||||
QtGui.QApplication.translate("MainWindow", 'Name', None, QtGui.QApplication.UnicodeUTF8))
|
||||
copy_status_item = copy_menu.addAction(
|
||||
QtGui.QApplication.translate("MainWindow", 'Topic', None, QtGui.QApplication.UnicodeUTF8))
|
||||
copy_key_item = copy_menu.addAction(
|
||||
QtGui.QApplication.translate("MainWindow", 'Public key', None, QtGui.QApplication.UnicodeUTF8))
|
||||
leave_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Leave group', None, QtGui.QApplication.UnicodeUTF8))
|
||||
set_alias_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Set alias', None, QtGui.QApplication.UnicodeUTF8))
|
||||
clear_history_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Clear history', None, QtGui.QApplication.UnicodeUTF8))
|
||||
notes_item = self.listMenu.addAction(QtGui.QApplication.translate("MainWindow", 'Notes', None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.connect(leave_item, QtCore.SIGNAL("triggered()"), lambda: Profile.get_instance().leave_group(num))
|
||||
|
||||
submenu = plugin_support.PluginLoader.get_instance().get_menu(self.listMenu, num)
|
||||
if len(submenu):
|
||||
plug = self.listMenu.addMenu(QtGui.QApplication.translate("MainWindow", 'Plugins', None, QtGui.QApplication.UnicodeUTF8))
|
||||
plug.addActions(submenu)
|
||||
self.connect(set_alias_item, QtCore.SIGNAL("triggered()"), lambda: self.set_alias(num))
|
||||
self.connect(remove_item, QtCore.SIGNAL("triggered()"), lambda: self.remove_friend(num))
|
||||
self.connect(copy_key_item, QtCore.SIGNAL("triggered()"), lambda: self.copy_friend_key(num))
|
||||
self.connect(clear_history_item, QtCore.SIGNAL("triggered()"), lambda: self.clear_history(num))
|
||||
self.connect(auto_accept_item, QtCore.SIGNAL("triggered()"), lambda: self.auto_accept(num, not allowed))
|
||||
self.connect(notes_item, QtCore.SIGNAL("triggered()"), lambda: self.show_note(friend))
|
||||
self.connect(set_alias_item, QtCore.SIGNAL("triggered()"), lambda: self.set_alias(num))
|
||||
self.connect(clear_history_item, QtCore.SIGNAL("triggered()"), lambda: self.clear_history(num))
|
||||
self.connect(copy_name_item, QtCore.SIGNAL("triggered()"), lambda: self.copy_name(friend))
|
||||
self.connect(copy_status_item, QtCore.SIGNAL("triggered()"), lambda: self.copy_status(friend))
|
||||
self.connect(copy_key_item, QtCore.SIGNAL("triggered()"), lambda: self.copy_friend_key(num))
|
||||
|
||||
parent_position = self.friends_list.mapToGlobal(QtCore.QPoint(0, 0))
|
||||
self.listMenu.move(parent_position + pos)
|
||||
self.listMenu.show()
|
||||
@ -563,7 +629,7 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.profile.set_alias(num)
|
||||
|
||||
def remove_friend(self, num):
|
||||
self.profile.delete_friend(num)
|
||||
self.profile.delete_friend_or_gc(num)
|
||||
|
||||
def copy_friend_key(self, num):
|
||||
tox_id = self.profile.friend_public_key(num)
|
||||
|
103
toxygen/menu.py
103
toxygen/menu.py
@ -11,6 +11,97 @@ import toxencryptsave
|
||||
import plugin_support
|
||||
|
||||
|
||||
class AddGroupchat(CenteredWidget):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.initUI()
|
||||
self.retranslateUi()
|
||||
self.center()
|
||||
|
||||
def initUI(self):
|
||||
self.setObjectName('AddGC')
|
||||
self.resize(570, 240)
|
||||
self.setMaximumSize(QtCore.QSize(570, 240))
|
||||
self.setMinimumSize(QtCore.QSize(570, 240))
|
||||
self.label = QtGui.QLabel(self)
|
||||
self.label.setGeometry(QtCore.QRect(50, 20, 470, 20))
|
||||
self.createGCButton = QtGui.QPushButton(self)
|
||||
self.createGCButton.setGeometry(QtCore.QRect(50, 190, 470, 30))
|
||||
self.name = LineEdit(self)
|
||||
self.name.setGeometry(QtCore.QRect(50, 40, 470, 27))
|
||||
self.privacy_type = QtGui.QLabel(self)
|
||||
self.privacy_type.setGeometry(QtCore.QRect(50, 70, 470, 20))
|
||||
self.privacy_combobox = QtGui.QComboBox(self)
|
||||
self.privacy_combobox.setGeometry(QtCore.QRect(50, 90, 470, 30))
|
||||
self.pass_label = QtGui.QLabel(self)
|
||||
self.pass_label.setGeometry(QtCore.QRect(50, 130, 470, 20))
|
||||
self.password = LineEdit(self)
|
||||
self.password.setGeometry(QtCore.QRect(50, 150, 470, 27))
|
||||
self.password.setEchoMode(QtGui.QLineEdit.EchoMode.Password)
|
||||
|
||||
self.createGCButton.clicked.connect(self.button_click)
|
||||
QtCore.QMetaObject.connectSlotsByName(self)
|
||||
|
||||
def retranslateUi(self):
|
||||
self.setWindowTitle(QtGui.QApplication.translate('AddGC', "Create group chat", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.createGCButton.setText(QtGui.QApplication.translate("AddGC", "Create", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.label.setText(QtGui.QApplication.translate('AddGC', "Name:", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.privacy_type.setText(QtGui.QApplication.translate('AddGC', "Privacy type:", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.privacy_combobox.addItem(QtGui.QApplication.translate('AddGC', "Public", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.privacy_combobox.addItem(QtGui.QApplication.translate('AddGC', "Private", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.name.setPlaceholderText(QtGui.QApplication.translate('AddGC', "Not empty group name", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.password.setPlaceholderText(QtGui.QApplication.translate('AddGC', "Optional password", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.pass_label.setText(QtGui.QApplication.translate('AddGC', "Password:", None, QtGui.QApplication.UnicodeUTF8))
|
||||
|
||||
def button_click(self):
|
||||
if self.name.text():
|
||||
Profile.get_instance().create_gc(self.name.text(),
|
||||
self.privacy_combobox.currentIndex() == 0,
|
||||
self.password.text())
|
||||
self.close()
|
||||
|
||||
|
||||
class JoinGroupchat(CenteredWidget):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.initUI()
|
||||
self.retranslateUi()
|
||||
self.center()
|
||||
|
||||
def initUI(self):
|
||||
self.setObjectName('AddGC')
|
||||
self.resize(570, 150)
|
||||
self.setMaximumSize(QtCore.QSize(570, 150))
|
||||
self.setMinimumSize(QtCore.QSize(570, 150))
|
||||
self.joinGCButton = QtGui.QPushButton(self)
|
||||
self.joinGCButton.setGeometry(QtCore.QRect(50, 110, 470, 30))
|
||||
self.id = LineEdit(self)
|
||||
self.id.setGeometry(QtCore.QRect(50, 10, 470, 30))
|
||||
self.password = LineEdit(self)
|
||||
self.password.setGeometry(QtCore.QRect(50, 50, 470, 30))
|
||||
self.password.setEchoMode(QtGui.QLineEdit.EchoMode.Password)
|
||||
|
||||
self.joinGCButton.clicked.connect(self.button_click)
|
||||
QtCore.QMetaObject.connectSlotsByName(self)
|
||||
|
||||
def retranslateUi(self):
|
||||
self.setWindowTitle(
|
||||
QtGui.QApplication.translate('JoinGC', "Join group chat", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.joinGCButton.setText(
|
||||
QtGui.QApplication.translate("JoinGC", "Join", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.id.setPlaceholderText(
|
||||
QtGui.QApplication.translate('JoinGC', "Group ID", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.password.setPlaceholderText(
|
||||
QtGui.QApplication.translate('JoinGC', "Optional password", None, QtGui.QApplication.UnicodeUTF8))
|
||||
|
||||
def button_click(self):
|
||||
if self.id.text():
|
||||
Profile.get_instance().join_gc(self.id.text().strip(), self.password.text())
|
||||
self.close()
|
||||
|
||||
|
||||
class AddContact(CenteredWidget):
|
||||
"""Add contact form"""
|
||||
|
||||
@ -510,28 +601,33 @@ class NotificationsSettings(CenteredWidget):
|
||||
|
||||
def initUI(self):
|
||||
self.setObjectName("notificationsForm")
|
||||
self.resize(350, 180)
|
||||
self.setMinimumSize(QtCore.QSize(350, 180))
|
||||
self.setMaximumSize(QtCore.QSize(350, 180))
|
||||
self.resize(350, 200)
|
||||
self.setMinimumSize(QtCore.QSize(350, 200))
|
||||
self.setMaximumSize(QtCore.QSize(350, 200))
|
||||
self.enableNotifications = QtGui.QCheckBox(self)
|
||||
self.enableNotifications.setGeometry(QtCore.QRect(10, 20, 340, 18))
|
||||
self.callsSound = QtGui.QCheckBox(self)
|
||||
self.callsSound.setGeometry(QtCore.QRect(10, 120, 340, 18))
|
||||
self.soundNotifications = QtGui.QCheckBox(self)
|
||||
self.soundNotifications.setGeometry(QtCore.QRect(10, 70, 340, 18))
|
||||
self.gcNotifications = QtGui.QCheckBox(self)
|
||||
self.gcNotifications.setGeometry(QtCore.QRect(10, 170, 340, 18))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(12)
|
||||
self.callsSound.setFont(font)
|
||||
self.soundNotifications.setFont(font)
|
||||
self.enableNotifications.setFont(font)
|
||||
self.gcNotifications.setFont(font)
|
||||
s = Settings.get_instance()
|
||||
self.enableNotifications.setChecked(s['notifications'])
|
||||
self.soundNotifications.setChecked(s['sound_notifications'])
|
||||
self.callsSound.setChecked(s['calls_sound'])
|
||||
self.gcNotifications.setChecked(s['notify_all_gc'])
|
||||
self.retranslateUi()
|
||||
QtCore.QMetaObject.connectSlotsByName(self)
|
||||
|
||||
def retranslateUi(self):
|
||||
self.gcNotifications.setText(QtGui.QApplication.translate("notificationsForm", "Enable group chat notifications", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.setWindowTitle(QtGui.QApplication.translate("notificationsForm", "Notification settings", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.enableNotifications.setText(QtGui.QApplication.translate("notificationsForm", "Enable notifications", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.callsSound.setText(QtGui.QApplication.translate("notificationsForm", "Enable call\'s sound", None, QtGui.QApplication.UnicodeUTF8))
|
||||
@ -542,6 +638,7 @@ class NotificationsSettings(CenteredWidget):
|
||||
settings['notifications'] = self.enableNotifications.isChecked()
|
||||
settings['sound_notifications'] = self.soundNotifications.isChecked()
|
||||
settings['calls_sound'] = self.callsSound.isChecked()
|
||||
settings['notify_all_gc'] = self.gcNotifications.isChecked()
|
||||
settings.save()
|
||||
|
||||
|
||||
|
@ -39,6 +39,18 @@ class TextMessage(Message):
|
||||
return self._message, self._owner, self._time, self._type
|
||||
|
||||
|
||||
class GroupChatTextMessage(TextMessage):
|
||||
|
||||
def __init__(self, friend_name, *args):
|
||||
super().__init__(*args)
|
||||
self._name = friend_name
|
||||
|
||||
def get_data(self):
|
||||
data = list(super().get_data())
|
||||
data.append(self._name)
|
||||
return tuple(data)
|
||||
|
||||
|
||||
class TransferMessage(Message):
|
||||
"""
|
||||
Message with info about file transfer
|
||||
@ -71,6 +83,7 @@ class TransferMessage(Message):
|
||||
|
||||
|
||||
class UnsentFile(Message):
|
||||
|
||||
def __init__(self, path, data, time):
|
||||
super(UnsentFile, self).__init__(MESSAGE_TYPE['FILE_TRANSFER'], 0, time)
|
||||
self._data, self._path = data, path
|
||||
|
@ -15,9 +15,11 @@ import time
|
||||
import calls
|
||||
import avwidgets
|
||||
import plugin_support
|
||||
import basecontact
|
||||
from groupchat import *
|
||||
|
||||
|
||||
class Profile(contact.Contact, Singleton):
|
||||
class Profile(basecontact.BaseContact, Singleton):
|
||||
"""
|
||||
Profile of current toxygen user. Contains friends list, tox instance
|
||||
"""
|
||||
@ -26,11 +28,11 @@ class Profile(contact.Contact, Singleton):
|
||||
:param tox: tox instance
|
||||
:param screen: ref to main screen
|
||||
"""
|
||||
contact.Contact.__init__(self,
|
||||
tox.self_get_name(),
|
||||
tox.self_get_status_message(),
|
||||
screen.user_info,
|
||||
tox.self_get_address())
|
||||
basecontact.BaseContact.__init__(self,
|
||||
tox.self_get_name(),
|
||||
tox.self_get_status_message(),
|
||||
screen.user_info,
|
||||
tox.self_get_address())
|
||||
Singleton.__init__(self)
|
||||
self._screen = screen
|
||||
self._messages = screen.messages
|
||||
@ -39,13 +41,14 @@ class Profile(contact.Contact, Singleton):
|
||||
self._call = calls.AV(tox.AV) # object with data about calls
|
||||
self._incoming_calls = set()
|
||||
self._load_history = True
|
||||
self._gc_invites = {} # dict of gc invites. key - friend number, value - list of gc data
|
||||
settings = Settings.get_instance()
|
||||
self._show_online = settings['show_online_friends']
|
||||
screen.online_contacts.setCurrentIndex(int(self._show_online))
|
||||
aliases = settings['friends_aliases']
|
||||
data = tox.self_get_friend_list()
|
||||
self._history = History(tox.self_get_public_key()) # connection to db
|
||||
self._friends, self._active_friend = [], -1
|
||||
self._friends_and_gc, self._active_friend_or_gc = [], -1
|
||||
for i in data: # creates list of friends
|
||||
tox_id = tox.friend_get_public_key(i)
|
||||
try:
|
||||
@ -58,9 +61,27 @@ class Profile(contact.Contact, Singleton):
|
||||
if not self._history.friend_exists_in_db(tox_id):
|
||||
self._history.add_friend_to_db(tox_id)
|
||||
message_getter = self._history.messages_getter(tox_id)
|
||||
friend = Friend(message_getter, i, name, status_message, item, tox_id)
|
||||
friend = Friend(i, message_getter, name, status_message, item, tox_id)
|
||||
friend.set_alias(alias)
|
||||
self._friends.append(friend)
|
||||
self._friends_and_gc.append(friend)
|
||||
|
||||
l = self._tox.group_get_number_groups()
|
||||
for i in range(l): # creates list of group chats
|
||||
tox_id = tox.group_get_chat_id(i)
|
||||
try:
|
||||
alias = list(filter(lambda x: x[0] == tox_id, aliases))[0][1]
|
||||
except:
|
||||
alias = ''
|
||||
item = self.create_friend_item()
|
||||
name = alias or tox.group_get_name(i) or tox_id
|
||||
status_message = tox.group_get_topic(i)
|
||||
if not self._history.friend_exists_in_db(tox_id):
|
||||
self._history.add_friend_to_db(tox_id)
|
||||
message_getter = self._history.messages_getter(tox_id)
|
||||
gc = GroupChat(self._tox, i, message_getter, name, status_message, item, tox_id)
|
||||
gc.set_alias(alias)
|
||||
self._friends_and_gc.append(gc)
|
||||
|
||||
self.filtration(self._show_online)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
@ -75,6 +96,9 @@ class Profile(contact.Contact, Singleton):
|
||||
self.set_status((self._status + 1) % 3)
|
||||
|
||||
def set_status(self, status):
|
||||
if self.status is None:
|
||||
for gc in filter(lambda x: type(x) is GroupChat, self._friends_and_gc):
|
||||
self._tox.group_reconnect(gc.number)
|
||||
super(Profile, self).set_status(status)
|
||||
if status is not None:
|
||||
self._tox.self_set_status(status)
|
||||
@ -87,11 +111,11 @@ class Profile(contact.Contact, Singleton):
|
||||
self._tox.self_set_name(self._name.encode('utf-8'))
|
||||
message = QtGui.QApplication.translate("MainWindow", 'User {} is now known as {}', None,
|
||||
QtGui.QApplication.UnicodeUTF8)
|
||||
message = message.format(tmp, value)
|
||||
for friend in self._friends:
|
||||
message = message.format(tmp, str(value, 'utf-8'))
|
||||
for friend in self._friends_and_gc:
|
||||
friend.append_message(InfoMessage(message, time.time()))
|
||||
if self._active_friend + 1:
|
||||
self.create_message_item(message, time.time(), '', MESSAGE_TYPE['INFO_MESSAGE'])
|
||||
if self._active_friend_or_gc + 1:
|
||||
self.create_message_item(message, curr_time(), '', MESSAGE_TYPE['INFO_MESSAGE'])
|
||||
self._messages.scrollToBottom()
|
||||
|
||||
def set_status_message(self, value):
|
||||
@ -117,7 +141,7 @@ class Profile(contact.Contact, Singleton):
|
||||
"""
|
||||
filter_str = filter_str.lower()
|
||||
settings = Settings.get_instance()
|
||||
for index, friend in enumerate(self._friends):
|
||||
for index, friend in enumerate(self._friends_and_gc):
|
||||
friend.visibility = (friend.status is not None or not show_online) and (filter_str in friend.name.lower())
|
||||
friend.visibility = friend.visibility or friend.messages or friend.actions
|
||||
if friend.visibility:
|
||||
@ -136,29 +160,32 @@ class Profile(contact.Contact, Singleton):
|
||||
self.filtration(self._show_online, self._filter_string)
|
||||
|
||||
def get_friend_by_number(self, num):
|
||||
return list(filter(lambda x: x.number == num, self._friends))[0]
|
||||
return list(filter(lambda x: x.number == num and type(x) is Friend, self._friends_and_gc))[0]
|
||||
|
||||
def get_friend(self, num):
|
||||
return self._friends[num]
|
||||
def get_gc_by_number(self, num):
|
||||
return list(filter(lambda x: x.number == num and type(x) is not Friend, self._friends_and_gc))[0]
|
||||
|
||||
def get_friend_or_gc(self, num):
|
||||
return self._friends_and_gc[num]
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Work with active friend
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_active(self):
|
||||
return self._active_friend
|
||||
return self._active_friend_or_gc
|
||||
|
||||
def set_active(self, value=None):
|
||||
"""
|
||||
Change current active friend or update info
|
||||
:param value: number of new active friend in friend's list or None to update active user's data
|
||||
"""
|
||||
if value is None and self._active_friend == -1: # nothing to update
|
||||
if value is None and self._active_friend_or_gc == -1: # nothing to update
|
||||
return
|
||||
if value == -1: # all friends were deleted
|
||||
self._screen.account_name.setText('')
|
||||
self._screen.account_status.setText('')
|
||||
self._active_friend = -1
|
||||
self._active_friend_or_gc = -1
|
||||
self._screen.account_avatar.setHidden(True)
|
||||
self._messages.clear()
|
||||
self._screen.messageEdit.clear()
|
||||
@ -167,26 +194,30 @@ class Profile(contact.Contact, Singleton):
|
||||
self.send_typing(False)
|
||||
self._screen.typing.setVisible(False)
|
||||
if value is not None:
|
||||
if self._active_friend + 1:
|
||||
if self._active_friend_or_gc + 1:
|
||||
try:
|
||||
self._friends[self._active_friend].curr_text = self._screen.messageEdit.toPlainText()
|
||||
self._friends_and_gc[self._active_friend_or_gc].curr_text = self._screen.messageEdit.toPlainText()
|
||||
except:
|
||||
pass
|
||||
self._active_friend = value
|
||||
friend = self._friends[value]
|
||||
self._friends[value].reset_messages()
|
||||
self._screen.messageEdit.setPlainText(friend.curr_text)
|
||||
self._active_friend_or_gc = value
|
||||
friend_or_gc = self._friends_and_gc[value]
|
||||
friend_or_gc.reset_messages()
|
||||
friend_or_gc.delete_old_messages()
|
||||
self._screen.messageEdit.setPlainText(friend_or_gc.curr_text)
|
||||
self._messages.clear()
|
||||
friend.load_corr()
|
||||
messages = friend.get_corr()[-PAGE_SIZE:]
|
||||
friend_or_gc.load_corr()
|
||||
messages = friend_or_gc.get_corr()[-PAGE_SIZE:]
|
||||
self._load_history = False
|
||||
|
||||
for message in messages:
|
||||
if message.get_type() <= 1:
|
||||
data = message.get_data()
|
||||
self.create_message_item(data[0],
|
||||
data[2],
|
||||
data[1],
|
||||
data[3])
|
||||
data[3],
|
||||
True,
|
||||
data[4] if len(data) == 5 else None)
|
||||
elif message.get_type() == MESSAGE_TYPE['FILE_TRANSFER']:
|
||||
if message.get_status() is None:
|
||||
self.create_unsent_file_item(message)
|
||||
@ -216,13 +247,16 @@ class Profile(contact.Contact, Singleton):
|
||||
else:
|
||||
self._screen.call_finished()
|
||||
else:
|
||||
friend = self._friends[self._active_friend]
|
||||
friend_or_gc = self._friends_and_gc[self._active_friend_or_gc]
|
||||
|
||||
self._screen.account_name.setText(friend.name)
|
||||
self._screen.account_status.setText(friend.status_message)
|
||||
avatar_path = (ProfileHelper.get_path() + 'avatars/{}.png').format(friend.tox_id[:TOX_PUBLIC_KEY_SIZE * 2])
|
||||
self._screen.account_name.setText(friend_or_gc.name)
|
||||
self._screen.account_status.setText(friend_or_gc.status_message)
|
||||
avatar_path = (ProfileHelper.get_path() + 'avatars/{}.png').format(friend_or_gc.tox_id[:TOX_PUBLIC_KEY_SIZE * 2])
|
||||
if not os.path.isfile(avatar_path): # load default image
|
||||
avatar_path = curr_directory() + '/images/avatar.png'
|
||||
if type(friend_or_gc) is Friend:
|
||||
avatar_path = curr_directory() + '/images/avatar.png'
|
||||
else:
|
||||
avatar_path = curr_directory() + '/images/group.png'
|
||||
os.chdir(os.path.dirname(avatar_path))
|
||||
pixmap = QtGui.QPixmap(QtCore.QSize(64, 64))
|
||||
pixmap.load(avatar_path)
|
||||
@ -237,17 +271,20 @@ class Profile(contact.Contact, Singleton):
|
||||
|
||||
active_friend = property(get_active, set_active)
|
||||
|
||||
def is_active_a_friend(self):
|
||||
return type(self._friends_and_gc[self._active_friend_or_gc]) is Friend
|
||||
|
||||
def get_last_message(self):
|
||||
return self._friends[self._active_friend].get_last_message_text()
|
||||
return self._friends_and_gc[self._active_friend_or_gc].get_last_message_text()
|
||||
|
||||
def get_active_number(self):
|
||||
return self._friends[self._active_friend].number if self._active_friend + 1 else -1
|
||||
return self._friends_and_gc[self._active_friend_or_gc].number if self._active_friend_or_gc + 1 else -1
|
||||
|
||||
def get_active_name(self):
|
||||
return self._friends[self._active_friend].name if self._active_friend + 1 else ''
|
||||
return self._friends_and_gc[self._active_friend_or_gc].name if self._active_friend_or_gc + 1 else ''
|
||||
|
||||
def is_active_online(self):
|
||||
return self._active_friend + 1 and self._friends[self._active_friend].status is not None
|
||||
return self._active_friend_or_gc + 1 and self._friends_and_gc[self._active_friend_or_gc].status is not None
|
||||
|
||||
def new_name(self, number, name):
|
||||
friend = self.get_friend_by_number(number)
|
||||
@ -265,8 +302,8 @@ class Profile(contact.Contact, Singleton):
|
||||
self.set_active(None)
|
||||
|
||||
def update(self):
|
||||
if self._active_friend + 1:
|
||||
self.set_active(self._active_friend)
|
||||
if self._active_friend_or_gc + 1:
|
||||
self.set_active(self._active_friend_or_gc)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Friend connection status callbacks
|
||||
@ -306,8 +343,8 @@ class Profile(contact.Contact, Singleton):
|
||||
"""
|
||||
Send typing notification to a friend
|
||||
"""
|
||||
if Settings.get_instance()['typing_notifications'] and self._active_friend + 1:
|
||||
friend = self._friends[self._active_friend]
|
||||
if Settings.get_instance()['typing_notifications'] and self._active_friend_or_gc + 1:
|
||||
friend = self._friends_and_gc[self._active_friend_or_gc]
|
||||
if friend.status is not None:
|
||||
self._tox.self_set_typing(friend.number, typing)
|
||||
|
||||
@ -341,12 +378,13 @@ class Profile(contact.Contact, Singleton):
|
||||
except:
|
||||
pass
|
||||
|
||||
def split_and_send(self, number, message_type, message):
|
||||
def split_and_send(self, number, message_type, message, is_group=False):
|
||||
"""
|
||||
Message splitting
|
||||
:param number: friend's number
|
||||
:param number: friend or gc number
|
||||
:param message_type: type of message
|
||||
:param message: message text
|
||||
:param is_group: send to group
|
||||
"""
|
||||
while len(message) > TOX_MAX_MESSAGE_LENGTH:
|
||||
size = TOX_MAX_MESSAGE_LENGTH * 4 / 5
|
||||
@ -360,62 +398,95 @@ class Profile(contact.Contact, Singleton):
|
||||
else:
|
||||
index = TOX_MAX_MESSAGE_LENGTH - size - 1
|
||||
index += size + 1
|
||||
self._tox.friend_send_message(number, message_type, message[:index])
|
||||
if not is_group:
|
||||
self._tox.friend_send_message(number, message_type, message[:index])
|
||||
else:
|
||||
self._tox.group_send_message(number, message_type, message[:index])
|
||||
message = message[index:]
|
||||
self._tox.friend_send_message(number, message_type, message)
|
||||
if not is_group:
|
||||
self._tox.friend_send_message(number, message_type, message)
|
||||
else:
|
||||
self._tox.group_send_message(number, message_type, message)
|
||||
|
||||
def new_message(self, friend_num, message_type, message):
|
||||
def new_message(self, num, message_type, message, is_group=False, peer_id=-1):
|
||||
"""
|
||||
Current user gets new message
|
||||
:param friend_num: friend_num of friend who sent message
|
||||
:param num: num of friend or gc who sent message
|
||||
:param message_type: message type - plain text or action message (/me)
|
||||
:param message: text of message
|
||||
:param is_group: is group chat message or not
|
||||
:param peer_id: if gc - peer id
|
||||
"""
|
||||
if friend_num == self.get_active_number(): # add message to list
|
||||
t = time.time()
|
||||
self.create_message_item(message, t, MESSAGE_OWNER['FRIEND'], message_type)
|
||||
t = time.time()
|
||||
active = False
|
||||
if num == self.get_active_number() and is_group != self.is_active_a_friend(): # add message to list
|
||||
if not is_group:
|
||||
self.create_message_item(message, t, MESSAGE_OWNER['FRIEND'], message_type)
|
||||
else:
|
||||
self.create_message_item(message, t, MESSAGE_OWNER['FRIEND'], message_type, True,
|
||||
self._tox.group_peer_get_name(num, peer_id))
|
||||
self._messages.scrollToBottom()
|
||||
self._friends[self._active_friend].append_message(
|
||||
TextMessage(message, MESSAGE_OWNER['FRIEND'], t, message_type))
|
||||
active = True
|
||||
if is_group:
|
||||
friend_or_gc = self.get_gc_by_number(num)
|
||||
friend_or_gc.append_message(GroupChatTextMessage(self._tox.group_peer_get_name(num, peer_id),
|
||||
message, MESSAGE_OWNER['FRIEND'],
|
||||
time.time(), message_type))
|
||||
else:
|
||||
friend = self.get_friend_by_number(friend_num)
|
||||
friend.inc_messages()
|
||||
friend.append_message(
|
||||
TextMessage(message, MESSAGE_OWNER['FRIEND'], time.time(), message_type))
|
||||
if not friend.visibility:
|
||||
self.update_filtration()
|
||||
friend_or_gc = self.get_friend_by_number(num)
|
||||
friend_or_gc.append_message(TextMessage(message, MESSAGE_OWNER['FRIEND'], time.time(), message_type))
|
||||
if not active:
|
||||
friend_or_gc.inc_messages()
|
||||
if not friend_or_gc.visibility:
|
||||
self.update_filtration()
|
||||
|
||||
def send_message(self, text, friend_num=None):
|
||||
def send_message(self, text, number=None, is_gc=False):
|
||||
"""
|
||||
Send message
|
||||
:param text: message text
|
||||
:param friend_num: num of friend
|
||||
:param number: num of friend or gc
|
||||
:param is_gc: is group chat
|
||||
"""
|
||||
if friend_num is None:
|
||||
friend_num = self.get_active_number()
|
||||
if number is None:
|
||||
number = self.get_active_number()
|
||||
is_gc = not self.is_active_a_friend()
|
||||
if text.startswith('/plugin '):
|
||||
plugin_support.PluginLoader.get_instance().command(text[8:])
|
||||
self._screen.messageEdit.clear()
|
||||
elif text and friend_num + 1:
|
||||
elif text and number + 1:
|
||||
text = ''.join(c if c <= '\u10FFFF' else '\u25AF' for c in text)
|
||||
|
||||
if text.startswith('/me '):
|
||||
message_type = TOX_MESSAGE_TYPE['ACTION']
|
||||
text = text[4:]
|
||||
else:
|
||||
message_type = TOX_MESSAGE_TYPE['NORMAL']
|
||||
friend = self.get_friend_by_number(friend_num)
|
||||
friend.inc_receipts()
|
||||
if friend.status is not None:
|
||||
self.split_and_send(friend.number, message_type, text.encode('utf-8'))
|
||||
if friend.number == self.get_active_number():
|
||||
t = time.time()
|
||||
self.create_message_item(text, t, MESSAGE_OWNER['NOT_SENT'], message_type)
|
||||
self._screen.messageEdit.clear()
|
||||
self._messages.scrollToBottom()
|
||||
friend.append_message(TextMessage(text, MESSAGE_OWNER['NOT_SENT'], t, message_type))
|
||||
|
||||
if not is_gc:
|
||||
friend_or_gc = self.get_friend_by_number(number)
|
||||
else:
|
||||
friend_or_gc = self.get_gc_by_number(number)
|
||||
t = time.time()
|
||||
|
||||
if not is_gc:
|
||||
friend_or_gc.inc_receipts()
|
||||
if friend_or_gc.status is not None:
|
||||
self.split_and_send(friend_or_gc.number, message_type, text.encode('utf-8'))
|
||||
if friend_or_gc.number == self.get_active_number() and self.is_active_a_friend():
|
||||
self.create_message_item(text, t, MESSAGE_OWNER['NOT_SENT'], message_type)
|
||||
self._screen.messageEdit.clear()
|
||||
self._messages.scrollToBottom()
|
||||
friend_or_gc.append_message(TextMessage(text, MESSAGE_OWNER['NOT_SENT'], t, message_type))
|
||||
else:
|
||||
self.split_and_send(friend_or_gc.number, message_type, text.encode('utf-8'), True)
|
||||
if friend_or_gc.number == self.get_active_number() and not self.is_active_a_friend():
|
||||
self.create_message_item(text, t, MESSAGE_OWNER['ME'], message_type)
|
||||
self._screen.messageEdit.clear()
|
||||
self._messages.scrollToBottom()
|
||||
friend_or_gc.append_message(TextMessage(text, MESSAGE_OWNER['ME'], t, message_type))
|
||||
|
||||
def delete_message(self, time):
|
||||
friend = self._friends[self._active_friend]
|
||||
friend = self._friends_and_gc[self._active_friend_or_gc]
|
||||
friend.delete_message(time)
|
||||
self._history.delete_message(friend.tox_id, time)
|
||||
self.update()
|
||||
@ -429,20 +500,21 @@ class Profile(contact.Contact, Singleton):
|
||||
Save history to db
|
||||
"""
|
||||
s = Settings.get_instance()
|
||||
# TODO: different saving for friends and gc
|
||||
if hasattr(self, '_history'):
|
||||
if s['save_history']:
|
||||
for friend in self._friends:
|
||||
if not self._history.friend_exists_in_db(friend.tox_id):
|
||||
self._history.add_friend_to_db(friend.tox_id)
|
||||
for friend_or_gc in self._friends_and_gc:
|
||||
if not self._history.friend_exists_in_db(friend_or_gc.tox_id):
|
||||
self._history.add_friend_to_db(friend_or_gc.tox_id)
|
||||
if not s['save_unsent_only']:
|
||||
messages = friend.get_corr_for_saving()
|
||||
messages = friend_or_gc.get_corr_for_saving()
|
||||
else:
|
||||
messages = friend.get_unsent_messages_for_saving()
|
||||
self._history.delete_messages(friend.tox_id)
|
||||
self._history.save_messages_to_db(friend.tox_id, messages)
|
||||
unsent_messages = friend.get_unsent_messages()
|
||||
messages = friend_or_gc.get_unsent_messages_for_saving()
|
||||
self._history.delete_messages(friend_or_gc.tox_id)
|
||||
self._history.save_messages_to_db(friend_or_gc.tox_id, messages)
|
||||
unsent_messages = friend_or_gc.get_unsent_messages()
|
||||
unsent_time = unsent_messages[0].get_data()[2] if len(unsent_messages) else time.time() + 1
|
||||
self._history.update_messages(friend.tox_id, unsent_time)
|
||||
self._history.update_messages(friend_or_gc.tox_id, unsent_time)
|
||||
self._history.save()
|
||||
del self._history
|
||||
|
||||
@ -451,14 +523,15 @@ class Profile(contact.Contact, Singleton):
|
||||
Clear chat history
|
||||
"""
|
||||
if num is not None:
|
||||
friend = self._friends[num]
|
||||
friend = self._friends_and_gc[num]
|
||||
friend.clear_corr(save_unsent)
|
||||
if self._history.friend_exists_in_db(friend.tox_id):
|
||||
self._history.delete_messages(friend.tox_id)
|
||||
self._history.delete_friend_from_db(friend.tox_id)
|
||||
else: # clear all history
|
||||
for number in range(len(self._friends)):
|
||||
for number in range(len(self._friends_and_gc)):
|
||||
self.clear_history(number, save_unsent)
|
||||
|
||||
if num is None or num == self.get_active_number():
|
||||
self.update()
|
||||
|
||||
@ -469,9 +542,10 @@ class Profile(contact.Contact, Singleton):
|
||||
if not self._load_history:
|
||||
return
|
||||
self._load_history = False
|
||||
friend = self._friends[self._active_friend]
|
||||
friend.load_corr(False)
|
||||
data = friend.get_corr()
|
||||
friend_or_gc = self._friends_and_gc[self._active_friend_or_gc]
|
||||
|
||||
friend_or_gc.load_corr(False)
|
||||
data = friend_or_gc.get_corr()
|
||||
if not data:
|
||||
return
|
||||
data.reverse()
|
||||
@ -525,11 +599,11 @@ class Profile(contact.Contact, Singleton):
|
||||
self._screen.friends_list.setItemWidget(elem, item)
|
||||
return item
|
||||
|
||||
def create_message_item(self, text, time, owner, message_type, append=True):
|
||||
def create_message_item(self, text, time, owner, message_type, append=True, friend_name=None):
|
||||
if message_type == MESSAGE_TYPE['INFO_MESSAGE']:
|
||||
name = ''
|
||||
elif owner == MESSAGE_OWNER['FRIEND']:
|
||||
name = self.get_active_name()
|
||||
name = friend_name or self.get_active_name()
|
||||
else:
|
||||
name = self._name
|
||||
item = MessageItem(text, time, name, owner != MESSAGE_OWNER['NOT_SENT'], message_type, self._messages)
|
||||
@ -588,7 +662,7 @@ class Profile(contact.Contact, Singleton):
|
||||
"""
|
||||
Set new alias for friend
|
||||
"""
|
||||
friend = self._friends[num]
|
||||
friend = self._friends_and_gc[num]
|
||||
name = friend.name
|
||||
dialog = QtGui.QApplication.translate('MainWindow',
|
||||
"Enter new alias for friend {} or leave empty to use friend's name:",
|
||||
@ -626,14 +700,16 @@ class Profile(contact.Contact, Singleton):
|
||||
self.update()
|
||||
|
||||
def friend_public_key(self, num):
|
||||
return self._friends[num].tox_id
|
||||
return self._friends_and_gc[num].tox_id
|
||||
|
||||
def delete_friend(self, num):
|
||||
def delete_friend_or_gc(self, num, is_gc=False, message=None):
|
||||
"""
|
||||
Removes friend from contact list
|
||||
:param num: number of friend in list
|
||||
Removes friend or gc from contact list
|
||||
:param num: number of friend or gc in list
|
||||
:param is_gc: is a group chat
|
||||
:param message: message in gc
|
||||
"""
|
||||
friend = self._friends[num]
|
||||
friend = self._friends_and_gc[num]
|
||||
settings = Settings.get_instance()
|
||||
try:
|
||||
index = list(map(lambda x: x[0], settings['friends_aliases'])).index(friend.tox_id)
|
||||
@ -646,11 +722,14 @@ class Profile(contact.Contact, Singleton):
|
||||
self.clear_history(num)
|
||||
if self._history.friend_exists_in_db(friend.tox_id):
|
||||
self._history.delete_friend_from_db(friend.tox_id)
|
||||
self._tox.friend_delete(friend.number)
|
||||
del self._friends[num]
|
||||
if not is_gc:
|
||||
self._tox.friend_delete(friend.number)
|
||||
else:
|
||||
self._tox.group_leave(friend.number, message.encode('utf-8') if message is not None else None)
|
||||
del self._friends_and_gc[num]
|
||||
self._screen.friends_list.takeItem(num)
|
||||
if num == self._active_friend: # active friend was deleted
|
||||
if not len(self._friends): # last friend was deleted
|
||||
if num == self._active_friend_or_gc: # active friend or gc was deleted
|
||||
if not len(self._friends_and_gc): # last contact was deleted
|
||||
self.set_active(-1)
|
||||
else:
|
||||
self.set_active(0)
|
||||
@ -671,7 +750,7 @@ class Profile(contact.Contact, Singleton):
|
||||
log('Accept friend request failed! ' + str(ex))
|
||||
message_getter = None
|
||||
friend = Friend(message_getter, num, tox_id, '', item, tox_id)
|
||||
self._friends.append(friend)
|
||||
self._friends_and_gc.append(friend)
|
||||
|
||||
def block_user(self, tox_id):
|
||||
"""
|
||||
@ -686,7 +765,7 @@ class Profile(contact.Contact, Singleton):
|
||||
settings.save()
|
||||
try:
|
||||
num = self._tox.friend_by_public_key(tox_id)
|
||||
self.delete_friend(num)
|
||||
self.delete_friend_or_gc(num)
|
||||
data = self._tox.get_savedata()
|
||||
ProfileHelper.get_instance().save_profile(data)
|
||||
except: # not in friend list
|
||||
@ -738,7 +817,7 @@ class Profile(contact.Contact, Singleton):
|
||||
self._history.add_friend_to_db(tox_id)
|
||||
message_getter = self._history.messages_getter(tox_id)
|
||||
friend = Friend(message_getter, result, tox_id, '', item, tox_id)
|
||||
self._friends.append(friend)
|
||||
self._friends_and_gc.append(friend)
|
||||
data = self._tox.get_savedata()
|
||||
ProfileHelper.get_instance().save_profile(data)
|
||||
return True
|
||||
@ -781,7 +860,7 @@ class Profile(contact.Contact, Singleton):
|
||||
del self._tox
|
||||
self._tox = restart()
|
||||
self.status = None
|
||||
for friend in self._friends:
|
||||
for friend in self._friends_and_gc:
|
||||
friend.status = None
|
||||
self.update_filtration()
|
||||
|
||||
@ -789,8 +868,8 @@ class Profile(contact.Contact, Singleton):
|
||||
if hasattr(self, '_call'):
|
||||
self._call.stop()
|
||||
del self._call
|
||||
for i in range(len(self._friends)):
|
||||
del self._friends[0]
|
||||
for i in range(len(self._friends_and_gc)):
|
||||
del self._friends_and_gc[0]
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# File transfers support
|
||||
@ -874,7 +953,7 @@ class Profile(contact.Contact, Singleton):
|
||||
0, -1)
|
||||
|
||||
def cancel_not_started_transfer(self, time):
|
||||
self._friends[self._active_friend].delete_one_unsent_file(time)
|
||||
self._friends_and_gc[self._active_friend_or_gc].delete_one_unsent_file(time)
|
||||
self.update()
|
||||
|
||||
def pause_transfer(self, friend_number, file_number, by_friend=False):
|
||||
@ -997,7 +1076,7 @@ class Profile(contact.Contact, Singleton):
|
||||
st.get_file_number())
|
||||
item = self.create_file_transfer_item(tm)
|
||||
st.set_state_changed_handler(item.update)
|
||||
self._friends[self._active_friend].append_message(tm)
|
||||
self._friends_and_gc[self._active_friend_or_gc].append_message(tm)
|
||||
self._messages.scrollToBottom()
|
||||
|
||||
def incoming_chunk(self, friend_number, file_number, position, data):
|
||||
@ -1090,12 +1169,12 @@ class Profile(contact.Contact, Singleton):
|
||||
|
||||
def reset_avatar(self):
|
||||
super(Profile, self).reset_avatar()
|
||||
for friend in filter(lambda x: x.status is not None, self._friends):
|
||||
for friend in filter(lambda x: x.status is not None, self._friends_and_gc):
|
||||
self.send_avatar(friend.number)
|
||||
|
||||
def set_avatar(self, data):
|
||||
super(Profile, self).set_avatar(data)
|
||||
for friend in filter(lambda x: x.status is not None, self._friends):
|
||||
for friend in filter(lambda x: x.status is not None, self._friends_and_gc):
|
||||
self.send_avatar(friend.number)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
@ -1109,6 +1188,8 @@ class Profile(contact.Contact, Singleton):
|
||||
|
||||
def call_click(self, audio=True, video=False):
|
||||
"""User clicked audio button in main window"""
|
||||
if not self.is_active_a_friend():
|
||||
return
|
||||
num = self.get_active_number()
|
||||
if num not in self._call and self.is_active_online(): # start call
|
||||
self._call(num, audio, video)
|
||||
@ -1119,7 +1200,8 @@ class Profile(contact.Contact, Singleton):
|
||||
else:
|
||||
text = QtGui.QApplication.translate("incoming_call", "Outgoing audio call", None,
|
||||
QtGui.QApplication.UnicodeUTF8)
|
||||
self._friends[self._active_friend].append_message(InfoMessage(text, time.time()))
|
||||
|
||||
self._friends_and_gc[self._active_friend_or_gc].append_message(InfoMessage(text, time.time()))
|
||||
self.create_message_item(text, time.time(), '', MESSAGE_TYPE['INFO_MESSAGE'])
|
||||
self._messages.scrollToBottom()
|
||||
elif num in self._call: # finish or cancel call if you call with active friend
|
||||
@ -1177,6 +1259,74 @@ class Profile(contact.Contact, Singleton):
|
||||
self.create_message_item(text, time.time(), '', MESSAGE_TYPE['INFO_MESSAGE'])
|
||||
self._messages.scrollToBottom()
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Group chats support
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_all_gc(self):
|
||||
return list(filter(lambda x: type(x) is GroupChat, self._friends_and_gc))
|
||||
|
||||
def add_gc(self, num):
|
||||
try:
|
||||
tox_id = self._tox.group_get_chat_id(num)
|
||||
name = self._tox.group_get_name(num)
|
||||
topic = self._tox.group_get_topic(num)
|
||||
except:
|
||||
tox_id = name = topic = ''
|
||||
item = self.create_friend_item()
|
||||
try:
|
||||
if not self._history.friend_exists_in_db(tox_id):
|
||||
self._history.add_friend_to_db(tox_id)
|
||||
message_getter = self._history.messages_getter(tox_id)
|
||||
except Exception as ex: # something is wrong
|
||||
log('Accept friend request failed! ' + str(ex))
|
||||
message_getter = None
|
||||
gc = GroupChat(self._tox, num, message_getter, name, topic, item, tox_id)
|
||||
self._friends_and_gc.append(gc)
|
||||
|
||||
def join_gc(self, chat_id, password):
|
||||
num = self._tox.group_join(chat_id, password if password else None)
|
||||
if num != 2 ** 32 - 1:
|
||||
self.add_gc(num)
|
||||
else:
|
||||
pass # TODO: join failed, show error
|
||||
|
||||
def create_gc(self, name, is_public, password):
|
||||
privacy_state = TOX_GROUP_PRIVACY_STATE['TOX_GROUP_PRIVACY_STATE_PUBLIC'] if is_public else TOX_GROUP_PRIVACY_STATE['TOX_GROUP_PRIVACY_STATE_PRIVATE']
|
||||
num = self._tox.group_new(privacy_state, bytes(name, 'utf-8'))
|
||||
if password:
|
||||
self._tox.group_founder_set_password(num, bytes(password, 'utf-8'))
|
||||
self.add_gc(num)
|
||||
self.get_gc_by_number(num).set_status(TOX_USER_STATUS['NONE'])
|
||||
|
||||
def process_group_invite(self, friend_num, data):
|
||||
# TODO: support password
|
||||
try:
|
||||
text = QtGui.QApplication.translate('MainWindow', 'User {} invites you to group',
|
||||
None, QtGui.QApplication.UnicodeUTF8)
|
||||
info = text.format(self.get_friend_by_number(friend_num).name)
|
||||
fr_req = QtGui.QApplication.translate('MainWindow', 'Group chat invite', None, QtGui.QApplication.UnicodeUTF8)
|
||||
reply = QtGui.QMessageBox.question(None, fr_req, info, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
||||
if reply == QtGui.QMessageBox.Yes: # accepted
|
||||
num = self._tox.group_invite_accept(data, friend_num)
|
||||
data = self._tox.get_savedata()
|
||||
ProfileHelper.get_instance().save_profile(data)
|
||||
print('In gc invite', num)
|
||||
self.add_gc(num)
|
||||
elif reply != QtGui.QMessageBox.No:
|
||||
if friend_num in self._gc_invites:
|
||||
self._gc_invites[friend_num].append(data)
|
||||
else:
|
||||
self._gc_invites[friend_num] = data
|
||||
except Exception as ex: # something is wrong
|
||||
log('Accept group chat invite failed! ' + str(ex))
|
||||
|
||||
def invite_friend(self, group_number, friend_number):
|
||||
self._tox.group_invite_friend(group_number, friend_number)
|
||||
|
||||
def leave_group(self, num, message=None):
|
||||
self.delete_friend_or_gc(num, True, message)
|
||||
|
||||
|
||||
def tox_factory(data=None, settings=None):
|
||||
"""
|
||||
|
@ -126,7 +126,8 @@ class Settings(dict, Singleton):
|
||||
'unread_color': 'red',
|
||||
'save_unsent_only': False,
|
||||
'compact_mode': False,
|
||||
'show_welcome_screen': True
|
||||
'show_welcome_screen': True,
|
||||
'notify_all_gc': False
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
948
toxygen/tox.py
948
toxygen/tox.py
@ -92,6 +92,22 @@ class Tox:
|
||||
self.file_recv_chunk_cb = None
|
||||
self.friend_lossy_packet_cb = None
|
||||
self.friend_lossless_packet_cb = None
|
||||
self.group_moderation_cb = None
|
||||
self.group_join_fail_cb = None
|
||||
self.group_self_join_cb = None
|
||||
self.group_invite_cb = None
|
||||
self.group_custom_packet_cb = None
|
||||
self.group_private_message_cb = None
|
||||
self.group_private_message_cb = None
|
||||
self.group_message_cb = None
|
||||
self.group_password_cb = None
|
||||
self.group_peer_limit_cb = None
|
||||
self.group_privacy_state_cb = None
|
||||
self.group_topic_cb = None
|
||||
self.group_peer_status_cb = None
|
||||
self.group_peer_name_cb = None
|
||||
self.group_peer_exit_cb = None
|
||||
self.group_peer_join_cb = None
|
||||
|
||||
self.AV = ToxAV(self._tox_pointer)
|
||||
|
||||
@ -1510,3 +1526,935 @@ class Tox:
|
||||
return result
|
||||
elif tox_err_get_port == TOX_ERR_GET_PORT['NOT_BOUND']:
|
||||
raise RuntimeError('The instance was not bound to any port.')
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Group chat instance management
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def group_new(self, privacy_state, group_name):
|
||||
"""
|
||||
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
|
||||
|
||||
def group_join(self, chat_id, password):
|
||||
"""
|
||||
Joins a group chat with specified Chat ID.
|
||||
|
||||
This function creates a new group chat object, adds it to the chats array, and sends
|
||||
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.
|
||||
"""
|
||||
|
||||
error = c_int()
|
||||
result = Tox.libtoxcore.tox_group_join(self._tox_pointer, string_to_bin(chat_id),
|
||||
password,
|
||||
len(password) if password is not None else 0,
|
||||
byref(error))
|
||||
return result
|
||||
|
||||
def group_reconnect(self, groupnumber):
|
||||
"""
|
||||
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
|
||||
|
||||
def group_leave(self, groupnumber, message):
|
||||
"""
|
||||
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
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
# Group user-visible client information (nickname/status/role/public key)
|
||||
# -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
|
||||
def group_self_get_name_size(self, groupnumber):
|
||||
"""
|
||||
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
|
||||
|
||||
def group_self_get_name(self, groupnumber):
|
||||
"""
|
||||
Write the nickname set by tox_group_self_set_name to a byte array.
|
||||
|
||||
If no nickname was set before calling this function, the name is empty,
|
||||
and this function has no effect.
|
||||
|
||||
Call tox_group_self_get_name_size to find out how much memory to allocate for the result.
|
||||
:return nickname
|
||||
"""
|
||||
|
||||
error = c_int()
|
||||
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
|
||||
|
||||
def group_self_get_status(self, groupnumber):
|
||||
"""
|
||||
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
|
||||
|
||||
def group_self_get_role(self, groupnumber):
|
||||
"""
|
||||
returns the client's role for the group instance on success.
|
||||
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
|
||||
|
||||
def group_self_get_peer_id(self, groupnumber):
|
||||
"""
|
||||
returns the client's peer id for the group instance on success.
|
||||
return value is unspecified on failure.
|
||||
"""
|
||||
|
||||
error = c_int()
|
||||
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)
|
||||
Tox.libtoxcore.tox_callback_group_message(self._tox_pointer, self.group_message_cb, user_data)
|
||||
|
||||
def callback_group_private_message(self, callback, user_data):
|
||||
"""
|
||||
Set the callback for the `group_private_message` event. Pass NULL to unset.
|
||||
This event is triggered when the client receives a private message.
|
||||
"""
|
||||
|
||||
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_char_p, c_size_t, c_void_p)
|
||||
self.group_private_message_cb = c_callback(callback)
|
||||
Tox.libtoxcore.tox_callback_group_private_message(self._tox_pointer, self.group_private_message_cb, user_data)
|
||||
|
||||
def callback_group_custom_packet(self, callback, user_data):
|
||||
"""
|
||||
Set the callback for the `group_custom_packet` event. Pass NULL to unset.
|
||||
|
||||
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
|
||||
|
@ -188,6 +188,729 @@ TOX_ERR_GET_PORT = {
|
||||
'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
|
||||
@ -196,6 +919,18 @@ 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
|
||||
|
Loading…
Reference in New Issue
Block a user