2018-01-26 20:21:46 +00:00
|
|
|
from contacts.friend import *
|
|
|
|
from user_data.settings import *
|
|
|
|
from wrapper.toxcore_enums_and_consts import *
|
2018-04-29 21:33:25 +00:00
|
|
|
from util.util import log
|
2018-04-15 21:11:51 +00:00
|
|
|
from history.database import *
|
2018-03-10 15:42:53 +00:00
|
|
|
from file_transfers.file_transfers import *
|
2016-03-12 20:18:13 +00:00
|
|
|
import time
|
2018-01-26 20:21:46 +00:00
|
|
|
from contacts import basecontact
|
|
|
|
from contacts.group_chat import *
|
2018-04-28 21:52:42 +00:00
|
|
|
import util.ui as util_ui
|
2016-02-18 16:15:38 +00:00
|
|
|
|
|
|
|
|
2018-04-15 21:11:51 +00:00
|
|
|
class Profile(basecontact.BaseContact):
|
2016-02-26 14:32:36 +00:00
|
|
|
"""
|
2016-03-09 19:46:00 +00:00
|
|
|
Profile of current toxygen user. Contains friends list, tox instance
|
2016-02-26 14:32:36 +00:00
|
|
|
"""
|
2018-04-19 17:05:14 +00:00
|
|
|
def __init__(self, profile_manager, tox, screen, file_transfer_handler):
|
2016-03-07 18:00:00 +00:00
|
|
|
"""
|
|
|
|
:param tox: tox instance
|
2016-03-09 18:11:36 +00:00
|
|
|
:param screen: ref to main screen
|
2016-03-07 18:00:00 +00:00
|
|
|
"""
|
2016-10-22 18:23:03 +00:00
|
|
|
basecontact.BaseContact.__init__(self,
|
2018-04-18 20:55:51 +00:00
|
|
|
profile_manager,
|
2016-10-22 18:23:03 +00:00
|
|
|
tox.self_get_name(),
|
|
|
|
tox.self_get_status_message(),
|
|
|
|
screen.user_info,
|
|
|
|
tox.self_get_address())
|
2018-04-19 17:05:14 +00:00
|
|
|
self._file_transfer_handler = file_transfer_handler
|
2016-03-16 08:01:23 +00:00
|
|
|
self._screen = screen
|
2016-03-09 18:11:36 +00:00
|
|
|
self._messages = screen.messages
|
2016-03-16 08:01:23 +00:00
|
|
|
self._tox = tox
|
2016-03-18 13:50:32 +00:00
|
|
|
self._file_transfers = {} # dict of file transfers. key - tuple (friend_number, file_number)
|
2016-07-02 14:34:14 +00:00
|
|
|
self._load_history = True
|
2017-03-03 19:09:45 +00:00
|
|
|
self._waiting_for_reconnection = False
|
2018-04-26 20:54:39 +00:00
|
|
|
#self._factory = items_factory.ItemsFactory(self._screen.friends_list, self._messages)
|
|
|
|
self._contacts_manager = None
|
2018-04-16 20:35:55 +00:00
|
|
|
#self._show_avatars = settings['show_avatars']
|
2018-03-10 15:42:53 +00:00
|
|
|
|
2016-03-04 19:03:20 +00:00
|
|
|
# -----------------------------------------------------------------------------------------------------------------
|
|
|
|
# Edit current user's data
|
|
|
|
# -----------------------------------------------------------------------------------------------------------------
|
|
|
|
|
2016-02-28 21:33:35 +00:00
|
|
|
def change_status(self):
|
2016-03-09 19:46:00 +00:00
|
|
|
"""
|
|
|
|
Changes status of user (online, away, busy)
|
|
|
|
"""
|
2016-02-28 21:33:35 +00:00
|
|
|
if self._status is not None:
|
2016-05-24 18:08:52 +00:00
|
|
|
self.set_status((self._status + 1) % 3)
|
|
|
|
|
|
|
|
def set_status(self, status):
|
2016-06-25 12:40:01 +00:00
|
|
|
super(Profile, self).set_status(status)
|
|
|
|
if status is not None:
|
2016-05-30 18:38:21 +00:00
|
|
|
self._tox.self_set_status(status)
|
2017-03-08 10:19:41 +00:00
|
|
|
elif not self._waiting_for_reconnection:
|
2017-04-22 19:35:32 +00:00
|
|
|
self._waiting_for_reconnection = True
|
2017-03-03 19:09:45 +00:00
|
|
|
QtCore.QTimer.singleShot(50000, self.reconnect)
|
2016-02-29 16:39:43 +00:00
|
|
|
|
|
|
|
def set_name(self, value):
|
2016-06-23 19:50:17 +00:00
|
|
|
if self.name == value:
|
|
|
|
return
|
2016-06-24 12:00:13 +00:00
|
|
|
tmp = self.name
|
|
|
|
super(Profile, self).set_name(value.encode('utf-8'))
|
2016-03-16 08:01:23 +00:00
|
|
|
self._tox.self_set_name(self._name.encode('utf-8'))
|
2018-04-28 21:52:42 +00:00
|
|
|
message = util_ui.tr('User {} is now known as {}')
|
2016-06-24 12:00:13 +00:00
|
|
|
message = message.format(tmp, value)
|
2016-10-22 18:23:03 +00:00
|
|
|
for friend in self._contacts:
|
2016-06-23 19:50:17 +00:00
|
|
|
friend.append_message(InfoMessage(message, time.time()))
|
|
|
|
if self._active_friend + 1:
|
2016-06-28 09:44:27 +00:00
|
|
|
self.create_message_item(message, time.time(), '', MESSAGE_TYPE['INFO_MESSAGE'])
|
2016-06-23 19:50:17 +00:00
|
|
|
self._messages.scrollToBottom()
|
2016-02-29 16:39:43 +00:00
|
|
|
|
|
|
|
def set_status_message(self, value):
|
2018-04-26 20:54:39 +00:00
|
|
|
super().set_status_message(value)
|
2016-03-16 08:01:23 +00:00
|
|
|
self._tox.self_set_status_message(self._status_message.encode('utf-8'))
|
2016-02-28 21:33:35 +00:00
|
|
|
|
2016-05-03 19:02:56 +00:00
|
|
|
def new_nospam(self):
|
2016-06-08 15:35:40 +00:00
|
|
|
"""Sets new nospam part of tox id"""
|
2016-05-03 19:02:56 +00:00
|
|
|
import random
|
|
|
|
self._tox.self_set_nospam(random.randint(0, 4294967295)) # no spam - uint32
|
|
|
|
self._tox_id = self._tox.self_get_address()
|
2018-04-26 20:54:39 +00:00
|
|
|
|
2016-05-03 19:02:56 +00:00
|
|
|
return self._tox_id
|
|
|
|
|
2016-06-07 09:27:58 +00:00
|
|
|
# -----------------------------------------------------------------------------------------------------------------
|
|
|
|
# Friend connection status callbacks
|
|
|
|
# -----------------------------------------------------------------------------------------------------------------
|
|
|
|
|
2016-06-15 12:38:42 +00:00
|
|
|
def send_files(self, friend_number):
|
|
|
|
friend = self.get_friend_by_number(friend_number)
|
2017-03-04 19:15:42 +00:00
|
|
|
friend.remove_invalid_unsent_files()
|
2016-06-15 12:38:42 +00:00
|
|
|
files = friend.get_unsent_files()
|
|
|
|
try:
|
|
|
|
for fl in files:
|
|
|
|
data = fl.get_data()
|
|
|
|
if data[1] is not None:
|
|
|
|
self.send_inline(data[1], data[0], friend_number, True)
|
|
|
|
else:
|
|
|
|
self.send_file(data[0], friend_number, True)
|
|
|
|
friend.clear_unsent_files()
|
2016-07-30 18:43:28 +00:00
|
|
|
for key in list(self._paused_file_transfers.keys()):
|
2016-07-30 12:44:45 +00:00
|
|
|
data = self._paused_file_transfers[key]
|
2016-07-30 18:43:28 +00:00
|
|
|
if not os.path.exists(data[0]):
|
|
|
|
del self._paused_file_transfers[key]
|
|
|
|
elif data[1] == friend_number and not data[2]:
|
2016-07-30 12:44:45 +00:00
|
|
|
self.send_file(data[0], friend_number, True, key)
|
|
|
|
del self._paused_file_transfers[key]
|
2017-07-18 18:36:14 +00:00
|
|
|
if friend_number == self.get_active_number() and self.is_active_a_friend():
|
2016-06-15 12:38:42 +00:00
|
|
|
self.update()
|
2016-06-17 21:43:30 +00:00
|
|
|
except Exception as ex:
|
2016-06-21 11:58:11 +00:00
|
|
|
print('Exception in file sending: ' + str(ex))
|
2016-06-04 12:19:15 +00:00
|
|
|
|
2016-05-05 23:00:10 +00:00
|
|
|
def friend_exit(self, friend_number):
|
2016-05-30 19:26:07 +00:00
|
|
|
"""
|
|
|
|
Friend with specified number quit
|
|
|
|
"""
|
2016-05-05 23:00:10 +00:00
|
|
|
self.get_friend_by_number(friend_number).status = None
|
|
|
|
self.friend_typing(friend_number, False)
|
|
|
|
if friend_number in self._call:
|
|
|
|
self._call.finish_call(friend_number, True)
|
2016-07-30 12:44:45 +00:00
|
|
|
for friend_num, file_num in list(self._file_transfers.keys()):
|
|
|
|
if friend_num == friend_number:
|
|
|
|
ft = self._file_transfers[(friend_num, file_num)]
|
|
|
|
if type(ft) is SendTransfer:
|
2016-07-30 18:43:28 +00:00
|
|
|
self._paused_file_transfers[ft.get_id()] = [ft.get_path(), friend_num, False, -1]
|
2016-08-08 19:11:43 +00:00
|
|
|
elif type(ft) is ReceiveTransfer and ft.state != TOX_FILE_TRANSFER_STATE['INCOMING_NOT_STARTED']:
|
2016-07-30 18:43:28 +00:00
|
|
|
self._paused_file_transfers[ft.get_id()] = [ft.get_path(), friend_num, True, ft.total_size()]
|
2016-08-04 09:56:47 +00:00
|
|
|
self.cancel_transfer(friend_num, file_num, True)
|
2016-05-05 23:00:10 +00:00
|
|
|
|
2016-02-28 21:33:35 +00:00
|
|
|
# -----------------------------------------------------------------------------------------------------------------
|
|
|
|
# Private messages
|
|
|
|
# -----------------------------------------------------------------------------------------------------------------
|
2016-02-28 15:25:18 +00:00
|
|
|
|
2016-06-15 21:12:27 +00:00
|
|
|
def receipt(self):
|
|
|
|
i = 0
|
|
|
|
while i < self._messages.count() and not self._messages.itemWidget(self._messages.item(i)).mark_as_sent():
|
|
|
|
i += 1
|
|
|
|
|
2016-06-04 19:17:32 +00:00
|
|
|
def send_messages(self, friend_number):
|
|
|
|
"""
|
|
|
|
Send 'offline' messages to friend
|
|
|
|
"""
|
|
|
|
friend = self.get_friend_by_number(friend_number)
|
|
|
|
friend.load_corr()
|
2016-06-28 09:44:27 +00:00
|
|
|
messages = friend.get_unsent_messages()
|
2016-06-04 19:17:32 +00:00
|
|
|
try:
|
|
|
|
for message in messages:
|
|
|
|
self.split_and_send(friend_number, message.get_data()[-1], message.get_data()[0].encode('utf-8'))
|
2016-06-23 09:21:26 +00:00
|
|
|
friend.inc_receipts()
|
2017-04-05 20:46:32 +00:00
|
|
|
except Exception as ex:
|
|
|
|
log('Sending pending messages failed with ' + str(ex))
|
2016-06-04 19:17:32 +00:00
|
|
|
|
2018-03-10 15:42:53 +00:00
|
|
|
def split_message(self, message):
|
|
|
|
messages = []
|
|
|
|
while len(message) > TOX_MAX_MESSAGE_LENGTH:
|
|
|
|
size = TOX_MAX_MESSAGE_LENGTH * 4 / 5
|
|
|
|
last_part = message[size:TOX_MAX_MESSAGE_LENGTH]
|
|
|
|
if ' ' in last_part:
|
|
|
|
index = last_part.index(' ')
|
|
|
|
elif ',' in last_part:
|
|
|
|
index = last_part.index(',')
|
|
|
|
elif '.' in last_part:
|
|
|
|
index = last_part.index('.')
|
|
|
|
else:
|
|
|
|
index = TOX_MAX_MESSAGE_LENGTH - size - 1
|
|
|
|
index += size + 1
|
|
|
|
messages.append(message[:index])
|
|
|
|
message = message[index:]
|
|
|
|
|
|
|
|
return messages
|
|
|
|
|
2016-03-09 18:11:36 +00:00
|
|
|
def new_message(self, friend_num, message_type, message):
|
2016-03-07 18:00:00 +00:00
|
|
|
"""
|
|
|
|
Current user gets new message
|
2016-03-09 18:11:36 +00:00
|
|
|
:param friend_num: friend_num of friend who sent message
|
2016-03-09 18:45:38 +00:00
|
|
|
:param message_type: message type - plain text or action message (/me)
|
2016-03-07 18:00:00 +00:00
|
|
|
:param message: text of message
|
|
|
|
"""
|
2017-07-18 18:36:14 +00:00
|
|
|
if friend_num == self.get_active_number()and self.is_active_a_friend(): # add message to list
|
2016-06-28 09:44:27 +00:00
|
|
|
t = time.time()
|
|
|
|
self.create_message_item(message, t, MESSAGE_OWNER['FRIEND'], message_type)
|
2016-03-14 19:30:51 +00:00
|
|
|
self._messages.scrollToBottom()
|
2017-02-12 14:58:23 +00:00
|
|
|
self.get_curr_friend().append_message(
|
2016-06-28 09:44:27 +00:00
|
|
|
TextMessage(message, MESSAGE_OWNER['FRIEND'], t, message_type))
|
2016-02-26 18:54:15 +00:00
|
|
|
else:
|
2016-03-28 21:07:42 +00:00
|
|
|
friend = self.get_friend_by_number(friend_num)
|
2016-06-13 16:28:17 +00:00
|
|
|
friend.inc_messages()
|
2016-03-29 12:54:58 +00:00
|
|
|
friend.append_message(
|
2016-06-21 11:58:11 +00:00
|
|
|
TextMessage(message, MESSAGE_OWNER['FRIEND'], time.time(), message_type))
|
2016-05-30 18:38:21 +00:00
|
|
|
if not friend.visibility:
|
|
|
|
self.update_filtration()
|
2016-02-26 18:54:15 +00:00
|
|
|
|
2018-03-11 21:32:46 +00:00
|
|
|
def send_message_to_friend(self, text, friend_number=None):
|
2016-03-07 18:00:00 +00:00
|
|
|
"""
|
2016-07-07 10:54:02 +00:00
|
|
|
Send message
|
2016-03-07 18:00:00 +00:00
|
|
|
:param text: message text
|
2018-03-11 21:32:46 +00:00
|
|
|
:param friend_number: number of friend
|
2016-03-07 18:00:00 +00:00
|
|
|
"""
|
2018-03-11 21:32:46 +00:00
|
|
|
if friend_number is None:
|
|
|
|
friend_number = self.get_active_number()
|
2016-05-28 10:06:13 +00:00
|
|
|
if text.startswith('/plugin '):
|
2018-03-11 21:32:46 +00:00
|
|
|
self._plugin_loader.command(text[8:])
|
2016-05-28 10:06:13 +00:00
|
|
|
self._screen.messageEdit.clear()
|
2018-03-11 21:32:46 +00:00
|
|
|
elif text and friend_number >= 0:
|
2016-03-04 17:52:52 +00:00
|
|
|
if text.startswith('/me '):
|
2016-02-28 15:25:18 +00:00
|
|
|
message_type = TOX_MESSAGE_TYPE['ACTION']
|
2016-03-04 17:52:52 +00:00
|
|
|
text = text[4:]
|
2016-02-28 15:25:18 +00:00
|
|
|
else:
|
|
|
|
message_type = TOX_MESSAGE_TYPE['NORMAL']
|
2018-03-11 21:32:46 +00:00
|
|
|
friend = self.get_friend_by_number(friend_number)
|
2016-06-15 20:27:57 +00:00
|
|
|
friend.inc_receipts()
|
2016-06-04 19:17:32 +00:00
|
|
|
if friend.status is not None:
|
2018-03-11 21:32:46 +00:00
|
|
|
messages = self.split_message(text.encode('utf-8'))
|
|
|
|
for message in messages:
|
|
|
|
self._tox.friend_send_message(friend_number, message_type, message)
|
2017-07-17 18:53:35 +00:00
|
|
|
t = time.time()
|
|
|
|
if friend.number == self.get_active_number() and self.is_active_a_friend():
|
2016-07-07 10:54:02 +00:00
|
|
|
self.create_message_item(text, t, MESSAGE_OWNER['NOT_SENT'], message_type)
|
|
|
|
self._screen.messageEdit.clear()
|
|
|
|
self._messages.scrollToBottom()
|
2016-06-28 09:44:27 +00:00
|
|
|
friend.append_message(TextMessage(text, MESSAGE_OWNER['NOT_SENT'], t, message_type))
|
|
|
|
|
2018-03-11 21:32:46 +00:00
|
|
|
def delete_message(self, message_id):
|
2017-02-12 14:58:23 +00:00
|
|
|
friend = self.get_curr_friend()
|
2016-06-28 09:44:27 +00:00
|
|
|
friend.delete_message(time)
|
2018-03-11 21:32:46 +00:00
|
|
|
self._history.delete_message(friend.tox_id, message_id)
|
2016-06-28 09:44:27 +00:00
|
|
|
self.update()
|
2016-02-27 17:03:33 +00:00
|
|
|
|
2016-02-28 21:33:35 +00:00
|
|
|
# -----------------------------------------------------------------------------------------------------------------
|
2016-10-22 18:55:34 +00:00
|
|
|
# Friend, message and file transfer items creation
|
2016-03-12 20:18:13 +00:00
|
|
|
# -----------------------------------------------------------------------------------------------------------------
|
|
|
|
|
2016-06-15 20:27:57 +00:00
|
|
|
def create_message_item(self, text, time, owner, message_type, append=True):
|
2016-06-17 21:43:30 +00:00
|
|
|
if message_type == MESSAGE_TYPE['INFO_MESSAGE']:
|
|
|
|
name = ''
|
|
|
|
elif owner == MESSAGE_OWNER['FRIEND']:
|
|
|
|
name = self.get_active_name()
|
|
|
|
else:
|
|
|
|
name = self._name
|
2016-10-22 18:55:34 +00:00
|
|
|
pixmap = None
|
2016-07-13 20:09:34 +00:00
|
|
|
if self._show_avatars:
|
2016-10-22 18:55:34 +00:00
|
|
|
if owner == MESSAGE_OWNER['FRIEND']:
|
2017-02-12 14:58:23 +00:00
|
|
|
pixmap = self.get_curr_friend().get_pixmap()
|
2016-10-22 18:55:34 +00:00
|
|
|
else:
|
|
|
|
pixmap = self.get_pixmap()
|
|
|
|
return self._factory.message_item(text, time, name, owner != MESSAGE_OWNER['NOT_SENT'],
|
|
|
|
message_type, append, pixmap)
|
2016-03-13 12:06:06 +00:00
|
|
|
|
2017-07-16 22:11:09 +00:00
|
|
|
def create_gc_message_item(self, text, time, owner, name, message_type, append=True):
|
|
|
|
pixmap = None
|
|
|
|
if self._show_avatars:
|
|
|
|
if owner == MESSAGE_OWNER['FRIEND']:
|
|
|
|
pixmap = self.get_curr_friend().get_pixmap()
|
|
|
|
else:
|
|
|
|
pixmap = self.get_pixmap()
|
|
|
|
return self._factory.message_item(text, time, name, True,
|
2017-07-17 18:53:35 +00:00
|
|
|
message_type - 5, append, pixmap)
|
2017-07-16 22:11:09 +00:00
|
|
|
|
2016-03-29 12:54:58 +00:00
|
|
|
def create_file_transfer_item(self, tm, append=True):
|
|
|
|
data = list(tm.get_data())
|
|
|
|
data[3] = self.get_friend_by_number(data[4]).name if data[3] else self._name
|
2016-10-22 18:55:34 +00:00
|
|
|
return self._factory.file_transfer_item(data, append)
|
2016-03-18 21:28:53 +00:00
|
|
|
|
2016-06-15 12:38:42 +00:00
|
|
|
def create_unsent_file_item(self, message, append=True):
|
|
|
|
data = message.get_data()
|
2016-10-22 18:55:34 +00:00
|
|
|
return self._factory.unsent_file_item(os.path.basename(data[0]),
|
|
|
|
os.path.getsize(data[0]) if data[1] is None else len(data[1]),
|
|
|
|
self.name,
|
|
|
|
data[2],
|
|
|
|
append)
|
2016-06-15 12:38:42 +00:00
|
|
|
|
2016-04-12 13:11:10 +00:00
|
|
|
def create_inline_item(self, data, append=True):
|
2016-10-22 18:55:34 +00:00
|
|
|
return self._factory.inline_item(data, append)
|
2016-04-12 13:11:10 +00:00
|
|
|
|
2016-03-14 19:30:51 +00:00
|
|
|
# -----------------------------------------------------------------------------------------------------------------
|
|
|
|
# Reset
|
|
|
|
# -----------------------------------------------------------------------------------------------------------------
|
|
|
|
|
2016-03-15 17:05:19 +00:00
|
|
|
def reset(self, restart):
|
2016-03-14 19:30:51 +00:00
|
|
|
"""
|
|
|
|
Recreate tox instance
|
2016-03-15 17:05:19 +00:00
|
|
|
:param restart: method which calls restart and returns new tox instance
|
2016-03-14 19:30:51 +00:00
|
|
|
"""
|
2016-10-22 18:23:03 +00:00
|
|
|
for friend in self._contacts:
|
2016-07-30 18:43:28 +00:00
|
|
|
self.friend_exit(friend.number)
|
2016-03-16 08:01:23 +00:00
|
|
|
del self._tox
|
|
|
|
self._tox = restart()
|
2016-03-15 17:05:19 +00:00
|
|
|
self.status = None
|
2018-04-26 20:54:39 +00:00
|
|
|
self._contacts_manager.update_filtration()
|
2016-03-14 19:30:51 +00:00
|
|
|
|
2016-07-19 12:14:30 +00:00
|
|
|
def reconnect(self):
|
2017-03-03 19:09:45 +00:00
|
|
|
self._waiting_for_reconnection = False
|
2016-10-22 18:23:03 +00:00
|
|
|
if self.status is None or all(list(map(lambda x: x.status is None, self._contacts))) and len(self._contacts):
|
2017-03-03 19:09:45 +00:00
|
|
|
self._waiting_for_reconnection = True
|
2016-07-19 12:14:30 +00:00
|
|
|
self.reset(self._screen.reset)
|
2017-03-03 19:09:45 +00:00
|
|
|
QtCore.QTimer.singleShot(50000, self.reconnect)
|
2016-07-19 12:14:30 +00:00
|
|
|
|
2016-04-24 10:45:11 +00:00
|
|
|
def close(self):
|
2017-07-17 19:27:52 +00:00
|
|
|
for friend in filter(lambda x: type(x) is Friend, self._contacts):
|
2016-07-30 19:51:25 +00:00
|
|
|
self.friend_exit(friend.number)
|
2016-10-22 18:23:03 +00:00
|
|
|
for i in range(len(self._contacts)):
|
|
|
|
del self._contacts[0]
|
2016-05-30 18:38:21 +00:00
|
|
|
if hasattr(self, '_call'):
|
2016-05-28 19:43:51 +00:00
|
|
|
self._call.stop()
|
|
|
|
del self._call
|
2016-04-24 10:45:11 +00:00
|
|
|
|
2016-03-18 16:33:54 +00:00
|
|
|
def reset_avatar(self):
|
2018-04-19 17:05:14 +00:00
|
|
|
super().reset_avatar()
|
2016-10-22 18:23:03 +00:00
|
|
|
for friend in filter(lambda x: x.status is not None, self._contacts):
|
2016-03-18 16:33:54 +00:00
|
|
|
self.send_avatar(friend.number)
|
|
|
|
|
|
|
|
def set_avatar(self, data):
|
2018-04-19 17:05:14 +00:00
|
|
|
super().set_avatar(data)
|
2016-10-22 18:23:03 +00:00
|
|
|
for friend in filter(lambda x: x.status is not None, self._contacts):
|
2016-03-18 16:33:54 +00:00
|
|
|
self.send_avatar(friend.number)
|