qTox  Version: nightly | Commit: bc751c8e1cac455f9690654fcfe0f560d2d7dfdd
coreext.cpp
Go to the documentation of this file.
1 /*
2  Copyright © 2019-2020 by The qTox Project Contributors
3 
4  This file is part of qTox, a Qt-based graphical interface for Tox.
5 
6  qTox is libre software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  qTox is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with qTox. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "coreext.h"
21 #include "toxstring.h"
22 
23 #include <QDateTime>
24 #include <QTimeZone>
25 #include <QtCore>
26 
27 #include <memory>
28 #include <cassert>
29 
30 extern "C" {
31 #include <toxext/toxext.h>
32 #include <tox_extension_messages.h>
33 }
34 
35 std::unique_ptr<CoreExt> CoreExt::makeCoreExt(Tox* core) {
36  auto toxExtPtr = toxext_init(core);
37  if (!toxExtPtr) {
38  return nullptr;
39  }
40 
41  auto toxExt = ExtensionPtr<ToxExt>(toxExtPtr, toxext_free);
42  return std::unique_ptr<CoreExt>(new CoreExt(std::move(toxExt)));
43 }
44 
46  : toxExt(std::move(toxExt_))
47  , toxExtMessages(nullptr, nullptr)
48 {
50  tox_extension_messages_register(
51  toxExt.get(),
55  this,
56  TOX_EXTENSION_MESSAGES_DEFAULT_MAX_RECEIVING_MESSAGE_SIZE),
57  tox_extension_messages_free);
58 }
59 
61 {
62  std::lock_guard<std::mutex> lock(toxext_mutex);
63  toxext_iterate(toxExt.get());
64 }
65 
66 void CoreExt::onLosslessPacket(uint32_t friendId, const uint8_t* data, size_t length)
67 {
68  if (is_toxext_packet(data, length)) {
69  std::lock_guard<std::mutex> lock(toxext_mutex);
70  toxext_handle_lossless_custom_packet(toxExt.get(), friendId, data, length);
71  }
72 }
73 
75  ToxExtPacketList* packetList,
76  ToxExtensionMessages* toxExtMessages,
77  uint32_t friendId,
78  std::mutex* toxext_mutex,
80  : toxext_mutex(toxext_mutex)
81  , toxExtMessages(toxExtMessages)
82  , packetList(packetList)
83  , friendId(friendId)
84 {
85  assert(toxext_mutex != nullptr);
86 }
87 
88 std::unique_ptr<ICoreExtPacket> CoreExt::getPacket(uint32_t friendId)
89 {
90  return std::unique_ptr<Packet>(new Packet(
91  toxext_packet_list_create(toxExt.get(), friendId),
92  toxExtMessages.get(),
93  friendId,
94  &toxext_mutex,
95  PacketPassKey{}));
96 }
97 
99 {
100  if (hasBeenSent) {
101  assert(false);
102  qWarning() << "Invalid use of CoreExt::Packet";
103  // Hope that UINT64_MAX will never collide with an actual receipt num
104  // that we care about
105  return UINT64_MAX;
106  }
107 
108  int size = message.toUtf8().size();
109  enum Tox_Extension_Messages_Error err;
110  auto maxSize = static_cast<int>(tox_extension_messages_get_max_sending_size(
112  friendId,
113  &err));
114 
115  if (size > maxSize) {
116  assert(false);
117  qCritical() << "addExtendedMessage called with message of size:" << size
118  << "when max is:" << maxSize << ". Ignoring.";
119  return false;
120  }
121 
122  ToxString toxString(message);
123  const auto receipt = tox_extension_messages_append(
125  packetList,
126  toxString.data(),
127  toxString.size(),
128  friendId,
129  &err);
130 
131  if (err != TOX_EXTENSION_MESSAGES_SUCCESS) {
132  qWarning() << "Error sending extension message";
133  }
134 
135  return receipt;
136 }
137 
139 {
140  std::lock_guard<std::mutex> lock(*toxext_mutex);
141 
142  auto ret = toxext_send(packetList);
143  if (ret != TOXEXT_SUCCESS) {
144  qWarning() << "Failed to send packet";
145  }
146  // Indicate we've sent the packet even on failure since our packetlist will
147  // be invalid no matter what
148  hasBeenSent = true;
149  return ret == TOXEXT_SUCCESS;
150 }
151 
153 {
154  return TOX_EXTENSION_MESSAGES_DEFAULT_MAX_RECEIVING_MESSAGE_SIZE;
155 }
156 
157 void CoreExt::onFriendStatusChanged(uint32_t friendId, Status::Status status)
158 {
159  const auto prevStatusIt = currentStatuses.find(friendId);
160  const auto prevStatus = prevStatusIt == currentStatuses.end()
161  ? Status::Status::Offline : prevStatusIt->second;
162 
163  currentStatuses[friendId] = status;
164 
165  // Does not depend on prevStatus since prevStatus could be newly
166  // constructed. In this case we should still ensure the rest of the system
167  // knows there is no extension support
168  if (status == Status::Status::Offline) {
169  emit extendedMessageSupport(friendId, false);
170  } else if (prevStatus == Status::Status::Offline) {
171  tox_extension_messages_negotiate(toxExtMessages.get(), friendId);
172  }
173 }
174 
175 void CoreExt::onExtendedMessageReceived(uint32_t friendId, const uint8_t* data, size_t size, void* userData)
176 {
177  QString msg = ToxString(data, size).getQString();
178  emit static_cast<CoreExt*>(userData)->extendedMessageReceived(friendId, msg);
179 }
180 
181 void CoreExt::onExtendedMessageReceipt(uint32_t friendId, uint64_t receiptId, void* userData)
182 {
183  emit static_cast<CoreExt*>(userData)->extendedReceiptReceived(friendId, receiptId);
184 }
185 
186 void CoreExt::onExtendedMessageNegotiation(uint32_t friendId, bool compatible, uint64_t maxMessageSize, void* userData)
187 {
188  auto coreExt = static_cast<CoreExt*>(userData);
189 
190  // HACK: handling configurable max message size per-friend is not trivial.
191  // For now the upper layers just assume that the max size for extended
192  // messages is the same for all friends. If a friend has a max message size
193  // lower than this value we just pretend they do not have the extension since
194  // we will not split correctly for this friend.
195  if (maxMessageSize < coreExt->getMaxExtendedMessageSize())
196  compatible = false;
197 
198  emit coreExt->extendedMessageSupport(friendId, compatible);
199 }
200 
CoreExt::onExtendedMessageReceived
static void onExtendedMessageReceived(uint32_t friendId, const uint8_t *data, size_t size, void *userData)
Definition: coreext.cpp:175
CoreExt::onLosslessPacket
void onLosslessPacket(uint32_t friendId, const uint8_t *data, size_t length)
Handles extension related lossless packets.
Definition: coreext.cpp:66
Status::Status
Status
Definition: status.h:28
CoreExt::process
void process()
Periodic service function.
Definition: coreext.cpp:60
ToxString::getQString
QString getQString() const
Gets the string as QString.
Definition: toxstring.cpp:84
CoreExt::currentStatuses
std::unordered_map< uint32_t, Status::Status > currentStatuses
Definition: coreext.h:150
Status::Status::Offline
@ Offline
CoreExt::onExtendedMessageReceipt
static void onExtendedMessageReceipt(uint32_t friendId, uint64_t receiptId, void *userData)
Definition: coreext.cpp:181
CoreExt::extendedMessageSupport
void extendedMessageSupport(uint32_t friendId, bool supported)
CoreExt::toxExt
ExtensionPtr< ToxExt > toxExt
Definition: coreext.h:151
CoreExt::Packet::addExtendedMessage
uint64_t addExtendedMessage(QString message) override
Adds message to packet.
Definition: coreext.cpp:98
CoreExt::toxExtMessages
ExtensionPtr< ToxExtensionMessages > toxExtMessages
Definition: coreext.h:152
coreext.h
CoreExt::ExtensionPtr
std::unique_ptr< T, void(*)(T *)> ExtensionPtr
Definition: coreext.h:145
toxstring.h
CoreExt::extendedMessageReceived
void extendedMessageReceived(uint32_t friendId, const QString &message)
CoreExt::PacketPassKey
Definition: coreext.h:46
ToxString
Helper to convert safely between strings in the c-toxcore representation and QString.
Definition: toxstring.h:27
CoreExt::Packet
Definition: coreext.h:80
CoreExt
Definition: coreext.h:41
HistMessageContentType::message
@ message
CoreExt::toxext_mutex
std::mutex toxext_mutex
Definition: coreext.h:149
CoreExt::Packet::toxext_mutex
std::mutex * toxext_mutex
Definition: coreext.h:114
CoreExt::Packet::send
bool send() override
Consumes the packet constructed with PacketBuilder packet and sends it to toxext.
Definition: coreext.cpp:138
CoreExt::CoreExt
CoreExt(CoreExt const &other)=delete
CoreExt::Packet::Packet
Packet(ToxExtPacketList *packetList, ToxExtensionMessages *toxExtMessages, uint32_t friendId, std::mutex *toxext_mutex, PacketPassKey)
Internal constructor for a packet.
Definition: coreext.cpp:74
ToxString::size
size_t size() const
Get the number of bytes in the string.
Definition: toxstring.cpp:75
CoreExt::onExtendedMessageNegotiation
static void onExtendedMessageNegotiation(uint32_t friendId, bool compatible, uint64_t maxMessageSize, void *userData)
Definition: coreext.cpp:186
CoreExt::extendedReceiptReceived
void extendedReceiptReceived(uint32_t friendId, uint64_t receiptId)
CoreExt::makeCoreExt
static std::unique_ptr< CoreExt > makeCoreExt(Tox *core)
Creates a CoreExt instance. Using a pointer here makes our registrations with extensions significantl...
Definition: coreext.cpp:35
ToxString::data
const uint8_t * data() const
Returns a pointer to the beginning of the string data.
Definition: toxstring.cpp:66
CoreExt::getMaxExtendedMessageSize
uint64_t getMaxExtendedMessageSize()
Definition: coreext.cpp:152
CoreExt::onFriendStatusChanged
void onFriendStatusChanged(uint32_t friendId, Status::Status status)
Definition: coreext.cpp:157
CoreExt::getPacket
std::unique_ptr< ICoreExtPacket > getPacket(uint32_t friendId) override
Gets a new packet builder for friend with core friend id friendId.
Definition: coreext.cpp:88