Coverage Report

Created: 2025-08-05 10:35

/src/c-toxcore/toxcore/tox.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: GPL-3.0-or-later
2
 * Copyright © 2016-2025 The TokTok team.
3
 * Copyright © 2013 Tox project.
4
 */
5
6
/**
7
 * The Tox public API.
8
 */
9
#ifndef _XOPEN_SOURCE
10
#define _XOPEN_SOURCE 600
11
#endif /* _XOPEN_SOURCE */
12
13
#include "tox.h"
14
15
#include <assert.h>
16
#include <string.h>
17
18
#include "DHT.h"
19
#include "Messenger.h"
20
#include "TCP_client.h"
21
#include "attributes.h"
22
#include "ccompat.h"
23
#include "crypto_core.h"
24
#include "friend_requests.h"
25
#include "group.h"
26
#include "group_chats.h"
27
#include "group_common.h"
28
#include "logger.h"
29
#include "mem.h"
30
#include "mono_time.h"
31
#include "net_crypto.h"
32
#include "network.h"
33
#include "onion_client.h"
34
#include "state.h"
35
#include "tox_log_level.h"
36
#include "tox_options.h"
37
#include "tox_private.h"
38
#include "tox_struct.h" // IWYU pragma: keep
39
#include "util.h"
40
41
#include "../toxencryptsave/defines.h"
42
43
#define SET_ERROR_PARAMETER(param, x) \
44
3.98k
    do {                              \
45
3.98k
        if (param != nullptr) {       \
46
46
            *param = x;               \
47
46
        }                             \
48
3.98k
    } while (0)
49
50
static_assert(TOX_HASH_LENGTH == CRYPTO_SHA256_SIZE,
51
              "TOX_HASH_LENGTH is assumed to be equal to CRYPTO_SHA256_SIZE");
52
static_assert(FILE_ID_LENGTH == CRYPTO_SYMMETRIC_KEY_SIZE,
53
              "FILE_ID_LENGTH is assumed to be equal to CRYPTO_SYMMETRIC_KEY_SIZE");
54
static_assert(TOX_DHT_NODE_IP_STRING_SIZE == IP_NTOA_LEN,
55
              "TOX_DHT_NODE_IP_STRING_SIZE is assumed to be equal to IP_NTOA_LEN");
56
static_assert(TOX_GROUP_PEER_IP_STRING_MAX_LENGTH == IP_NTOA_LEN,
57
              "TOX_GROUP_PEER_IP_STRING_MAX_LENGTH is assumed to be equal to IP_NTOA_LEN");
58
static_assert(TOX_DHT_NODE_PUBLIC_KEY_SIZE == CRYPTO_PUBLIC_KEY_SIZE,
59
              "TOX_DHT_NODE_PUBLIC_KEY_SIZE is assumed to be equal to CRYPTO_PUBLIC_KEY_SIZE");
60
static_assert(TOX_FILE_ID_LENGTH == CRYPTO_SYMMETRIC_KEY_SIZE,
61
              "TOX_FILE_ID_LENGTH is assumed to be equal to CRYPTO_SYMMETRIC_KEY_SIZE");
62
static_assert(TOX_FILE_ID_LENGTH == TOX_HASH_LENGTH,
63
              "TOX_FILE_ID_LENGTH is assumed to be equal to TOX_HASH_LENGTH");
64
static_assert(TOX_PUBLIC_KEY_SIZE == CRYPTO_PUBLIC_KEY_SIZE,
65
              "TOX_PUBLIC_KEY_SIZE is assumed to be equal to CRYPTO_PUBLIC_KEY_SIZE");
66
static_assert(TOX_SECRET_KEY_SIZE == CRYPTO_SECRET_KEY_SIZE,
67
              "TOX_SECRET_KEY_SIZE is assumed to be equal to CRYPTO_SECRET_KEY_SIZE");
68
static_assert(TOX_MAX_NAME_LENGTH == MAX_NAME_LENGTH,
69
              "TOX_MAX_NAME_LENGTH is assumed to be equal to MAX_NAME_LENGTH");
70
static_assert(TOX_MAX_STATUS_MESSAGE_LENGTH == MAX_STATUSMESSAGE_LENGTH,
71
              "TOX_MAX_STATUS_MESSAGE_LENGTH is assumed to be equal to MAX_STATUSMESSAGE_LENGTH");
72
static_assert(TOX_GROUP_MAX_MESSAGE_LENGTH == GROUP_MAX_MESSAGE_LENGTH,
73
              "TOX_GROUP_MAX_MESSAGE_LENGTH is assumed to be equal to GROUP_MAX_MESSAGE_LENGTH");
74
static_assert(TOX_MAX_CUSTOM_PACKET_SIZE == MAX_GC_CUSTOM_LOSSLESS_PACKET_SIZE,
75
              "TOX_MAX_CUSTOM_PACKET_SIZE is assumed to be equal to MAX_GC_CUSTOM_LOSSLESS_PACKET_SIZE");
76
77
struct Tox_Userdata {
78
    Tox *tox;
79
    void *user_data;
80
};
81
82
static logger_cb tox_log_handler;
83
static void tox_log_handler(void *_Nullable context, Logger_Level level, const char *_Nonnull file, uint32_t line, const char *_Nonnull func,
84
                            const char *_Nonnull message, void *_Nullable userdata)
85
88.8k
{
86
88.8k
    Tox *tox = (Tox *)context;
87
88.8k
    assert(tox != nullptr);
88
89
88.8k
    if (tox->log_callback != nullptr) {
90
25
        tox->log_callback(tox, (Tox_Log_Level)level, file, line, func, message, userdata);
91
25
    }
92
88.8k
}
93
94
static m_self_connection_status_cb tox_self_connection_status_handler;
95
static void tox_self_connection_status_handler(Messenger *_Nonnull m, Onion_Connection_Status connection_status, void *_Nullable user_data)
96
0
{
97
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
98
0
    if (tox_data->tox->self_connection_status_callback != nullptr) {
99
0
        tox_unlock(tox_data->tox);
100
0
        tox_data->tox->self_connection_status_callback(tox_data->tox, (Tox_Connection)connection_status, tox_data->user_data);
101
0
        tox_lock(tox_data->tox);
102
0
    }
103
0
}
104
105
static m_friend_name_cb tox_friend_name_handler;
106
static void tox_friend_name_handler(Messenger *_Nonnull m, uint32_t friend_number, const uint8_t *_Nonnull name, size_t length,
107
                                    void *_Nullable user_data)
108
0
{
109
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
110
0
    if (tox_data->tox->friend_name_callback != nullptr) {
111
0
        tox_unlock(tox_data->tox);
112
0
        tox_data->tox->friend_name_callback(tox_data->tox, friend_number, name, length, tox_data->user_data);
113
0
        tox_lock(tox_data->tox);
114
0
    }
115
0
}
116
117
static m_friend_status_message_cb tox_friend_status_message_handler;
118
static void tox_friend_status_message_handler(Messenger *_Nonnull m, uint32_t friend_number, const uint8_t *_Nonnull message,
119
        size_t length, void *_Nullable user_data)
120
0
{
121
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
122
0
    if (tox_data->tox->friend_status_message_callback != nullptr) {
123
0
        tox_unlock(tox_data->tox);
124
0
        tox_data->tox->friend_status_message_callback(tox_data->tox, friend_number, message, length, tox_data->user_data);
125
0
        tox_lock(tox_data->tox);
126
0
    }
127
0
}
128
129
static m_friend_status_cb tox_friend_status_handler;
130
static void tox_friend_status_handler(Messenger *_Nonnull m, uint32_t friend_number, unsigned int status, void *_Nullable user_data)
131
0
{
132
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
133
0
    if (tox_data->tox->friend_status_callback != nullptr) {
134
0
        tox_unlock(tox_data->tox);
135
0
        tox_data->tox->friend_status_callback(tox_data->tox, friend_number, (Tox_User_Status)status, tox_data->user_data);
136
0
        tox_lock(tox_data->tox);
137
0
    }
138
0
}
139
140
static m_friend_connection_status_cb tox_friend_connection_status_handler;
141
static void tox_friend_connection_status_handler(Messenger *_Nonnull m, uint32_t friend_number, unsigned int connection_status,
142
        void *_Nullable user_data)
143
0
{
144
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
145
0
    if (tox_data->tox->friend_connection_status_callback != nullptr) {
146
0
        tox_unlock(tox_data->tox);
147
0
        tox_data->tox->friend_connection_status_callback(tox_data->tox, friend_number, (Tox_Connection)connection_status,
148
0
                tox_data->user_data);
149
0
        tox_lock(tox_data->tox);
150
0
    }
151
0
}
152
153
static m_friend_typing_cb tox_friend_typing_handler;
154
static void tox_friend_typing_handler(Messenger *_Nonnull m, uint32_t friend_number, bool is_typing, void *_Nullable user_data)
155
0
{
156
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
157
0
    if (tox_data->tox->friend_typing_callback != nullptr) {
158
0
        tox_unlock(tox_data->tox);
159
0
        tox_data->tox->friend_typing_callback(tox_data->tox, friend_number, is_typing, tox_data->user_data);
160
0
        tox_lock(tox_data->tox);
161
0
    }
162
0
}
163
164
static m_friend_read_receipt_cb tox_friend_read_receipt_handler;
165
static void tox_friend_read_receipt_handler(Messenger *_Nonnull m, uint32_t friend_number, uint32_t message_id, void *_Nullable user_data)
166
0
{
167
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
168
0
    if (tox_data->tox->friend_read_receipt_callback != nullptr) {
169
0
        tox_unlock(tox_data->tox);
170
0
        tox_data->tox->friend_read_receipt_callback(tox_data->tox, friend_number, message_id, tox_data->user_data);
171
0
        tox_lock(tox_data->tox);
172
0
    }
173
0
}
174
175
static m_friend_request_cb tox_friend_request_handler;
176
static void tox_friend_request_handler(Messenger *_Nonnull m, const uint8_t public_key[TOX_PUBLIC_KEY_SIZE], const uint8_t *_Nonnull message, size_t length,
177
                                       void *_Nullable user_data)
178
0
{
179
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
180
0
    if (tox_data->tox->friend_request_callback != nullptr) {
181
0
        tox_unlock(tox_data->tox);
182
0
        tox_data->tox->friend_request_callback(tox_data->tox, public_key, message, length, tox_data->user_data);
183
0
        tox_lock(tox_data->tox);
184
0
    }
185
0
}
186
187
static m_friend_message_cb tox_friend_message_handler;
188
static void tox_friend_message_handler(Messenger *_Nonnull m, uint32_t friend_number, unsigned int message_type,
189
                                       const uint8_t *_Nonnull message, size_t length, void *_Nullable user_data)
190
0
{
191
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
192
0
    if (tox_data->tox->friend_message_callback != nullptr) {
193
0
        tox_unlock(tox_data->tox);
194
0
        tox_data->tox->friend_message_callback(tox_data->tox, friend_number, (Tox_Message_Type)message_type, message, length,
195
0
                                               tox_data->user_data);
196
0
        tox_lock(tox_data->tox);
197
0
    }
198
0
}
199
200
static m_file_recv_control_cb tox_file_recv_control_handler;
201
static void tox_file_recv_control_handler(Messenger *_Nonnull m, uint32_t friend_number, uint32_t file_number,
202
        unsigned int control, void *_Nullable user_data)
203
0
{
204
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
205
0
    if (tox_data->tox->file_recv_control_callback != nullptr) {
206
0
        tox_unlock(tox_data->tox);
207
0
        tox_data->tox->file_recv_control_callback(tox_data->tox, friend_number, file_number, (Tox_File_Control)control,
208
0
                tox_data->user_data);
209
0
        tox_lock(tox_data->tox);
210
0
    }
211
0
}
212
213
static m_file_chunk_request_cb tox_file_chunk_request_handler;
214
static void tox_file_chunk_request_handler(Messenger *_Nonnull m, uint32_t friend_number, uint32_t file_number,
215
        uint64_t position, size_t length, void *_Nullable user_data)
216
0
{
217
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
218
0
    if (tox_data->tox->file_chunk_request_callback != nullptr) {
219
0
        tox_unlock(tox_data->tox);
220
0
        tox_data->tox->file_chunk_request_callback(tox_data->tox, friend_number, file_number, position, length,
221
0
                tox_data->user_data);
222
0
        tox_lock(tox_data->tox);
223
0
    }
224
0
}
225
226
static m_file_recv_cb tox_file_recv_handler;
227
static void tox_file_recv_handler(Messenger *_Nonnull m, uint32_t friend_number, uint32_t file_number, uint32_t kind,
228
                                  uint64_t file_size, const uint8_t *_Nonnull filename, size_t filename_length, void *_Nullable user_data)
229
0
{
230
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
231
0
    if (tox_data->tox->file_recv_callback != nullptr) {
232
0
        tox_unlock(tox_data->tox);
233
0
        tox_data->tox->file_recv_callback(tox_data->tox, friend_number, file_number, kind, file_size, filename, filename_length,
234
0
                                          tox_data->user_data);
235
0
        tox_lock(tox_data->tox);
236
0
    }
237
0
}
238
239
static m_file_recv_chunk_cb tox_file_recv_chunk_handler;
240
static void tox_file_recv_chunk_handler(Messenger *_Nonnull m, uint32_t friend_number, uint32_t file_number, uint64_t position,
241
                                        const uint8_t *_Nullable data, size_t length, void *_Nullable user_data)
242
0
{
243
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
244
0
    if (tox_data->tox->file_recv_chunk_callback != nullptr) {
245
0
        tox_unlock(tox_data->tox);
246
0
        tox_data->tox->file_recv_chunk_callback(tox_data->tox, friend_number, file_number, position, data, length,
247
0
                                                tox_data->user_data);
248
0
        tox_lock(tox_data->tox);
249
0
    }
250
0
}
251
252
static g_conference_invite_cb tox_conference_invite_handler;
253
static void tox_conference_invite_handler(Messenger *_Nonnull m, uint32_t friend_number, int type, const uint8_t *_Nonnull cookie,
254
        size_t length, void *_Nullable user_data)
255
0
{
256
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
257
0
    if (tox_data->tox->conference_invite_callback != nullptr) {
258
0
        tox_unlock(tox_data->tox);
259
0
        tox_data->tox->conference_invite_callback(tox_data->tox, friend_number, (Tox_Conference_Type)type, cookie, length,
260
0
                tox_data->user_data);
261
0
        tox_lock(tox_data->tox);
262
0
    }
263
0
}
264
265
static g_conference_connected_cb tox_conference_connected_handler;
266
static void tox_conference_connected_handler(Messenger *_Nonnull m, uint32_t conference_number, void *_Nullable user_data)
267
0
{
268
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
269
0
    if (tox_data->tox->conference_connected_callback != nullptr) {
270
0
        tox_unlock(tox_data->tox);
271
0
        tox_data->tox->conference_connected_callback(tox_data->tox, conference_number, tox_data->user_data);
272
0
        tox_lock(tox_data->tox);
273
0
    }
274
0
}
275
276
static g_conference_message_cb tox_conference_message_handler;
277
static void tox_conference_message_handler(Messenger *_Nonnull m, uint32_t conference_number, uint32_t peer_number, int type,
278
        const uint8_t *_Nonnull message, size_t length, void *_Nullable user_data)
279
0
{
280
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
281
0
    if (tox_data->tox->conference_message_callback != nullptr) {
282
0
        tox_unlock(tox_data->tox);
283
0
        tox_data->tox->conference_message_callback(tox_data->tox, conference_number, peer_number, (Tox_Message_Type)type,
284
0
                message, length, tox_data->user_data);
285
0
        tox_lock(tox_data->tox);
286
0
    }
287
0
}
288
289
static title_cb tox_conference_title_handler;
290
static void tox_conference_title_handler(Messenger *_Nonnull m, uint32_t conference_number, uint32_t peer_number,
291
        const uint8_t *_Nonnull title, size_t length, void *_Nullable user_data)
292
0
{
293
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
294
0
    if (tox_data->tox->conference_title_callback != nullptr) {
295
0
        tox_unlock(tox_data->tox);
296
0
        tox_data->tox->conference_title_callback(tox_data->tox, conference_number, peer_number, title, length,
297
0
                tox_data->user_data);
298
0
        tox_lock(tox_data->tox);
299
0
    }
300
0
}
301
302
static peer_name_cb tox_conference_peer_name_handler;
303
static void tox_conference_peer_name_handler(Messenger *_Nonnull m, uint32_t conference_number, uint32_t peer_number,
304
        const uint8_t *_Nonnull name, size_t length, void *_Nullable user_data)
305
0
{
306
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
307
0
    if (tox_data->tox->conference_peer_name_callback != nullptr) {
308
0
        tox_unlock(tox_data->tox);
309
0
        tox_data->tox->conference_peer_name_callback(tox_data->tox, conference_number, peer_number, name, length,
310
0
                tox_data->user_data);
311
0
        tox_lock(tox_data->tox);
312
0
    }
313
0
}
314
315
static peer_list_changed_cb tox_conference_peer_list_changed_handler;
316
static void tox_conference_peer_list_changed_handler(Messenger *_Nonnull m, uint32_t conference_number, void *_Nullable user_data)
317
0
{
318
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
319
0
    if (tox_data->tox->conference_peer_list_changed_callback != nullptr) {
320
0
        tox_unlock(tox_data->tox);
321
0
        tox_data->tox->conference_peer_list_changed_callback(tox_data->tox, conference_number, tox_data->user_data);
322
0
        tox_lock(tox_data->tox);
323
0
    }
324
0
}
325
326
static dht_nodes_response_cb tox_dht_nodes_response_handler;
327
static void tox_dht_nodes_response_handler(const DHT *_Nonnull dht, const Node_format *_Nonnull node, void *_Nullable user_data)
328
0
{
329
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
330
0
    if (tox_data->tox->dht_nodes_response_callback == nullptr) {
331
0
        return;
332
0
    }
333
334
0
    Ip_Ntoa ip_str;
335
0
    net_ip_ntoa(&node->ip_port.ip, &ip_str);
336
337
0
    tox_unlock(tox_data->tox);
338
0
    tox_data->tox->dht_nodes_response_callback(
339
0
        tox_data->tox, node->public_key, ip_str.buf, ip_str.length, net_ntohs(node->ip_port.port),
340
0
        tox_data->user_data);
341
0
    tox_lock(tox_data->tox);
342
0
}
343
344
static m_friend_lossy_packet_cb tox_friend_lossy_packet_handler;
345
static void tox_friend_lossy_packet_handler(Messenger *_Nonnull m, uint32_t friend_number, uint8_t packet_id,
346
        const uint8_t *_Nonnull data, size_t length, void *_Nullable user_data)
347
0
{
348
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
349
0
    assert(data != nullptr);
350
0
    assert(length > 0);
351
352
0
    if (tox_data->tox->friend_lossy_packet_callback_per_pktid[packet_id] != nullptr) {
353
0
        tox_unlock(tox_data->tox);
354
0
        tox_data->tox->friend_lossy_packet_callback_per_pktid[packet_id](tox_data->tox, friend_number, data, length,
355
0
                tox_data->user_data);
356
0
        tox_lock(tox_data->tox);
357
0
    }
358
0
}
359
360
static m_friend_lossless_packet_cb tox_friend_lossless_packet_handler;
361
static void tox_friend_lossless_packet_handler(Messenger *_Nonnull m, uint32_t friend_number, uint8_t packet_id,
362
        const uint8_t *_Nonnull data, size_t length, void *_Nullable user_data)
363
0
{
364
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
365
0
    assert(data != nullptr);
366
0
    assert(length > 0);
367
368
0
    if (tox_data->tox->friend_lossless_packet_callback_per_pktid[packet_id] != nullptr) {
369
0
        tox_unlock(tox_data->tox);
370
0
        tox_data->tox->friend_lossless_packet_callback_per_pktid[packet_id](tox_data->tox, friend_number, data, length,
371
0
                tox_data->user_data);
372
0
        tox_lock(tox_data->tox);
373
0
    }
374
0
}
375
376
static void tox_group_peer_name_handler(const Messenger *_Nonnull m, uint32_t group_number, GC_Peer_Id peer_id,
377
                                        const uint8_t *_Nonnull name, size_t length, void *_Nullable user_data)
378
0
{
379
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
380
0
    if (tox_data->tox->group_peer_name_callback != nullptr) {
381
0
        tox_unlock(tox_data->tox);
382
0
        tox_data->tox->group_peer_name_callback(tox_data->tox, group_number, gc_peer_id_to_int(peer_id), name, length, tox_data->user_data);
383
0
        tox_lock(tox_data->tox);
384
0
    }
385
0
}
386
387
static void tox_group_peer_status_handler(const Messenger *_Nonnull m, uint32_t group_number, GC_Peer_Id peer_id,
388
        unsigned int status, void *_Nullable user_data)
389
0
{
390
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
391
0
    if (tox_data->tox->group_peer_status_callback != nullptr) {
392
0
        tox_unlock(tox_data->tox);
393
0
        tox_data->tox->group_peer_status_callback(tox_data->tox, group_number, gc_peer_id_to_int(peer_id), (Tox_User_Status)status,
394
0
                tox_data->user_data);
395
0
        tox_lock(tox_data->tox);
396
0
    }
397
0
}
398
399
static void tox_group_topic_handler(const Messenger *_Nonnull m, uint32_t group_number, GC_Peer_Id peer_id, const uint8_t *_Nonnull topic,
400
                                    size_t length, void *_Nullable user_data)
401
0
{
402
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
403
0
    if (tox_data->tox->group_topic_callback != nullptr) {
404
0
        tox_unlock(tox_data->tox);
405
0
        tox_data->tox->group_topic_callback(tox_data->tox, group_number, gc_peer_id_to_int(peer_id), topic, length, tox_data->user_data);
406
0
        tox_lock(tox_data->tox);
407
0
    }
408
0
}
409
410
static void tox_group_topic_lock_handler(const Messenger *_Nonnull m, uint32_t group_number, unsigned int topic_lock,
411
        void *_Nullable user_data)
412
0
{
413
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
414
0
    if (tox_data->tox->group_topic_lock_callback != nullptr) {
415
0
        tox_unlock(tox_data->tox);
416
0
        tox_data->tox->group_topic_lock_callback(tox_data->tox, group_number, (Tox_Group_Topic_Lock)topic_lock,
417
0
                tox_data->user_data);
418
0
        tox_lock(tox_data->tox);
419
0
    }
420
0
}
421
422
static void tox_group_voice_state_handler(const Messenger *_Nonnull m, uint32_t group_number, unsigned int voice_state,
423
        void *_Nullable user_data)
424
0
{
425
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
426
0
    if (tox_data->tox->group_voice_state_callback != nullptr) {
427
0
        tox_unlock(tox_data->tox);
428
0
        tox_data->tox->group_voice_state_callback(tox_data->tox, group_number, (Tox_Group_Voice_State)voice_state,
429
0
                tox_data->user_data);
430
0
        tox_lock(tox_data->tox);
431
0
    }
432
0
}
433
434
static void tox_group_peer_limit_handler(const Messenger *_Nonnull m, uint32_t group_number, uint32_t peer_limit,
435
        void *_Nullable user_data)
436
0
{
437
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
438
0
    if (tox_data->tox->group_peer_limit_callback != nullptr) {
439
0
        tox_unlock(tox_data->tox);
440
0
        tox_data->tox->group_peer_limit_callback(tox_data->tox, group_number, peer_limit, tox_data->user_data);
441
0
        tox_lock(tox_data->tox);
442
0
    }
443
0
}
444
445
static void tox_group_privacy_state_handler(const Messenger *_Nonnull m, uint32_t group_number, unsigned int privacy_state,
446
        void *_Nullable user_data)
447
0
{
448
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
449
0
    if (tox_data->tox->group_privacy_state_callback != nullptr) {
450
0
        tox_unlock(tox_data->tox);
451
0
        tox_data->tox->group_privacy_state_callback(tox_data->tox, group_number, (Tox_Group_Privacy_State)privacy_state,
452
0
                tox_data->user_data);
453
0
        tox_lock(tox_data->tox);
454
0
    }
455
0
}
456
457
static void tox_group_password_handler(const Messenger *_Nonnull m, uint32_t group_number, const uint8_t *_Nullable password,
458
                                       size_t length, void *_Nullable user_data)
459
0
{
460
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
461
0
    if (tox_data->tox->group_password_callback != nullptr) {
462
0
        tox_unlock(tox_data->tox);
463
0
        tox_data->tox->group_password_callback(tox_data->tox, group_number, password, length, tox_data->user_data);
464
0
        tox_lock(tox_data->tox);
465
0
    }
466
0
}
467
468
static void tox_group_message_handler(const Messenger *_Nonnull m, uint32_t group_number, GC_Peer_Id peer_id, unsigned int type,
469
                                      const uint8_t *_Nonnull message, size_t length, Tox_Group_Message_Id message_id, void *_Nullable user_data)
470
0
{
471
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
472
0
    if (tox_data->tox->group_message_callback != nullptr) {
473
0
        tox_unlock(tox_data->tox);
474
0
        tox_data->tox->group_message_callback(tox_data->tox, group_number, gc_peer_id_to_int(peer_id), (Tox_Message_Type)type, message, length,
475
0
                                              message_id, tox_data->user_data);
476
0
        tox_lock(tox_data->tox);
477
0
    }
478
0
}
479
480
static void tox_group_private_message_handler(const Messenger *_Nonnull m, uint32_t group_number, GC_Peer_Id peer_id,
481
        unsigned int type, const uint8_t *_Nonnull message, size_t length, Tox_Group_Message_Id message_id, void *_Nullable user_data)
482
0
{
483
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
484
0
    if (tox_data->tox->group_private_message_callback != nullptr) {
485
0
        tox_unlock(tox_data->tox);
486
0
        tox_data->tox->group_private_message_callback(tox_data->tox, group_number, gc_peer_id_to_int(peer_id), (Tox_Message_Type)type, message,
487
0
                length, message_id, tox_data->user_data);
488
0
        tox_lock(tox_data->tox);
489
0
    }
490
0
}
491
492
static void tox_group_custom_packet_handler(const Messenger *_Nonnull m, uint32_t group_number, GC_Peer_Id peer_id,
493
        const uint8_t *_Nonnull data, size_t length, void *_Nullable user_data)
494
0
{
495
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
496
0
    if (tox_data->tox->group_custom_packet_callback != nullptr) {
497
0
        tox_unlock(tox_data->tox);
498
0
        tox_data->tox->group_custom_packet_callback(tox_data->tox, group_number, gc_peer_id_to_int(peer_id), data, length, tox_data->user_data);
499
0
        tox_lock(tox_data->tox);
500
0
    }
501
0
}
502
503
static void tox_group_custom_private_packet_handler(const Messenger *_Nonnull m, uint32_t group_number, GC_Peer_Id peer_id,
504
        const uint8_t *_Nonnull data, size_t length, void *_Nullable user_data)
505
0
{
506
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
507
0
    if (tox_data->tox->group_custom_private_packet_callback != nullptr) {
508
0
        tox_unlock(tox_data->tox);
509
0
        tox_data->tox->group_custom_private_packet_callback(tox_data->tox, group_number, gc_peer_id_to_int(peer_id), data, length,
510
0
                tox_data->user_data);
511
0
        tox_lock(tox_data->tox);
512
0
    }
513
0
}
514
515
static void tox_group_invite_handler(const Messenger *_Nonnull m, uint32_t friend_number, const uint8_t *_Nonnull invite_data,
516
                                     size_t length, const uint8_t *_Nonnull group_name, size_t group_name_length, void *_Nullable user_data)
517
0
{
518
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
519
0
    if (tox_data->tox->group_invite_callback != nullptr) {
520
0
        tox_unlock(tox_data->tox);
521
0
        tox_data->tox->group_invite_callback(tox_data->tox, friend_number, invite_data, length, group_name, group_name_length,
522
0
                                             tox_data->user_data);
523
0
        tox_lock(tox_data->tox);
524
0
    }
525
0
}
526
527
static void tox_group_peer_join_handler(const Messenger *_Nonnull m, uint32_t group_number, GC_Peer_Id peer_id, void *_Nullable user_data)
528
0
{
529
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
530
0
    if (tox_data->tox->group_peer_join_callback != nullptr) {
531
0
        tox_unlock(tox_data->tox);
532
0
        tox_data->tox->group_peer_join_callback(tox_data->tox, group_number, gc_peer_id_to_int(peer_id), tox_data->user_data);
533
0
        tox_lock(tox_data->tox);
534
0
    }
535
0
}
536
537
static void tox_group_peer_exit_handler(const Messenger *_Nonnull m, uint32_t group_number, GC_Peer_Id peer_id,
538
                                        unsigned int exit_type, const uint8_t *_Nonnull name, size_t name_length,
539
                                        const uint8_t *_Nullable part_message, size_t length, void *_Nullable user_data)
540
0
{
541
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
542
0
    if (tox_data->tox->group_peer_exit_callback != nullptr) {
543
0
        tox_unlock(tox_data->tox);
544
0
        tox_data->tox->group_peer_exit_callback(tox_data->tox, group_number, gc_peer_id_to_int(peer_id),
545
0
                                                (Tox_Group_Exit_Type)exit_type, name, name_length,
546
0
                                                part_message, length, tox_data->user_data);
547
0
        tox_lock(tox_data->tox);
548
0
    }
549
0
}
550
551
static void tox_group_self_join_handler(const Messenger *_Nonnull m, uint32_t group_number, void *_Nullable user_data)
552
0
{
553
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
554
0
    if (tox_data->tox->group_self_join_callback != nullptr) {
555
0
        tox_unlock(tox_data->tox);
556
0
        tox_data->tox->group_self_join_callback(tox_data->tox, group_number, tox_data->user_data);
557
0
        tox_lock(tox_data->tox);
558
0
    }
559
0
}
560
561
static void tox_group_join_fail_handler(const Messenger *_Nonnull m, uint32_t group_number, unsigned int fail_type,
562
                                        void *_Nullable user_data)
563
0
{
564
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
565
0
    if (tox_data->tox->group_join_fail_callback != nullptr) {
566
0
        tox_unlock(tox_data->tox);
567
0
        tox_data->tox->group_join_fail_callback(tox_data->tox, group_number, (Tox_Group_Join_Fail)fail_type,
568
0
                                                tox_data->user_data);
569
0
        tox_lock(tox_data->tox);
570
0
    }
571
0
}
572
573
static void tox_group_moderation_handler(const Messenger *_Nonnull m, uint32_t group_number, GC_Peer_Id source_peer_number,
574
        GC_Peer_Id target_peer_number, unsigned int mod_type, void *_Nullable user_data)
575
0
{
576
0
    struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
577
0
    if (tox_data->tox->group_moderation_callback != nullptr) {
578
0
        tox_unlock(tox_data->tox);
579
0
        tox_data->tox->group_moderation_callback(tox_data->tox, group_number,
580
0
                gc_peer_id_to_int(source_peer_number), gc_peer_id_to_int(target_peer_number),
581
0
                (Tox_Group_Mod_Event)mod_type, tox_data->user_data);
582
0
        tox_lock(tox_data->tox);
583
0
    }
584
0
}
585
586
bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch)
587
0
{
588
0
    return TOX_VERSION_IS_API_COMPATIBLE(major, minor, patch);
589
0
}
590
591
static State_Load_Status state_load_callback(void *_Nonnull outer, const uint8_t *_Nonnull data, uint32_t length, uint16_t type)
592
34.2k
{
593
34.2k
    const Tox *tox = (const Tox *)outer;
594
34.2k
    State_Load_Status status = STATE_LOAD_STATUS_CONTINUE;
595
596
34.2k
    if (messenger_load_state_section(tox->m, data, length, type, &status)
597
34.2k
            || conferences_load_state_section(tox->m->conferences_object, data, length, type, &status)) {
598
33.8k
        return status;
599
33.8k
    }
600
601
435
    if (type == STATE_TYPE_END) {
602
8
        if (length != 0) {
603
1
            return STATE_LOAD_STATUS_ERROR;
604
1
        }
605
606
7
        return STATE_LOAD_STATUS_END;
607
8
    }
608
609
427
    LOGGER_ERROR(tox->m->log, "Load state: contains unrecognized part (len %u, type %u)",
610
427
                 length, type);
611
612
427
    return STATE_LOAD_STATUS_CONTINUE;
613
435
}
614
615
/** Load tox from data of size length. */
616
static int tox_load(Tox *_Nonnull tox, const uint8_t *_Nonnull data, uint32_t length)
617
1.96k
{
618
1.96k
    uint32_t data32[2];
619
1.96k
    const uint32_t cookie_len = sizeof(data32);
620
621
1.96k
    if (length < cookie_len) {
622
0
        return -1;
623
0
    }
624
625
1.96k
    memcpy(data32, data, sizeof(uint32_t));
626
1.96k
    lendian_bytes_to_host32(data32 + 1, data + sizeof(uint32_t));
627
628
1.96k
    if (data32[0] != 0 || data32[1] != STATE_COOKIE_GLOBAL) {
629
2
        return -1;
630
2
    }
631
632
1.96k
    return state_load(tox->m->log, state_load_callback, tox, data + cookie_len,
633
1.96k
                      length - cookie_len, STATE_COOKIE_TYPE);
634
1.96k
}
635
636
static Tox *tox_new_system(const struct Tox_Options *_Nullable options, Tox_Err_New *_Nullable error, const Tox_System *_Nullable sys)
637
1.99k
{
638
1.99k
    struct Tox_Options *default_options = nullptr;
639
1.99k
    if (options == nullptr) {
640
0
        Tox_Err_Options_New err;
641
0
        default_options = tox_options_new(&err);
642
643
0
        switch (err) {
644
0
            case TOX_ERR_OPTIONS_NEW_OK: {
645
0
                assert(default_options != nullptr);
646
0
                break;
647
0
            }
648
649
0
            case TOX_ERR_OPTIONS_NEW_MALLOC: {
650
0
                SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC);
651
0
                return nullptr;
652
0
            }
653
0
        }
654
0
    }
655
656
1.99k
    const struct Tox_Options *const opts = options != nullptr ? options : default_options;
657
1.99k
    assert(opts != nullptr);
658
659
1.99k
    const Tox_System default_system = tox_default_system();
660
661
1.99k
    if (sys == nullptr) {
662
0
        sys = &default_system;
663
0
    }
664
665
1.99k
    if (sys->rng == nullptr || sys->ns == nullptr || sys->mem == nullptr) {
666
        // TODO(iphydf): Not quite right, but similar.
667
0
        SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC);
668
0
        tox_options_free(default_options);
669
0
        return nullptr;
670
0
    }
671
672
1.99k
    Messenger_Options m_options = {false};
673
674
1.99k
    m_options.dns_enabled = !tox_options_get_experimental_disable_dns(opts);
675
676
1.99k
    bool load_savedata_sk = false;
677
1.99k
    bool load_savedata_tox = false;
678
679
1.99k
    if (tox_options_get_savedata_type(opts) != TOX_SAVEDATA_TYPE_NONE) {
680
1.97k
        if (tox_options_get_savedata_data(opts) == nullptr || tox_options_get_savedata_length(opts) == 0) {
681
0
            SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT);
682
0
            tox_options_free(default_options);
683
0
            return nullptr;
684
0
        }
685
1.97k
    }
686
687
1.99k
    if (tox_options_get_savedata_type(opts) == TOX_SAVEDATA_TYPE_SECRET_KEY) {
688
0
        if (tox_options_get_savedata_length(opts) != TOX_SECRET_KEY_SIZE) {
689
0
            SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT);
690
0
            tox_options_free(default_options);
691
0
            return nullptr;
692
0
        }
693
694
0
        load_savedata_sk = true;
695
1.99k
    } else if (tox_options_get_savedata_type(opts) == TOX_SAVEDATA_TYPE_TOX_SAVE) {
696
1.97k
        if (tox_options_get_savedata_length(opts) < TOX_ENC_SAVE_MAGIC_LENGTH) {
697
1
            SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT);
698
1
            tox_options_free(default_options);
699
1
            return nullptr;
700
1
        }
701
702
1.96k
        if (memcmp(tox_options_get_savedata_data(opts), TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0) {
703
1
            SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_ENCRYPTED);
704
1
            tox_options_free(default_options);
705
1
            return nullptr;
706
1
        }
707
708
1.96k
        load_savedata_tox = true;
709
1.96k
    }
710
711
1.99k
    m_options.ipv6enabled = tox_options_get_ipv6_enabled(opts);
712
1.99k
    m_options.udp_disabled = !tox_options_get_udp_enabled(opts);
713
1.99k
    m_options.port_range[0] = tox_options_get_start_port(opts);
714
1.99k
    m_options.port_range[1] = tox_options_get_end_port(opts);
715
1.99k
    m_options.tcp_server_port = tox_options_get_tcp_port(opts);
716
1.99k
    m_options.hole_punching_enabled = tox_options_get_hole_punching_enabled(opts);
717
1.99k
    m_options.local_discovery_enabled = tox_options_get_local_discovery_enabled(opts);
718
1.99k
    m_options.dht_announcements_enabled = tox_options_get_dht_announcements_enabled(opts);
719
1.99k
    m_options.groups_persistence_enabled = tox_options_get_experimental_groups_persistence(opts);
720
721
1.99k
    if (m_options.udp_disabled) {
722
0
        m_options.local_discovery_enabled = false;
723
0
    }
724
725
1.99k
    Tox *tox = (Tox *)mem_alloc(sys->mem, sizeof(Tox));
726
727
1.99k
    if (tox == nullptr) {
728
1
        SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC);
729
1
        tox_options_free(default_options);
730
1
        return nullptr;
731
1
    }
732
733
1.99k
    tox->log_callback = tox_options_get_log_callback(opts);
734
1.99k
    m_options.log_callback = tox_log_handler;
735
1.99k
    m_options.log_context = tox;
736
1.99k
    m_options.log_user_data = tox_options_get_log_user_data(opts);
737
738
1.99k
    switch (tox_options_get_proxy_type(opts)) {
739
4
        case TOX_PROXY_TYPE_HTTP: {
740
4
            m_options.proxy_info.proxy_type = TCP_PROXY_HTTP;
741
4
            break;
742
0
        }
743
744
7
        case TOX_PROXY_TYPE_SOCKS5: {
745
7
            m_options.proxy_info.proxy_type = TCP_PROXY_SOCKS5;
746
7
            break;
747
0
        }
748
749
1.97k
        case TOX_PROXY_TYPE_NONE: {
750
1.97k
            m_options.proxy_info.proxy_type = TCP_PROXY_NONE;
751
1.97k
            break;
752
0
        }
753
754
0
        default: {
755
0
            SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_TYPE);
756
0
            mem_delete(sys->mem, tox);
757
0
            tox_options_free(default_options);
758
0
            return nullptr;
759
0
        }
760
1.99k
    }
761
762
1.99k
    tox->sys = *sys;
763
764
1.99k
    if (m_options.proxy_info.proxy_type != TCP_PROXY_NONE) {
765
11
        if (tox_options_get_proxy_port(opts) == 0) {
766
0
            SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_PORT);
767
0
            mem_delete(sys->mem, tox);
768
0
            tox_options_free(default_options);
769
0
            return nullptr;
770
0
        }
771
772
11
        ip_init(&m_options.proxy_info.ip_port.ip, m_options.ipv6enabled);
773
774
11
        if (m_options.ipv6enabled) {
775
11
            m_options.proxy_info.ip_port.ip.family = net_family_unspec();
776
11
        }
777
778
11
        const char *const proxy_host = tox_options_get_proxy_host(opts);
779
11
        const bool dns_enabled = !tox_options_get_experimental_disable_dns(opts);
780
781
11
        if (proxy_host == nullptr
782
11
                || !addr_resolve_or_parse_ip(tox->sys.ns, tox->sys.mem, proxy_host, &m_options.proxy_info.ip_port.ip, nullptr, dns_enabled)) {
783
0
            SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_HOST);
784
            // TODO(irungentoo): TOX_ERR_NEW_PROXY_NOT_FOUND if domain.
785
0
            mem_delete(sys->mem, tox);
786
0
            tox_options_free(default_options);
787
0
            return nullptr;
788
0
        }
789
790
11
        m_options.proxy_info.ip_port.port = net_htons(tox_options_get_proxy_port(opts));
791
11
    }
792
793
1.99k
    tox->mono_time = mono_time_new(tox->sys.mem, sys->mono_time_callback, sys->mono_time_user_data);
794
795
1.99k
    if (tox->mono_time == nullptr) {
796
2
        SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC);
797
2
        mem_delete(sys->mem, tox);
798
2
        tox_options_free(default_options);
799
2
        return nullptr;
800
2
    }
801
802
1.98k
    if (tox_options_get_experimental_thread_safety(opts)) {
803
0
        pthread_mutex_t *mutex = (pthread_mutex_t *)mem_alloc(sys->mem, sizeof(pthread_mutex_t));
804
805
0
        if (mutex == nullptr) {
806
0
            SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC);
807
0
            mem_delete(sys->mem, tox);
808
0
            tox_options_free(default_options);
809
0
            return nullptr;
810
0
        }
811
812
0
        pthread_mutex_init(mutex, nullptr);
813
814
0
        tox->mutex = mutex;
815
1.98k
    } else {
816
1.98k
        tox->mutex = nullptr;
817
1.98k
    }
818
819
1.98k
    tox_lock(tox);
820
821
1.98k
    Messenger_Error m_error;
822
1.98k
    tox->m = new_messenger(tox->mono_time, tox->sys.mem, tox->sys.rng, tox->sys.ns, &m_options, &m_error);
823
824
1.98k
    if (tox->m == nullptr) {
825
20
        switch (m_error) {
826
0
            case MESSENGER_ERROR_PORT:
827
0
            case MESSENGER_ERROR_TCP_SERVER: {
828
0
                SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PORT_ALLOC);
829
0
                break;
830
0
            }
831
20
            case MESSENGER_ERROR_OTHER:
832
20
            case MESSENGER_ERROR_NONE: {
833
20
                SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC);
834
20
                break;
835
20
            }
836
20
        }
837
838
20
        mono_time_free(tox->sys.mem, tox->mono_time);
839
20
        tox_unlock(tox);
840
841
20
        if (tox->mutex != nullptr) {
842
0
            pthread_mutex_destroy(tox->mutex);
843
0
        }
844
845
20
        mem_delete(sys->mem, tox->mutex);
846
20
        mem_delete(sys->mem, tox);
847
20
        tox_options_free(default_options);
848
20
        return nullptr;
849
20
    }
850
851
1.96k
    tox->m->conferences_object = new_groupchats(tox->mono_time, sys->mem, tox->m);
852
853
1.96k
    if (tox->m->conferences_object == nullptr) {
854
0
        kill_messenger(tox->m);
855
856
0
        mono_time_free(tox->sys.mem, tox->mono_time);
857
0
        tox_unlock(tox);
858
859
0
        if (tox->mutex != nullptr) {
860
0
            pthread_mutex_destroy(tox->mutex);
861
0
        }
862
863
0
        mem_delete(sys->mem, tox->mutex);
864
0
        mem_delete(sys->mem, tox);
865
866
0
        SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC);
867
0
        tox_options_free(default_options);
868
0
        return nullptr;
869
0
    }
870
871
1.96k
    if (load_savedata_tox
872
1.96k
            && tox_load(tox, tox_options_get_savedata_data(opts), tox_options_get_savedata_length(opts)) == -1) {
873
499
        kill_groupchats(tox->m->conferences_object);
874
499
        kill_messenger(tox->m);
875
876
499
        mono_time_free(tox->sys.mem, tox->mono_time);
877
499
        tox_unlock(tox);
878
879
499
        if (tox->mutex != nullptr) {
880
0
            pthread_mutex_destroy(tox->mutex);
881
0
        }
882
883
499
        mem_delete(sys->mem, tox->mutex);
884
499
        mem_delete(sys->mem, tox);
885
886
499
        SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT);
887
499
        tox_options_free(default_options);
888
499
        return nullptr;
889
499
    }
890
891
1.46k
    if (load_savedata_sk) {
892
0
        load_secret_key(tox->m->net_crypto, tox_options_get_savedata_data(opts));
893
0
    }
894
895
1.46k
    m_callback_namechange(tox->m, tox_friend_name_handler);
896
1.46k
    m_callback_core_connection(tox->m, tox_self_connection_status_handler);
897
1.46k
    m_callback_statusmessage(tox->m, tox_friend_status_message_handler);
898
1.46k
    m_callback_userstatus(tox->m, tox_friend_status_handler);
899
1.46k
    m_callback_connectionstatus(tox->m, tox_friend_connection_status_handler);
900
1.46k
    m_callback_typingchange(tox->m, tox_friend_typing_handler);
901
1.46k
    m_callback_read_receipt(tox->m, tox_friend_read_receipt_handler);
902
1.46k
    m_callback_friendrequest(tox->m, tox_friend_request_handler);
903
1.46k
    m_callback_friendmessage(tox->m, tox_friend_message_handler);
904
1.46k
    callback_file_control(tox->m, tox_file_recv_control_handler);
905
1.46k
    callback_file_reqchunk(tox->m, tox_file_chunk_request_handler);
906
1.46k
    callback_file_sendrequest(tox->m, tox_file_recv_handler);
907
1.46k
    callback_file_data(tox->m, tox_file_recv_chunk_handler);
908
1.46k
    dht_callback_nodes_response(tox->m->dht, tox_dht_nodes_response_handler);
909
1.46k
    g_callback_group_invite(tox->m->conferences_object, tox_conference_invite_handler);
910
1.46k
    g_callback_group_connected(tox->m->conferences_object, tox_conference_connected_handler);
911
1.46k
    g_callback_group_message(tox->m->conferences_object, tox_conference_message_handler);
912
1.46k
    g_callback_group_title(tox->m->conferences_object, tox_conference_title_handler);
913
1.46k
    g_callback_peer_name(tox->m->conferences_object, tox_conference_peer_name_handler);
914
1.46k
    g_callback_peer_list_changed(tox->m->conferences_object, tox_conference_peer_list_changed_handler);
915
1.46k
    custom_lossy_packet_registerhandler(tox->m, tox_friend_lossy_packet_handler);
916
1.46k
    custom_lossless_packet_registerhandler(tox->m, tox_friend_lossless_packet_handler);
917
918
1.46k
    m_callback_group_invite(tox->m, tox_group_invite_handler);
919
1.46k
    gc_callback_message(tox->m, tox_group_message_handler);
920
1.46k
    gc_callback_private_message(tox->m, tox_group_private_message_handler);
921
1.46k
    gc_callback_custom_packet(tox->m, tox_group_custom_packet_handler);
922
1.46k
    gc_callback_custom_private_packet(tox->m, tox_group_custom_private_packet_handler);
923
1.46k
    gc_callback_moderation(tox->m, tox_group_moderation_handler);
924
1.46k
    gc_callback_nick_change(tox->m, tox_group_peer_name_handler);
925
1.46k
    gc_callback_status_change(tox->m, tox_group_peer_status_handler);
926
1.46k
    gc_callback_topic_change(tox->m, tox_group_topic_handler);
927
1.46k
    gc_callback_peer_limit(tox->m, tox_group_peer_limit_handler);
928
1.46k
    gc_callback_privacy_state(tox->m, tox_group_privacy_state_handler);
929
1.46k
    gc_callback_topic_lock(tox->m, tox_group_topic_lock_handler);
930
1.46k
    gc_callback_password(tox->m, tox_group_password_handler);
931
1.46k
    gc_callback_peer_join(tox->m, tox_group_peer_join_handler);
932
1.46k
    gc_callback_peer_exit(tox->m, tox_group_peer_exit_handler);
933
1.46k
    gc_callback_self_join(tox->m, tox_group_self_join_handler);
934
1.46k
    gc_callback_rejected(tox->m, tox_group_join_fail_handler);
935
1.46k
    gc_callback_voice_state(tox->m, tox_group_voice_state_handler);
936
937
1.46k
    tox_unlock(tox);
938
939
1.46k
    SET_ERROR_PARAMETER(error, TOX_ERR_NEW_OK);
940
941
1.46k
    tox_options_free(default_options);
942
1.46k
    return tox;
943
1.96k
}
944
945
Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error)
946
0
{
947
0
    return tox_new_system(options, error, nullptr);
948
0
}
949
950
Tox *tox_new_testing(const Tox_Options *options, Tox_Err_New *error, const Tox_Options_Testing *testing, Tox_Err_New_Testing *testing_error)
951
1.99k
{
952
1.99k
    if (testing == nullptr) {
953
0
        SET_ERROR_PARAMETER(error, TOX_ERR_NEW_NULL);
954
0
        SET_ERROR_PARAMETER(testing_error, TOX_ERR_NEW_TESTING_NULL);
955
0
        return nullptr;
956
0
    }
957
958
1.99k
    if (testing->operating_system == nullptr) {
959
0
        SET_ERROR_PARAMETER(error, TOX_ERR_NEW_NULL);
960
0
        SET_ERROR_PARAMETER(testing_error, TOX_ERR_NEW_TESTING_NULL);
961
0
        return nullptr;
962
0
    }
963
964
1.99k
    const Tox_System *sys = testing->operating_system;
965
966
1.99k
    if (sys->rng == nullptr || sys->ns == nullptr || sys->mem == nullptr) {
967
0
        SET_ERROR_PARAMETER(error, TOX_ERR_NEW_NULL);
968
0
        SET_ERROR_PARAMETER(testing_error, TOX_ERR_NEW_TESTING_NULL);
969
0
        return nullptr;
970
0
    }
971
972
1.99k
    SET_ERROR_PARAMETER(testing_error, TOX_ERR_NEW_TESTING_OK);
973
1.99k
    return tox_new_system(options, error, sys);
974
1.99k
}
975
976
void tox_kill(Tox *tox)
977
1.46k
{
978
1.46k
    if (tox == nullptr) {
979
0
        return;
980
0
    }
981
982
1.46k
    tox_lock(tox);
983
1.46k
    LOGGER_ASSERT(tox->m->log, tox->toxav_object == nullptr, "Attempted to kill tox while toxav is still alive");
984
1.46k
    kill_groupchats(tox->m->conferences_object);
985
1.46k
    kill_messenger(tox->m);
986
1.46k
    mono_time_free(tox->sys.mem, tox->mono_time);
987
1.46k
    tox_unlock(tox);
988
989
1.46k
    if (tox->mutex != nullptr) {
990
0
        pthread_mutex_destroy(tox->mutex);
991
0
        mem_delete(tox->sys.mem, tox->mutex);
992
0
    }
993
994
1.46k
    mem_delete(tox->sys.mem, tox);
995
1.46k
}
996
997
static uint32_t end_size(void)
998
2.93k
{
999
2.93k
    return 2 * sizeof(uint32_t);
1000
2.93k
}
1001
1002
static void end_save(uint8_t *_Nonnull data)
1003
1.46k
{
1004
1.46k
    state_write_section_header(data, STATE_COOKIE_TYPE, 0, STATE_TYPE_END);
1005
1.46k
}
1006
1007
size_t tox_get_savedata_size(const Tox *tox)
1008
2.93k
{
1009
2.93k
    assert(tox != nullptr);
1010
2.93k
    tox_lock(tox);
1011
2.93k
    const size_t ret = 2 * sizeof(uint32_t)
1012
2.93k
                       + messenger_size(tox->m)
1013
2.93k
                       + conferences_size(tox->m->conferences_object)
1014
2.93k
                       + end_size();
1015
2.93k
    tox_unlock(tox);
1016
2.93k
    return ret;
1017
2.93k
}
1018
1019
void tox_get_savedata(const Tox *tox, uint8_t *savedata)
1020
1.46k
{
1021
1.46k
    assert(tox != nullptr);
1022
1023
1.46k
    if (savedata == nullptr) {
1024
0
        return;
1025
0
    }
1026
1027
1.46k
    memzero(savedata, tox_get_savedata_size(tox));
1028
1029
1.46k
    tox_lock(tox);
1030
1031
1.46k
    const uint32_t size32 = sizeof(uint32_t);
1032
1033
    // write cookie
1034
1.46k
    memzero(savedata, size32);
1035
1.46k
    savedata += size32;
1036
1.46k
    host_to_lendian_bytes32(savedata, STATE_COOKIE_GLOBAL);
1037
1.46k
    savedata += size32;
1038
1039
1.46k
    savedata = messenger_save(tox->m, savedata);
1040
1.46k
    savedata = conferences_save(tox->m->conferences_object, savedata);
1041
1.46k
    end_save(savedata);
1042
1043
1.46k
    tox_unlock(tox);
1044
1.46k
}
1045
1046
static int32_t resolve_bootstrap_node(Tox *_Nullable tox, const char *_Nullable host, uint16_t port, const uint8_t public_key[TOX_PUBLIC_KEY_SIZE],
1047
                                      IP_Port *_Nonnull *root, Tox_Err_Bootstrap *_Nullable error)
1048
0
{
1049
0
    assert(tox != nullptr);
1050
0
    assert(root != nullptr);
1051
1052
0
    if (host == nullptr || public_key == nullptr) {
1053
0
        SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_NULL);
1054
0
        return -1;
1055
0
    }
1056
1057
0
    if (port == 0) {
1058
0
        SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_PORT);
1059
0
        return -1;
1060
0
    }
1061
1062
0
    const int32_t count = net_getipport(tox->sys.ns, tox->sys.mem, host, root, TOX_SOCK_DGRAM, tox->m->options.dns_enabled);
1063
1064
0
    if (count < 1) {
1065
0
        LOGGER_DEBUG(tox->m->log, "could not resolve bootstrap node '%s'", host);
1066
0
        net_freeipport(tox->sys.mem, *root);
1067
0
        SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST);
1068
0
        return -1;
1069
0
    }
1070
1071
0
    assert(*root != nullptr);
1072
0
    return count;
1073
0
}
1074
1075
bool tox_bootstrap(Tox *tox, const char *host, uint16_t port, const uint8_t public_key[TOX_PUBLIC_KEY_SIZE], Tox_Err_Bootstrap *error)
1076
0
{
1077
0
    IP_Port *root;
1078
0
    const int32_t count = resolve_bootstrap_node(tox, host, port, public_key, &root, error);
1079
1080
0
    if (count == -1) {
1081
0
        return false;
1082
0
    }
1083
1084
0
    tox_lock(tox);
1085
0
    assert(count >= 0);
1086
0
    bool onion_success = false;
1087
    // UDP bootstrap is default success if it's disabled (because we don't even try).
1088
0
    bool udp_success = tox->m->options.udp_disabled;
1089
1090
0
    for (int32_t i = 0; i < count; ++i) {
1091
0
        if (!tox->m->options.ipv6enabled && net_family_is_ipv6(root[i].ip.family)) {
1092
            // We can't use ipv6 when it's disabled.
1093
0
            continue;
1094
0
        }
1095
1096
0
        root[i].port = net_htons(port);
1097
1098
0
        if (onion_add_bs_path_node(tox->m->onion_c, &root[i], public_key)) {
1099
            // If UDP is enabled, the caller cares about whether any of the
1100
            // bootstrap calls below will succeed. In TCP-only mode, adding
1101
            // onion path nodes successfully is sufficient.
1102
0
            onion_success = true;
1103
0
        }
1104
1105
0
        if (!tox->m->options.udp_disabled) {
1106
0
            if (dht_bootstrap(tox->m->dht, &root[i], public_key)) {
1107
                // If any of the bootstrap calls worked, we call it success.
1108
0
                udp_success = true;
1109
0
            }
1110
0
        }
1111
0
    }
1112
1113
0
    tox_unlock(tox);
1114
1115
0
    net_freeipport(tox->sys.mem, root);
1116
1117
0
    if (count == 0 || !onion_success || !udp_success) {
1118
0
        LOGGER_DEBUG(tox->m->log, "bootstrap node '%s' resolved to %d IP_Ports%s (onion: %s, UDP: %s)",
1119
0
                     host, count,
1120
0
                     count > 0 ? ", but failed to bootstrap with any of them" : "",
1121
0
                     onion_success ? "success" : "FAILURE",
1122
0
                     tox->m->options.udp_disabled ? "disabled" : (udp_success ? "success" : "FAILURE"));
1123
0
        SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST);
1124
0
        return false;
1125
0
    }
1126
1127
0
    SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK);
1128
0
    return true;
1129
0
}
1130
1131
bool tox_add_tcp_relay(Tox *tox, const char *host, uint16_t port, const uint8_t public_key[TOX_PUBLIC_KEY_SIZE],
1132
                       Tox_Err_Bootstrap *error)
1133
0
{
1134
0
    IP_Port *root;
1135
0
    const int32_t count = resolve_bootstrap_node(tox, host, port, public_key, &root, error);
1136
1137
0
    if (count == -1) {
1138
0
        return false;
1139
0
    }
1140
1141
0
    tox_lock(tox);
1142
0
    assert(count >= 0);
1143
1144
0
    for (int32_t i = 0; i < count; ++i) {
1145
0
        root[i].port = net_htons(port);
1146
1147
0
        add_tcp_relay(tox->m->net_crypto, &root[i], public_key);
1148
0
    }
1149
1150
0
    tox_unlock(tox);
1151
1152
0
    net_freeipport(tox->sys.mem, root);
1153
1154
0
    if (count == 0) {
1155
0
        SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST);
1156
0
        return false;
1157
0
    }
1158
1159
0
    SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK);
1160
0
    return true;
1161
0
}
1162
1163
Tox_Connection tox_self_get_connection_status(const Tox *tox)
1164
0
{
1165
0
    assert(tox != nullptr);
1166
0
    tox_lock(tox);
1167
0
    const Onion_Connection_Status ret = onion_connection_status(tox->m->onion_c);
1168
0
    tox_unlock(tox);
1169
1170
0
    switch (ret) {
1171
0
        case ONION_CONNECTION_STATUS_NONE:
1172
0
            return TOX_CONNECTION_NONE;
1173
1174
0
        case ONION_CONNECTION_STATUS_TCP:
1175
0
            return TOX_CONNECTION_TCP;
1176
1177
0
        case ONION_CONNECTION_STATUS_UDP:
1178
0
            return TOX_CONNECTION_UDP;
1179
0
    }
1180
1181
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %u", ret);
1182
0
    return TOX_CONNECTION_NONE;
1183
0
}
1184
1185
void tox_callback_self_connection_status(Tox *tox, tox_self_connection_status_cb *callback)
1186
0
{
1187
0
    assert(tox != nullptr);
1188
0
    tox->self_connection_status_callback = callback;
1189
0
}
1190
1191
uint32_t tox_iteration_interval(const Tox *tox)
1192
0
{
1193
0
    assert(tox != nullptr);
1194
0
    tox_lock(tox);
1195
0
    uint32_t ret = messenger_run_interval(tox->m);
1196
1197
0
    if (m_is_receiving_file(tox->m)) {
1198
0
        ret = 1;
1199
0
    }
1200
1201
0
    tox_unlock(tox);
1202
0
    return ret;
1203
0
}
1204
1205
void tox_iterate(Tox *tox, void *user_data)
1206
0
{
1207
0
    assert(tox != nullptr);
1208
0
    tox_lock(tox);
1209
1210
0
    mono_time_update(tox->mono_time);
1211
1212
0
    struct Tox_Userdata tox_data = { tox, user_data };
1213
0
    do_messenger(tox->m, &tox_data);
1214
0
    do_groupchats(tox->m->conferences_object, &tox_data);
1215
1216
0
    tox_unlock(tox);
1217
0
}
1218
1219
void tox_self_get_address(const Tox *tox, uint8_t address[TOX_ADDRESS_SIZE])
1220
0
{
1221
0
    assert(tox != nullptr);
1222
1223
0
    if (address != nullptr) {
1224
0
        tox_lock(tox);
1225
0
        getaddress(tox->m, address);
1226
0
        tox_unlock(tox);
1227
0
    }
1228
0
}
1229
1230
void tox_self_set_nospam(Tox *tox, uint32_t nospam)
1231
0
{
1232
0
    assert(tox != nullptr);
1233
0
    tox_lock(tox);
1234
0
    set_nospam(tox->m->fr, net_htonl(nospam));
1235
0
    tox_unlock(tox);
1236
0
}
1237
1238
uint32_t tox_self_get_nospam(const Tox *tox)
1239
0
{
1240
0
    assert(tox != nullptr);
1241
0
    tox_lock(tox);
1242
0
    const uint32_t ret = net_ntohl(get_nospam(tox->m->fr));
1243
0
    tox_unlock(tox);
1244
0
    return ret;
1245
0
}
1246
1247
void tox_self_get_public_key(const Tox *tox, uint8_t public_key[TOX_PUBLIC_KEY_SIZE])
1248
0
{
1249
0
    assert(tox != nullptr);
1250
1251
0
    if (public_key != nullptr) {
1252
0
        tox_lock(tox);
1253
0
        memcpy(public_key, nc_get_self_public_key(tox->m->net_crypto), CRYPTO_PUBLIC_KEY_SIZE);
1254
0
        tox_unlock(tox);
1255
0
    }
1256
0
}
1257
1258
void tox_self_get_secret_key(const Tox *tox, uint8_t secret_key[TOX_SECRET_KEY_SIZE])
1259
0
{
1260
0
    assert(tox != nullptr);
1261
1262
0
    if (secret_key != nullptr) {
1263
0
        tox_lock(tox);
1264
0
        memcpy(secret_key, nc_get_self_secret_key(tox->m->net_crypto), CRYPTO_SECRET_KEY_SIZE);
1265
0
        tox_unlock(tox);
1266
0
    }
1267
0
}
1268
1269
bool tox_self_set_name(Tox *tox, const uint8_t *name, size_t length, Tox_Err_Set_Info *error)
1270
0
{
1271
0
    assert(tox != nullptr);
1272
1273
0
    if (name == nullptr && length != 0) {
1274
0
        SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_NULL);
1275
0
        return false;
1276
0
    }
1277
1278
0
    tox_lock(tox);
1279
1280
0
    if (setname(tox->m, name, length) == 0) {
1281
        // TODO(irungentoo): function to set different per group names?
1282
0
        send_name_all_groups(tox->m->conferences_object);
1283
0
        SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_OK);
1284
0
        tox_unlock(tox);
1285
0
        return true;
1286
0
    }
1287
1288
0
    SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_TOO_LONG);
1289
0
    tox_unlock(tox);
1290
0
    return false;
1291
0
}
1292
1293
size_t tox_self_get_name_size(const Tox *tox)
1294
0
{
1295
0
    assert(tox != nullptr);
1296
0
    tox_lock(tox);
1297
0
    const size_t ret = m_get_self_name_size(tox->m);
1298
0
    tox_unlock(tox);
1299
0
    return ret;
1300
0
}
1301
1302
void tox_self_get_name(const Tox *tox, uint8_t *name)
1303
0
{
1304
0
    assert(tox != nullptr);
1305
1306
0
    if (name != nullptr) {
1307
0
        tox_lock(tox);
1308
0
        getself_name(tox->m, name);
1309
0
        tox_unlock(tox);
1310
0
    }
1311
0
}
1312
1313
bool tox_self_set_status_message(Tox *tox, const uint8_t *status_message, size_t length, Tox_Err_Set_Info *error)
1314
0
{
1315
0
    assert(tox != nullptr);
1316
1317
0
    if (status_message == nullptr && length != 0) {
1318
0
        SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_NULL);
1319
0
        return false;
1320
0
    }
1321
1322
0
    tox_lock(tox);
1323
1324
0
    if (m_set_statusmessage(tox->m, status_message, length) == 0) {
1325
0
        SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_OK);
1326
0
        tox_unlock(tox);
1327
0
        return true;
1328
0
    }
1329
1330
0
    SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_TOO_LONG);
1331
0
    tox_unlock(tox);
1332
0
    return false;
1333
0
}
1334
1335
size_t tox_self_get_status_message_size(const Tox *tox)
1336
0
{
1337
0
    assert(tox != nullptr);
1338
0
    tox_lock(tox);
1339
0
    const size_t ret = m_get_self_statusmessage_size(tox->m);
1340
0
    tox_unlock(tox);
1341
0
    return ret;
1342
0
}
1343
1344
void tox_self_get_status_message(const Tox *tox, uint8_t *status_message)
1345
0
{
1346
0
    assert(tox != nullptr);
1347
1348
0
    if (status_message != nullptr) {
1349
0
        tox_lock(tox);
1350
0
        m_copy_self_statusmessage(tox->m, status_message);
1351
0
        tox_unlock(tox);
1352
0
    }
1353
0
}
1354
1355
void tox_self_set_status(Tox *tox, Tox_User_Status status)
1356
0
{
1357
0
    assert(tox != nullptr);
1358
0
    tox_lock(tox);
1359
0
    m_set_userstatus(tox->m, status);
1360
0
    tox_unlock(tox);
1361
0
}
1362
1363
Tox_User_Status tox_self_get_status(const Tox *tox)
1364
0
{
1365
0
    assert(tox != nullptr);
1366
0
    tox_lock(tox);
1367
0
    const uint8_t status = m_get_self_userstatus(tox->m);
1368
0
    tox_unlock(tox);
1369
0
    return (Tox_User_Status)status;
1370
0
}
1371
1372
static void set_friend_error(const Logger *_Nonnull log, int32_t ret, Tox_Err_Friend_Add *_Nullable error)
1373
0
{
1374
0
    switch (ret) {
1375
0
        case FAERR_TOOLONG: {
1376
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_TOO_LONG);
1377
0
            break;
1378
0
        }
1379
1380
0
        case FAERR_NOMESSAGE: {
1381
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NO_MESSAGE);
1382
0
            break;
1383
0
        }
1384
1385
0
        case FAERR_OWNKEY: {
1386
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OWN_KEY);
1387
0
            break;
1388
0
        }
1389
1390
0
        case FAERR_ALREADYSENT: {
1391
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_ALREADY_SENT);
1392
0
            break;
1393
0
        }
1394
1395
0
        case FAERR_BADCHECKSUM: {
1396
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_BAD_CHECKSUM);
1397
0
            break;
1398
0
        }
1399
1400
0
        case FAERR_SETNEWNOSPAM: {
1401
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM);
1402
0
            break;
1403
0
        }
1404
1405
0
        case FAERR_NOMEM: {
1406
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_MALLOC);
1407
0
            break;
1408
0
        }
1409
1410
0
        default: {
1411
            /* can't happen */
1412
0
            LOGGER_FATAL(log, "impossible return value: %d", ret);
1413
0
            break;
1414
0
        }
1415
0
    }
1416
0
}
1417
1418
uint32_t tox_friend_add(Tox *tox, const uint8_t address[TOX_ADDRESS_SIZE], const uint8_t *message, size_t length,
1419
                        Tox_Err_Friend_Add *error)
1420
0
{
1421
0
    assert(tox != nullptr);
1422
1423
0
    if (address == nullptr || message == nullptr) {
1424
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NULL);
1425
0
        return UINT32_MAX;
1426
0
    }
1427
1428
0
    tox_lock(tox);
1429
0
    const int32_t ret = m_addfriend(tox->m, address, message, length);
1430
1431
0
    if (ret >= 0) {
1432
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OK);
1433
0
        tox_unlock(tox);
1434
0
        return (uint32_t)ret;
1435
0
    }
1436
1437
0
    set_friend_error(tox->m->log, ret, error);
1438
0
    tox_unlock(tox);
1439
0
    return UINT32_MAX;
1440
0
}
1441
1442
uint32_t tox_friend_add_norequest(Tox *tox, const uint8_t public_key[TOX_PUBLIC_KEY_SIZE], Tox_Err_Friend_Add *error)
1443
0
{
1444
0
    assert(tox != nullptr);
1445
1446
0
    if (public_key == nullptr) {
1447
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NULL);
1448
0
        return UINT32_MAX;
1449
0
    }
1450
1451
0
    tox_lock(tox);
1452
0
    const int32_t ret = m_addfriend_norequest(tox->m, public_key);
1453
1454
0
    if (ret >= 0) {
1455
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OK);
1456
0
        tox_unlock(tox);
1457
0
        return (uint32_t)ret;
1458
0
    }
1459
1460
0
    set_friend_error(tox->m->log, ret, error);
1461
0
    tox_unlock(tox);
1462
0
    return UINT32_MAX;
1463
0
}
1464
1465
bool tox_friend_delete(Tox *tox, uint32_t friend_number, Tox_Err_Friend_Delete *error)
1466
0
{
1467
0
    assert(tox != nullptr);
1468
0
    tox_lock(tox);
1469
0
    const int ret = m_delfriend(tox->m, friend_number);
1470
0
    tox_unlock(tox);
1471
1472
    // TODO(irungentoo): handle if realloc fails?
1473
0
    if (ret == -1) {
1474
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_DELETE_FRIEND_NOT_FOUND);
1475
0
        return false;
1476
0
    }
1477
1478
0
    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_DELETE_OK);
1479
0
    return true;
1480
0
}
1481
1482
uint32_t tox_friend_by_public_key(const Tox *tox, const uint8_t public_key[TOX_PUBLIC_KEY_SIZE], Tox_Err_Friend_By_Public_Key *error)
1483
0
{
1484
0
    assert(tox != nullptr);
1485
1486
0
    if (public_key == nullptr) {
1487
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_NULL);
1488
0
        return UINT32_MAX;
1489
0
    }
1490
1491
0
    tox_lock(tox);
1492
0
    const int32_t ret = getfriend_id(tox->m, public_key);
1493
0
    tox_unlock(tox);
1494
1495
0
    if (ret == -1) {
1496
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_NOT_FOUND);
1497
0
        return UINT32_MAX;
1498
0
    }
1499
1500
0
    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK);
1501
0
    assert(ret >= 0);
1502
0
    return (uint32_t)ret;
1503
0
}
1504
1505
bool tox_friend_get_public_key(const Tox *tox, uint32_t friend_number, uint8_t public_key[TOX_PUBLIC_KEY_SIZE],
1506
                               Tox_Err_Friend_Get_Public_Key *error)
1507
0
{
1508
0
    assert(tox != nullptr);
1509
1510
0
    if (public_key == nullptr) {
1511
0
        return false;
1512
0
    }
1513
1514
0
    tox_lock(tox);
1515
1516
0
    if (get_real_pk(tox->m, friend_number, public_key) == -1) {
1517
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_PUBLIC_KEY_FRIEND_NOT_FOUND);
1518
0
        tox_unlock(tox);
1519
0
        return false;
1520
0
    }
1521
1522
0
    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK);
1523
0
    tox_unlock(tox);
1524
0
    return true;
1525
0
}
1526
1527
bool tox_friend_exists(const Tox *tox, uint32_t friend_number)
1528
0
{
1529
0
    assert(tox != nullptr);
1530
0
    tox_lock(tox);
1531
0
    const bool ret = m_friend_exists(tox->m, friend_number);
1532
0
    tox_unlock(tox);
1533
0
    return ret;
1534
0
}
1535
1536
uint64_t tox_friend_get_last_online(const Tox *tox, uint32_t friend_number, Tox_Err_Friend_Get_Last_Online *error)
1537
0
{
1538
0
    assert(tox != nullptr);
1539
0
    tox_lock(tox);
1540
0
    const uint64_t timestamp = m_get_last_online(tox->m, friend_number);
1541
0
    tox_unlock(tox);
1542
1543
0
    if (timestamp == UINT64_MAX) {
1544
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_LAST_ONLINE_FRIEND_NOT_FOUND);
1545
0
        return UINT64_MAX;
1546
0
    }
1547
1548
0
    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_LAST_ONLINE_OK);
1549
0
    return timestamp;
1550
0
}
1551
1552
size_t tox_self_get_friend_list_size(const Tox *tox)
1553
0
{
1554
0
    assert(tox != nullptr);
1555
0
    tox_lock(tox);
1556
0
    const size_t ret = count_friendlist(tox->m);
1557
0
    tox_unlock(tox);
1558
0
    return ret;
1559
0
}
1560
1561
void tox_self_get_friend_list(const Tox *tox, uint32_t *friend_list)
1562
0
{
1563
0
    assert(tox != nullptr);
1564
1565
0
    if (friend_list != nullptr) {
1566
0
        tox_lock(tox);
1567
        // TODO(irungentoo): size parameter?
1568
0
        copy_friendlist(tox->m, friend_list, count_friendlist(tox->m));
1569
0
        tox_unlock(tox);
1570
0
    }
1571
0
}
1572
1573
size_t tox_friend_get_name_size(const Tox *tox, uint32_t friend_number, Tox_Err_Friend_Query *error)
1574
0
{
1575
0
    assert(tox != nullptr);
1576
0
    tox_lock(tox);
1577
0
    const int ret = m_get_name_size(tox->m, friend_number);
1578
0
    tox_unlock(tox);
1579
1580
0
    if (ret == -1) {
1581
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
1582
0
        return SIZE_MAX;
1583
0
    }
1584
1585
0
    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);
1586
0
    return ret;
1587
0
}
1588
1589
bool tox_friend_get_name(const Tox *tox, uint32_t friend_number, uint8_t *name, Tox_Err_Friend_Query *error)
1590
0
{
1591
0
    assert(tox != nullptr);
1592
1593
0
    if (name == nullptr) {
1594
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_NULL);
1595
0
        return false;
1596
0
    }
1597
1598
0
    tox_lock(tox);
1599
0
    const int ret = getname(tox->m, friend_number, name);
1600
0
    tox_unlock(tox);
1601
1602
0
    if (ret == -1) {
1603
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
1604
0
        return false;
1605
0
    }
1606
1607
0
    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);
1608
0
    return true;
1609
0
}
1610
1611
void tox_callback_friend_name(Tox *tox, tox_friend_name_cb *callback)
1612
0
{
1613
0
    assert(tox != nullptr);
1614
0
    tox->friend_name_callback = callback;
1615
0
}
1616
1617
size_t tox_friend_get_status_message_size(const Tox *tox, uint32_t friend_number, Tox_Err_Friend_Query *error)
1618
0
{
1619
0
    assert(tox != nullptr);
1620
0
    tox_lock(tox);
1621
0
    const int ret = m_get_statusmessage_size(tox->m, friend_number);
1622
0
    tox_unlock(tox);
1623
1624
0
    if (ret == -1) {
1625
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
1626
0
        return SIZE_MAX;
1627
0
    }
1628
1629
0
    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);
1630
0
    return ret;
1631
0
}
1632
1633
bool tox_friend_get_status_message(const Tox *tox, uint32_t friend_number, uint8_t *status_message,
1634
                                   Tox_Err_Friend_Query *error)
1635
0
{
1636
0
    assert(tox != nullptr);
1637
1638
0
    if (status_message == nullptr) {
1639
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_NULL);
1640
0
        return false;
1641
0
    }
1642
1643
0
    tox_lock(tox);
1644
0
    const int size = m_get_statusmessage_size(tox->m, friend_number);
1645
1646
0
    if (size == -1) {
1647
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
1648
0
        tox_unlock(tox);
1649
0
        return false;
1650
0
    }
1651
1652
0
    const int ret = m_copy_statusmessage(tox->m, friend_number, status_message, size);
1653
0
    LOGGER_ASSERT(tox->m->log, ret == size, "concurrency problem: friend status message changed");
1654
1655
0
    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);
1656
0
    tox_unlock(tox);
1657
0
    return ret == size;
1658
0
}
1659
1660
void tox_callback_friend_status_message(Tox *tox, tox_friend_status_message_cb *callback)
1661
0
{
1662
0
    assert(tox != nullptr);
1663
0
    tox->friend_status_message_callback = callback;
1664
0
}
1665
1666
Tox_User_Status tox_friend_get_status(const Tox *tox, uint32_t friend_number, Tox_Err_Friend_Query *error)
1667
0
{
1668
0
    assert(tox != nullptr);
1669
0
    tox_lock(tox);
1670
0
    const int ret = m_get_userstatus(tox->m, friend_number);
1671
0
    tox_unlock(tox);
1672
1673
0
    if (ret == USERSTATUS_INVALID) {
1674
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
1675
0
        return TOX_USER_STATUS_NONE;
1676
0
    }
1677
1678
0
    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);
1679
0
    return (Tox_User_Status)ret;
1680
0
}
1681
1682
void tox_callback_friend_status(Tox *tox, tox_friend_status_cb *callback)
1683
0
{
1684
0
    assert(tox != nullptr);
1685
0
    tox->friend_status_callback = callback;
1686
0
}
1687
1688
Tox_Connection tox_friend_get_connection_status(const Tox *tox, uint32_t friend_number, Tox_Err_Friend_Query *error)
1689
0
{
1690
0
    assert(tox != nullptr);
1691
0
    tox_lock(tox);
1692
0
    const int ret = m_get_friend_connectionstatus(tox->m, friend_number);
1693
0
    tox_unlock(tox);
1694
1695
0
    if (ret == -1) {
1696
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
1697
0
        return TOX_CONNECTION_NONE;
1698
0
    }
1699
1700
0
    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);
1701
0
    return (Tox_Connection)ret;
1702
0
}
1703
1704
void tox_callback_friend_connection_status(Tox *tox, tox_friend_connection_status_cb *callback)
1705
0
{
1706
0
    assert(tox != nullptr);
1707
0
    tox->friend_connection_status_callback = callback;
1708
0
}
1709
1710
bool tox_friend_get_typing(const Tox *tox, uint32_t friend_number, Tox_Err_Friend_Query *error)
1711
0
{
1712
0
    assert(tox != nullptr);
1713
0
    tox_lock(tox);
1714
0
    const int ret = m_get_istyping(tox->m, friend_number);
1715
0
    tox_unlock(tox);
1716
1717
0
    if (ret == -1) {
1718
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
1719
0
        return false;
1720
0
    }
1721
1722
0
    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);
1723
0
    return ret != 0;
1724
0
}
1725
1726
void tox_callback_friend_typing(Tox *tox, tox_friend_typing_cb *callback)
1727
0
{
1728
0
    assert(tox != nullptr);
1729
0
    tox->friend_typing_callback = callback;
1730
0
}
1731
1732
bool tox_self_set_typing(Tox *tox, uint32_t friend_number, bool typing, Tox_Err_Set_Typing *error)
1733
0
{
1734
0
    assert(tox != nullptr);
1735
0
    tox_lock(tox);
1736
1737
0
    if (m_set_usertyping(tox->m, friend_number, typing) == -1) {
1738
0
        SET_ERROR_PARAMETER(error, TOX_ERR_SET_TYPING_FRIEND_NOT_FOUND);
1739
0
        tox_unlock(tox);
1740
0
        return false;
1741
0
    }
1742
1743
0
    SET_ERROR_PARAMETER(error, TOX_ERR_SET_TYPING_OK);
1744
0
    tox_unlock(tox);
1745
0
    return true;
1746
0
}
1747
1748
static void set_message_error(const Logger *_Nonnull log, int ret, Tox_Err_Friend_Send_Message *_Nullable error)
1749
0
{
1750
0
    switch (ret) {
1751
0
        case 0: {
1752
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_OK);
1753
0
            break;
1754
0
        }
1755
1756
0
        case -1: {
1757
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_FOUND);
1758
0
            break;
1759
0
        }
1760
1761
0
        case -2: {
1762
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_TOO_LONG);
1763
0
            break;
1764
0
        }
1765
1766
0
        case -3: {
1767
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_CONNECTED);
1768
0
            break;
1769
0
        }
1770
1771
0
        case -4: {
1772
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ);
1773
0
            break;
1774
0
        }
1775
1776
0
        case -5: {
1777
0
            LOGGER_FATAL(log, "impossible: Messenger and Tox disagree on message types");
1778
0
            break;
1779
0
        }
1780
1781
0
        default: {
1782
            /* can't happen */
1783
0
            LOGGER_FATAL(log, "impossible return value: %d", ret);
1784
0
            break;
1785
0
        }
1786
0
    }
1787
0
}
1788
1789
uint32_t tox_friend_send_message(Tox *tox, uint32_t friend_number, Tox_Message_Type type, const uint8_t *message,
1790
                                 size_t length, Tox_Err_Friend_Send_Message *error)
1791
0
{
1792
0
    assert(tox != nullptr);
1793
1794
0
    if (message == nullptr) {
1795
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_NULL);
1796
0
        return 0;
1797
0
    }
1798
1799
0
    if (length == 0) {
1800
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_EMPTY);
1801
0
        return 0;
1802
0
    }
1803
1804
0
    uint32_t message_id = 0;
1805
0
    tox_lock(tox);
1806
0
    set_message_error(tox->m->log, m_send_message_generic(tox->m, friend_number, type, message, length, &message_id),
1807
0
                      error);
1808
0
    tox_unlock(tox);
1809
0
    return message_id;
1810
0
}
1811
1812
void tox_callback_friend_read_receipt(Tox *tox, tox_friend_read_receipt_cb *callback)
1813
0
{
1814
0
    assert(tox != nullptr);
1815
0
    tox->friend_read_receipt_callback = callback;
1816
0
}
1817
1818
void tox_callback_friend_request(Tox *tox, tox_friend_request_cb *callback)
1819
0
{
1820
0
    assert(tox != nullptr);
1821
0
    tox->friend_request_callback = callback;
1822
0
}
1823
1824
void tox_callback_friend_message(Tox *tox, tox_friend_message_cb *callback)
1825
0
{
1826
0
    assert(tox != nullptr);
1827
0
    tox->friend_message_callback = callback;
1828
0
}
1829
1830
bool tox_hash(uint8_t hash[TOX_HASH_LENGTH], const uint8_t *data, size_t length)
1831
0
{
1832
0
    if (hash == nullptr || (data == nullptr && length != 0)) {
1833
0
        return false;
1834
0
    }
1835
1836
0
    crypto_sha256(hash, data, length);
1837
0
    return true;
1838
0
}
1839
1840
bool tox_file_control(Tox *tox, uint32_t friend_number, uint32_t file_number, Tox_File_Control control,
1841
                      Tox_Err_File_Control *error)
1842
0
{
1843
0
    assert(tox != nullptr);
1844
0
    tox_lock(tox);
1845
0
    const int ret = file_control(tox->m, friend_number, file_number, control);
1846
0
    tox_unlock(tox);
1847
1848
0
    if (ret == 0) {
1849
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_OK);
1850
0
        return true;
1851
0
    }
1852
1853
0
    switch (ret) {
1854
0
        case -1: {
1855
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND);
1856
0
            return false;
1857
0
        }
1858
1859
0
        case -2: {
1860
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED);
1861
0
            return false;
1862
0
        }
1863
1864
0
        case -3: {
1865
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_NOT_FOUND);
1866
0
            return false;
1867
0
        }
1868
1869
0
        case -4: {
1870
            /* can't happen (this code is returned if `control` is invalid type) */
1871
0
            LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
1872
0
            return false;
1873
0
        }
1874
1875
0
        case -5: {
1876
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_ALREADY_PAUSED);
1877
0
            return false;
1878
0
        }
1879
1880
0
        case -6: {
1881
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_DENIED);
1882
0
            return false;
1883
0
        }
1884
1885
0
        case -7: {
1886
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_NOT_PAUSED);
1887
0
            return false;
1888
0
        }
1889
1890
0
        case -8: {
1891
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_SENDQ);
1892
0
            return false;
1893
0
        }
1894
0
    }
1895
1896
    /* can't happen */
1897
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
1898
1899
0
    return false;
1900
0
}
1901
1902
bool tox_file_seek(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position,
1903
                   Tox_Err_File_Seek *error)
1904
0
{
1905
0
    assert(tox != nullptr);
1906
0
    tox_lock(tox);
1907
0
    const int ret = file_seek(tox->m, friend_number, file_number, position);
1908
0
    tox_unlock(tox);
1909
1910
0
    if (ret == 0) {
1911
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_OK);
1912
0
        return true;
1913
0
    }
1914
1915
0
    switch (ret) {
1916
0
        case -1: {
1917
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_FRIEND_NOT_FOUND);
1918
0
            return false;
1919
0
        }
1920
1921
0
        case -2: {
1922
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_FRIEND_NOT_CONNECTED);
1923
0
            return false;
1924
0
        }
1925
1926
0
        case -3: {
1927
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_NOT_FOUND);
1928
0
            return false;
1929
0
        }
1930
1931
0
        case -4: // fall-through
1932
0
        case -5: {
1933
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_DENIED);
1934
0
            return false;
1935
0
        }
1936
1937
0
        case -6: {
1938
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_INVALID_POSITION);
1939
0
            return false;
1940
0
        }
1941
1942
0
        case -8: {
1943
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_SENDQ);
1944
0
            return false;
1945
0
        }
1946
0
    }
1947
1948
    /* can't happen */
1949
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
1950
1951
0
    return false;
1952
0
}
1953
1954
void tox_callback_file_recv_control(Tox *tox, tox_file_recv_control_cb *callback)
1955
0
{
1956
0
    assert(tox != nullptr);
1957
0
    tox->file_recv_control_callback = callback;
1958
0
}
1959
1960
bool tox_file_get_file_id(const Tox *tox, uint32_t friend_number, uint32_t file_number, uint8_t file_id[TOX_FILE_ID_LENGTH],
1961
                          Tox_Err_File_Get *error)
1962
0
{
1963
0
    assert(tox != nullptr);
1964
1965
0
    if (file_id == nullptr) {
1966
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_NULL);
1967
0
        return false;
1968
0
    }
1969
1970
0
    tox_lock(tox);
1971
0
    const int ret = file_get_id(tox->m, friend_number, file_number, file_id);
1972
0
    tox_unlock(tox);
1973
1974
0
    if (ret == 0) {
1975
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_OK);
1976
0
        return true;
1977
0
    }
1978
1979
0
    if (ret == -1) {
1980
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_FRIEND_NOT_FOUND);
1981
0
    } else {
1982
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_NOT_FOUND);
1983
0
    }
1984
1985
0
    return false;
1986
0
}
1987
1988
uint32_t tox_file_send(Tox *tox, uint32_t friend_number, uint32_t kind, uint64_t file_size, const uint8_t file_id[TOX_FILE_ID_LENGTH],
1989
                       const uint8_t *filename, size_t filename_length, Tox_Err_File_Send *error)
1990
0
{
1991
0
    assert(tox != nullptr);
1992
1993
0
    if (filename == nullptr && filename_length != 0) {
1994
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NULL);
1995
0
        return UINT32_MAX;
1996
0
    }
1997
1998
0
    uint8_t f_id[FILE_ID_LENGTH];
1999
2000
0
    if (file_id == nullptr) {
2001
        /* Tox keys are 32 bytes like FILE_ID_LENGTH. */
2002
0
        new_symmetric_key(tox->sys.rng, f_id);
2003
0
        file_id = f_id;
2004
0
    }
2005
2006
0
    tox_lock(tox);
2007
0
    const long int file_num = new_filesender(tox->m, friend_number, kind, file_size, file_id, filename, filename_length);
2008
0
    tox_unlock(tox);
2009
2010
0
    if (file_num >= 0) {
2011
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_OK);
2012
0
        return file_num;
2013
0
    }
2014
2015
0
    switch (file_num) {
2016
0
        case -1: {
2017
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND);
2018
0
            return UINT32_MAX;
2019
0
        }
2020
2021
0
        case -2: {
2022
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NAME_TOO_LONG);
2023
0
            return UINT32_MAX;
2024
0
        }
2025
2026
0
        case -3: {
2027
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_TOO_MANY);
2028
0
            return UINT32_MAX;
2029
0
        }
2030
2031
0
        case -4: {
2032
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED);
2033
0
            return UINT32_MAX;
2034
0
        }
2035
0
    }
2036
2037
    /* can't happen */
2038
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %ld", file_num);
2039
2040
0
    return UINT32_MAX;
2041
0
}
2042
2043
bool tox_file_send_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, const uint8_t *data,
2044
                         size_t length, Tox_Err_File_Send_Chunk *error)
2045
0
{
2046
0
    assert(tox != nullptr);
2047
0
    tox_lock(tox);
2048
0
    const int ret = send_file_data(tox->m, friend_number, file_number, position, data, length);
2049
0
    tox_unlock(tox);
2050
2051
0
    if (ret == 0) {
2052
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_OK);
2053
0
        return true;
2054
0
    }
2055
2056
0
    switch (ret) {
2057
0
        case -1: {
2058
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_FOUND);
2059
0
            return false;
2060
0
        }
2061
2062
0
        case -2: {
2063
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED);
2064
0
            return false;
2065
0
        }
2066
2067
0
        case -3: {
2068
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND);
2069
0
            return false;
2070
0
        }
2071
2072
0
        case -4: {
2073
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING);
2074
0
            return false;
2075
0
        }
2076
2077
0
        case -5: {
2078
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_INVALID_LENGTH);
2079
0
            return false;
2080
0
        }
2081
2082
0
        case -6: {
2083
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_SENDQ);
2084
0
            return false;
2085
0
        }
2086
2087
0
        case -7: {
2088
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_WRONG_POSITION);
2089
0
            return false;
2090
0
        }
2091
0
    }
2092
2093
    /* can't happen */
2094
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
2095
2096
0
    return false;
2097
0
}
2098
2099
void tox_callback_file_chunk_request(Tox *tox, tox_file_chunk_request_cb *callback)
2100
0
{
2101
0
    assert(tox != nullptr);
2102
0
    tox->file_chunk_request_callback = callback;
2103
0
}
2104
2105
void tox_callback_file_recv(Tox *tox, tox_file_recv_cb *callback)
2106
0
{
2107
0
    assert(tox != nullptr);
2108
0
    tox->file_recv_callback = callback;
2109
0
}
2110
2111
void tox_callback_file_recv_chunk(Tox *tox, tox_file_recv_chunk_cb *callback)
2112
0
{
2113
0
    assert(tox != nullptr);
2114
0
    tox->file_recv_chunk_callback = callback;
2115
0
}
2116
2117
void tox_callback_conference_invite(Tox *tox, tox_conference_invite_cb *callback)
2118
0
{
2119
0
    assert(tox != nullptr);
2120
0
    tox->conference_invite_callback = callback;
2121
0
}
2122
2123
void tox_callback_conference_connected(Tox *tox, tox_conference_connected_cb *callback)
2124
0
{
2125
0
    assert(tox != nullptr);
2126
0
    tox->conference_connected_callback = callback;
2127
0
}
2128
2129
void tox_callback_conference_message(Tox *tox, tox_conference_message_cb *callback)
2130
0
{
2131
0
    assert(tox != nullptr);
2132
0
    tox->conference_message_callback = callback;
2133
0
}
2134
2135
void tox_callback_conference_title(Tox *tox, tox_conference_title_cb *callback)
2136
0
{
2137
0
    assert(tox != nullptr);
2138
0
    tox->conference_title_callback = callback;
2139
0
}
2140
2141
void tox_callback_conference_peer_name(Tox *tox, tox_conference_peer_name_cb *callback)
2142
0
{
2143
0
    assert(tox != nullptr);
2144
0
    tox->conference_peer_name_callback = callback;
2145
0
}
2146
2147
void tox_callback_conference_peer_list_changed(Tox *tox, tox_conference_peer_list_changed_cb *callback)
2148
0
{
2149
0
    assert(tox != nullptr);
2150
0
    tox->conference_peer_list_changed_callback = callback;
2151
0
}
2152
2153
uint32_t tox_conference_new(Tox *tox, Tox_Err_Conference_New *error)
2154
0
{
2155
0
    assert(tox != nullptr);
2156
0
    tox_lock(tox);
2157
0
    const int ret = add_groupchat(tox->m->conferences_object, tox->sys.rng, GROUPCHAT_TYPE_TEXT);
2158
0
    tox_unlock(tox);
2159
2160
0
    if (ret == -1) {
2161
0
        SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_NEW_INIT);
2162
0
        return UINT32_MAX;
2163
0
    }
2164
2165
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_NEW_OK);
2166
0
    return ret;
2167
0
}
2168
2169
bool tox_conference_delete(Tox *tox, uint32_t conference_number, Tox_Err_Conference_Delete *error)
2170
0
{
2171
0
    assert(tox != nullptr);
2172
0
    tox_lock(tox);
2173
0
    const bool ret = del_groupchat(tox->m->conferences_object, conference_number, true);
2174
0
    tox_unlock(tox);
2175
2176
0
    if (!ret) {
2177
0
        SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_DELETE_CONFERENCE_NOT_FOUND);
2178
0
        return false;
2179
0
    }
2180
2181
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_DELETE_OK);
2182
0
    return true;
2183
0
}
2184
2185
uint32_t tox_conference_peer_count(const Tox *tox, uint32_t conference_number, Tox_Err_Conference_Peer_Query *error)
2186
0
{
2187
0
    assert(tox != nullptr);
2188
0
    tox_lock(tox);
2189
0
    const int ret = group_number_peers(tox->m->conferences_object, conference_number, false);
2190
0
    tox_unlock(tox);
2191
2192
0
    if (ret == -1) {
2193
0
        SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
2194
0
        return UINT32_MAX;
2195
0
    }
2196
2197
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
2198
0
    return ret;
2199
0
}
2200
2201
size_t tox_conference_peer_get_name_size(const Tox *tox, uint32_t conference_number, uint32_t peer_number,
2202
        Tox_Err_Conference_Peer_Query *error)
2203
0
{
2204
0
    assert(tox != nullptr);
2205
0
    tox_lock(tox);
2206
0
    const int ret = group_peername_size(tox->m->conferences_object, conference_number, peer_number, false);
2207
0
    tox_unlock(tox);
2208
2209
0
    switch (ret) {
2210
0
        case -1: {
2211
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
2212
0
            return -1;
2213
0
        }
2214
2215
0
        case -2: {
2216
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
2217
0
            return -1;
2218
0
        }
2219
0
    }
2220
2221
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
2222
0
    return ret;
2223
0
}
2224
2225
bool tox_conference_peer_get_name(const Tox *tox, uint32_t conference_number, uint32_t peer_number, uint8_t *name,
2226
                                  Tox_Err_Conference_Peer_Query *error)
2227
0
{
2228
0
    assert(tox != nullptr);
2229
0
    tox_lock(tox);
2230
0
    const int ret = group_peername(tox->m->conferences_object, conference_number, peer_number, name, false);
2231
0
    tox_unlock(tox);
2232
2233
0
    switch (ret) {
2234
0
        case -1: {
2235
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
2236
0
            return false;
2237
0
        }
2238
2239
0
        case -2: {
2240
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
2241
0
            return false;
2242
0
        }
2243
0
    }
2244
2245
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
2246
0
    return true;
2247
0
}
2248
2249
bool tox_conference_peer_get_public_key(const Tox *tox, uint32_t conference_number, uint32_t peer_number,
2250
                                        uint8_t public_key[TOX_PUBLIC_KEY_SIZE], Tox_Err_Conference_Peer_Query *error)
2251
0
{
2252
0
    assert(tox != nullptr);
2253
0
    tox_lock(tox);
2254
0
    const int ret = group_peer_pubkey(tox->m->conferences_object, conference_number, peer_number, public_key, false);
2255
0
    tox_unlock(tox);
2256
2257
0
    switch (ret) {
2258
0
        case -1: {
2259
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
2260
0
            return false;
2261
0
        }
2262
2263
0
        case -2: {
2264
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
2265
0
            return false;
2266
0
        }
2267
0
    }
2268
2269
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
2270
0
    return true;
2271
0
}
2272
2273
bool tox_conference_peer_number_is_ours(const Tox *tox, uint32_t conference_number, uint32_t peer_number,
2274
                                        Tox_Err_Conference_Peer_Query *error)
2275
0
{
2276
0
    assert(tox != nullptr);
2277
0
    tox_lock(tox);
2278
0
    const int ret = group_peernumber_is_ours(tox->m->conferences_object, conference_number, peer_number);
2279
0
    tox_unlock(tox);
2280
2281
0
    switch (ret) {
2282
0
        case -1: {
2283
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
2284
0
            return false;
2285
0
        }
2286
2287
0
        case -2: {
2288
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
2289
0
            return false;
2290
0
        }
2291
2292
0
        case -3: {
2293
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_NO_CONNECTION);
2294
0
            return false;
2295
0
        }
2296
0
    }
2297
2298
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
2299
0
    return ret != 0;
2300
0
}
2301
2302
uint32_t tox_conference_offline_peer_count(const Tox *tox, uint32_t conference_number,
2303
        Tox_Err_Conference_Peer_Query *error)
2304
0
{
2305
0
    assert(tox != nullptr);
2306
0
    tox_lock(tox);
2307
0
    const int ret = group_number_peers(tox->m->conferences_object, conference_number, true);
2308
0
    tox_unlock(tox);
2309
2310
0
    if (ret == -1) {
2311
0
        SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
2312
0
        return UINT32_MAX;
2313
0
    }
2314
2315
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
2316
0
    return ret;
2317
0
}
2318
2319
size_t tox_conference_offline_peer_get_name_size(const Tox *tox, uint32_t conference_number,
2320
        uint32_t offline_peer_number,
2321
        Tox_Err_Conference_Peer_Query *error)
2322
0
{
2323
0
    assert(tox != nullptr);
2324
0
    tox_lock(tox);
2325
0
    const int ret = group_peername_size(tox->m->conferences_object, conference_number, offline_peer_number, true);
2326
0
    tox_unlock(tox);
2327
2328
0
    switch (ret) {
2329
0
        case -1: {
2330
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
2331
0
            return -1;
2332
0
        }
2333
2334
0
        case -2: {
2335
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
2336
0
            return -1;
2337
0
        }
2338
0
    }
2339
2340
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
2341
0
    return ret;
2342
0
}
2343
2344
bool tox_conference_offline_peer_get_name(const Tox *tox, uint32_t conference_number, uint32_t offline_peer_number,
2345
        uint8_t *name,
2346
        Tox_Err_Conference_Peer_Query *error)
2347
0
{
2348
0
    assert(tox != nullptr);
2349
0
    tox_lock(tox);
2350
0
    const int ret = group_peername(tox->m->conferences_object, conference_number, offline_peer_number, name, true);
2351
0
    tox_unlock(tox);
2352
2353
0
    switch (ret) {
2354
0
        case -1: {
2355
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
2356
0
            return false;
2357
0
        }
2358
2359
0
        case -2: {
2360
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
2361
0
            return false;
2362
0
        }
2363
0
    }
2364
2365
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
2366
0
    return true;
2367
0
}
2368
2369
bool tox_conference_offline_peer_get_public_key(const Tox *tox, uint32_t conference_number,
2370
        uint32_t offline_peer_number,
2371
        uint8_t public_key[TOX_PUBLIC_KEY_SIZE], Tox_Err_Conference_Peer_Query *error)
2372
0
{
2373
0
    assert(tox != nullptr);
2374
0
    tox_lock(tox);
2375
0
    const int ret = group_peer_pubkey(tox->m->conferences_object, conference_number, offline_peer_number, public_key, true);
2376
0
    tox_unlock(tox);
2377
2378
0
    switch (ret) {
2379
0
        case -1: {
2380
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
2381
0
            return false;
2382
0
        }
2383
2384
0
        case -2: {
2385
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
2386
0
            return false;
2387
0
        }
2388
0
    }
2389
2390
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
2391
0
    return true;
2392
0
}
2393
2394
uint64_t tox_conference_offline_peer_get_last_active(const Tox *tox, uint32_t conference_number,
2395
        uint32_t offline_peer_number,
2396
        Tox_Err_Conference_Peer_Query *error)
2397
0
{
2398
0
    assert(tox != nullptr);
2399
0
    uint64_t last_active = UINT64_MAX;
2400
0
    tox_lock(tox);
2401
0
    const int ret = group_frozen_last_active(tox->m->conferences_object, conference_number, offline_peer_number,
2402
0
                    &last_active);
2403
0
    tox_unlock(tox);
2404
2405
0
    switch (ret) {
2406
0
        case -1: {
2407
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
2408
0
            return UINT64_MAX;
2409
0
        }
2410
2411
0
        case -2: {
2412
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
2413
0
            return UINT64_MAX;
2414
0
        }
2415
0
    }
2416
2417
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
2418
0
    return last_active;
2419
0
}
2420
2421
bool tox_conference_set_max_offline(Tox *tox, uint32_t conference_number,
2422
                                    uint32_t max_offline,
2423
                                    Tox_Err_Conference_Set_Max_Offline *error)
2424
0
{
2425
0
    assert(tox != nullptr);
2426
0
    tox_lock(tox);
2427
0
    const int ret = group_set_max_frozen(tox->m->conferences_object, conference_number, max_offline);
2428
0
    tox_unlock(tox);
2429
2430
0
    if (ret == -1) {
2431
0
        SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_CONFERENCE_NOT_FOUND);
2432
0
        return false;
2433
0
    }
2434
2435
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_OK);
2436
0
    return true;
2437
0
}
2438
2439
bool tox_conference_invite(Tox *tox, uint32_t friend_number, uint32_t conference_number,
2440
                           Tox_Err_Conference_Invite *error)
2441
0
{
2442
0
    assert(tox != nullptr);
2443
0
    tox_lock(tox);
2444
0
    const int ret = invite_friend(tox->m->conferences_object, friend_number, conference_number);
2445
0
    tox_unlock(tox);
2446
2447
0
    switch (ret) {
2448
0
        case -1: {
2449
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_CONFERENCE_NOT_FOUND);
2450
0
            return false;
2451
0
        }
2452
2453
0
        case -2: {
2454
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_FAIL_SEND);
2455
0
            return false;
2456
0
        }
2457
2458
0
        case -3: {
2459
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_NO_CONNECTION);
2460
0
            return false;
2461
0
        }
2462
0
    }
2463
2464
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_OK);
2465
0
    return true;
2466
0
}
2467
2468
uint32_t tox_conference_join(Tox *tox, uint32_t friend_number, const uint8_t *cookie, size_t length,
2469
                             Tox_Err_Conference_Join *error)
2470
0
{
2471
0
    assert(tox != nullptr);
2472
2473
0
    if (cookie == nullptr) {
2474
0
        SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_NULL);
2475
0
        return UINT32_MAX;
2476
0
    }
2477
2478
0
    tox_lock(tox);
2479
0
    const int ret = join_groupchat(tox->m->conferences_object, friend_number, GROUPCHAT_TYPE_TEXT, cookie, length);
2480
0
    tox_unlock(tox);
2481
2482
0
    switch (ret) {
2483
0
        case -1: {
2484
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_INVALID_LENGTH);
2485
0
            return UINT32_MAX;
2486
0
        }
2487
2488
0
        case -2: {
2489
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_WRONG_TYPE);
2490
0
            return UINT32_MAX;
2491
0
        }
2492
2493
0
        case -3: {
2494
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_FRIEND_NOT_FOUND);
2495
0
            return UINT32_MAX;
2496
0
        }
2497
2498
0
        case -4: {
2499
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_DUPLICATE);
2500
0
            return UINT32_MAX;
2501
0
        }
2502
2503
0
        case -5: {
2504
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_INIT_FAIL);
2505
0
            return UINT32_MAX;
2506
0
        }
2507
2508
0
        case -6: {
2509
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_FAIL_SEND);
2510
0
            return UINT32_MAX;
2511
0
        }
2512
0
    }
2513
2514
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_OK);
2515
0
    return ret;
2516
0
}
2517
2518
bool tox_conference_send_message(Tox *tox, uint32_t conference_number, Tox_Message_Type type, const uint8_t *message,
2519
                                 size_t length, Tox_Err_Conference_Send_Message *error)
2520
0
{
2521
0
    assert(tox != nullptr);
2522
0
    tox_lock(tox);
2523
0
    int ret = 0;
2524
2525
0
    if (type == TOX_MESSAGE_TYPE_NORMAL) {
2526
0
        ret = group_message_send(tox->m->conferences_object, conference_number, message, length);
2527
0
    } else {
2528
0
        ret = group_action_send(tox->m->conferences_object, conference_number, message, length);
2529
0
    }
2530
2531
0
    tox_unlock(tox);
2532
2533
0
    switch (ret) {
2534
0
        case -1: {
2535
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_CONFERENCE_NOT_FOUND);
2536
0
            return false;
2537
0
        }
2538
2539
0
        case -2: {
2540
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_TOO_LONG);
2541
0
            return false;
2542
0
        }
2543
2544
0
        case -3: {
2545
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_NO_CONNECTION);
2546
0
            return false;
2547
0
        }
2548
2549
0
        case -4: {
2550
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_FAIL_SEND);
2551
0
            return false;
2552
0
        }
2553
0
    }
2554
2555
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_OK);
2556
0
    return true;
2557
0
}
2558
2559
size_t tox_conference_get_title_size(const Tox *tox, uint32_t conference_number, Tox_Err_Conference_Title *error)
2560
0
{
2561
0
    assert(tox != nullptr);
2562
0
    tox_lock(tox);
2563
0
    const int ret = group_title_get_size(tox->m->conferences_object, conference_number);
2564
0
    tox_unlock(tox);
2565
2566
0
    switch (ret) {
2567
0
        case -1: {
2568
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND);
2569
0
            return -1;
2570
0
        }
2571
2572
0
        case -2: {
2573
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH);
2574
0
            return -1;
2575
0
        }
2576
0
    }
2577
2578
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_OK);
2579
0
    return ret;
2580
0
}
2581
2582
bool tox_conference_get_title(const Tox *tox, uint32_t conference_number, uint8_t *title,
2583
                              Tox_Err_Conference_Title *error)
2584
0
{
2585
0
    assert(tox != nullptr);
2586
0
    tox_lock(tox);
2587
0
    const int ret = group_title_get(tox->m->conferences_object, conference_number, title);
2588
0
    tox_unlock(tox);
2589
2590
0
    switch (ret) {
2591
0
        case -1: {
2592
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND);
2593
0
            return false;
2594
0
        }
2595
2596
0
        case -2: {
2597
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH);
2598
0
            return false;
2599
0
        }
2600
0
    }
2601
2602
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_OK);
2603
0
    return true;
2604
0
}
2605
2606
bool tox_conference_set_title(Tox *tox, uint32_t conference_number, const uint8_t *title, size_t length,
2607
                              Tox_Err_Conference_Title *error)
2608
0
{
2609
0
    assert(tox != nullptr);
2610
0
    tox_lock(tox);
2611
0
    const int ret = group_title_send(tox->m->conferences_object, conference_number, title, length);
2612
0
    tox_unlock(tox);
2613
2614
0
    switch (ret) {
2615
0
        case -1: {
2616
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND);
2617
0
            return false;
2618
0
        }
2619
2620
0
        case -2: {
2621
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH);
2622
0
            return false;
2623
0
        }
2624
2625
0
        case -3: {
2626
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_FAIL_SEND);
2627
0
            return false;
2628
0
        }
2629
0
    }
2630
2631
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_OK);
2632
0
    return true;
2633
0
}
2634
2635
size_t tox_conference_get_chatlist_size(const Tox *tox)
2636
0
{
2637
0
    assert(tox != nullptr);
2638
0
    tox_lock(tox);
2639
0
    const size_t ret = count_chatlist(tox->m->conferences_object);
2640
0
    tox_unlock(tox);
2641
0
    return ret;
2642
0
}
2643
2644
void tox_conference_get_chatlist(const Tox *tox, uint32_t *chatlist)
2645
0
{
2646
0
    assert(tox != nullptr);
2647
0
    tox_lock(tox);
2648
0
    const size_t list_size = count_chatlist(tox->m->conferences_object);
2649
0
    copy_chatlist(tox->m->conferences_object, chatlist, list_size);
2650
0
    tox_unlock(tox);
2651
0
}
2652
2653
Tox_Conference_Type tox_conference_get_type(const Tox *tox, uint32_t conference_number,
2654
        Tox_Err_Conference_Get_Type *error)
2655
0
{
2656
0
    assert(tox != nullptr);
2657
0
    tox_lock(tox);
2658
0
    const int ret = group_get_type(tox->m->conferences_object, conference_number);
2659
0
    tox_unlock(tox);
2660
2661
0
    if (ret == -1) {
2662
0
        SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_GET_TYPE_CONFERENCE_NOT_FOUND);
2663
0
        return (Tox_Conference_Type)ret;
2664
0
    }
2665
2666
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_GET_TYPE_OK);
2667
0
    return (Tox_Conference_Type)ret;
2668
0
}
2669
2670
bool tox_conference_get_id(const Tox *tox, uint32_t conference_number, uint8_t id[TOX_CONFERENCE_ID_SIZE])
2671
0
{
2672
0
    assert(tox != nullptr);
2673
0
    tox_lock(tox);
2674
0
    const bool ret = conference_get_id(tox->m->conferences_object, conference_number, id);
2675
0
    tox_unlock(tox);
2676
0
    return ret;
2677
0
}
2678
2679
// TODO(iphydf): Delete in 0.3.0.
2680
bool tox_conference_get_uid(const Tox *tox, uint32_t conference_number, uint8_t uid[TOX_CONFERENCE_UID_SIZE])
2681
0
{
2682
0
    assert(tox != nullptr);
2683
0
    return tox_conference_get_id(tox, conference_number, uid);
2684
0
}
2685
2686
uint32_t tox_conference_by_id(const Tox *tox, const uint8_t id[TOX_CONFERENCE_ID_SIZE], Tox_Err_Conference_By_Id *error)
2687
0
{
2688
0
    assert(tox != nullptr);
2689
2690
0
    if (id == nullptr) {
2691
0
        SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_BY_ID_NULL);
2692
0
        return UINT32_MAX;
2693
0
    }
2694
2695
0
    tox_lock(tox);
2696
0
    const int32_t ret = conference_by_id(tox->m->conferences_object, id);
2697
0
    tox_unlock(tox);
2698
2699
0
    if (ret == -1) {
2700
0
        SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_BY_ID_NOT_FOUND);
2701
0
        return UINT32_MAX;
2702
0
    }
2703
2704
0
    SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_BY_ID_OK);
2705
0
    assert(ret >= 0);
2706
0
    return (uint32_t)ret;
2707
0
}
2708
2709
// TODO(iphydf): Delete in 0.3.0.
2710
uint32_t tox_conference_by_uid(const Tox *tox, const uint8_t uid[TOX_CONFERENCE_UID_SIZE], Tox_Err_Conference_By_Uid *error)
2711
0
{
2712
0
    assert(tox != nullptr);
2713
0
    Tox_Err_Conference_By_Id id_error;
2714
0
    const uint32_t res = tox_conference_by_id(tox, uid, &id_error);
2715
2716
0
    switch (id_error) {
2717
0
        case TOX_ERR_CONFERENCE_BY_ID_OK: {
2718
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_BY_UID_OK);
2719
0
            break;
2720
0
        }
2721
2722
0
        case TOX_ERR_CONFERENCE_BY_ID_NULL: {
2723
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_BY_UID_NULL);
2724
0
            break;
2725
0
        }
2726
2727
0
        case TOX_ERR_CONFERENCE_BY_ID_NOT_FOUND: {
2728
0
            SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_BY_UID_NOT_FOUND);
2729
0
            break;
2730
0
        }
2731
0
    }
2732
2733
0
    return res;
2734
0
}
2735
2736
static void set_custom_packet_error(int ret, Tox_Err_Friend_Custom_Packet *_Nullable error)
2737
0
{
2738
0
    switch (ret) {
2739
0
        case 0: {
2740
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_OK);
2741
0
            break;
2742
0
        }
2743
2744
0
        case -1: {
2745
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_FOUND);
2746
0
            break;
2747
0
        }
2748
2749
0
        case -2: {
2750
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_TOO_LONG);
2751
0
            break;
2752
0
        }
2753
2754
0
        case -3: {
2755
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID);
2756
0
            break;
2757
0
        }
2758
2759
0
        case -4: {
2760
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_CONNECTED);
2761
0
            break;
2762
0
        }
2763
2764
0
        case -5: {
2765
0
            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_SENDQ);
2766
0
            break;
2767
0
        }
2768
0
    }
2769
0
}
2770
2771
// cppcheck-suppress constParameterPointer
2772
bool tox_friend_send_lossy_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,
2773
                                  Tox_Err_Friend_Custom_Packet *error)
2774
0
{
2775
0
    assert(tox != nullptr);
2776
2777
0
    if (data == nullptr) {
2778
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_NULL);
2779
0
        return false;
2780
0
    }
2781
2782
0
    if (length == 0) {
2783
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY);
2784
0
        return false;
2785
0
    }
2786
2787
0
    if (data[0] < PACKET_ID_RANGE_LOSSY_START || data[0] > PACKET_ID_RANGE_LOSSY_END) {
2788
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID);
2789
0
        return false;
2790
0
    }
2791
2792
0
    tox_lock(tox);
2793
0
    const int ret = m_send_custom_lossy_packet(tox->m, friend_number, data, length);
2794
0
    tox_unlock(tox);
2795
2796
0
    set_custom_packet_error(ret, error);
2797
2798
0
    return ret == 0;
2799
0
}
2800
2801
void tox_callback_friend_lossy_packet(Tox *tox, tox_friend_lossy_packet_cb *callback)
2802
0
{
2803
0
    assert(tox != nullptr);
2804
2805
    /* start at PACKET_ID_RANGE_LOSSY_CUSTOM_START so ToxAV Packets are excluded */
2806
0
    for (uint8_t i = PACKET_ID_RANGE_LOSSY_CUSTOM_START; i <= PACKET_ID_RANGE_LOSSY_END; ++i) {
2807
0
        tox->friend_lossy_packet_callback_per_pktid[i] = callback;
2808
0
    }
2809
0
}
2810
2811
// cppcheck-suppress constParameterPointer
2812
bool tox_friend_send_lossless_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,
2813
                                     Tox_Err_Friend_Custom_Packet *error)
2814
0
{
2815
0
    assert(tox != nullptr);
2816
2817
0
    if (data == nullptr) {
2818
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_NULL);
2819
0
        return false;
2820
0
    }
2821
2822
0
    if (length == 0) {
2823
0
        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY);
2824
0
        return false;
2825
0
    }
2826
2827
0
    tox_lock(tox);
2828
0
    const int ret = send_custom_lossless_packet(tox->m, friend_number, data, length);
2829
0
    tox_unlock(tox);
2830
2831
0
    set_custom_packet_error(ret, error);
2832
2833
0
    return ret == 0;
2834
0
}
2835
2836
void tox_callback_friend_lossless_packet(Tox *tox, tox_friend_lossless_packet_cb *callback)
2837
0
{
2838
0
    assert(tox != nullptr);
2839
2840
0
    for (uint8_t i = PACKET_ID_RANGE_LOSSLESS_CUSTOM_START; i <= PACKET_ID_RANGE_LOSSLESS_CUSTOM_END; ++i) {
2841
0
        tox->friend_lossless_packet_callback_per_pktid[i] = callback;
2842
0
    }
2843
0
}
2844
2845
void tox_self_get_dht_id(const Tox *tox, uint8_t dht_id[TOX_PUBLIC_KEY_SIZE])
2846
0
{
2847
0
    assert(tox != nullptr);
2848
2849
0
    if (dht_id != nullptr) {
2850
0
        tox_lock(tox);
2851
0
        memcpy(dht_id, dht_get_self_public_key(tox->m->dht), CRYPTO_PUBLIC_KEY_SIZE);
2852
0
        tox_unlock(tox);
2853
0
    }
2854
0
}
2855
2856
uint16_t tox_self_get_udp_port(const Tox *tox, Tox_Err_Get_Port *error)
2857
0
{
2858
0
    assert(tox != nullptr);
2859
0
    tox_lock(tox);
2860
0
    const uint16_t port = tox->m == nullptr || tox->m->net == nullptr ? 0 : net_htons(net_port(tox->m->net));
2861
0
    tox_unlock(tox);
2862
2863
0
    if (port == 0) {
2864
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_NOT_BOUND);
2865
0
        return 0;
2866
0
    }
2867
2868
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_OK);
2869
0
    return port;
2870
0
}
2871
2872
uint16_t tox_self_get_tcp_port(const Tox *tox, Tox_Err_Get_Port *error)
2873
0
{
2874
0
    assert(tox != nullptr);
2875
0
    tox_lock(tox);
2876
2877
0
    if (tox->m != nullptr && tox->m->tcp_server != nullptr) {
2878
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_OK);
2879
0
        const uint16_t ret = tox->m->options.tcp_server_port;
2880
0
        tox_unlock(tox);
2881
0
        return ret;
2882
0
    }
2883
2884
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_NOT_BOUND);
2885
0
    tox_unlock(tox);
2886
0
    return 0;
2887
0
}
2888
2889
/* GROUPCHAT FUNCTIONS */
2890
2891
void tox_callback_group_invite(Tox *tox, tox_group_invite_cb *callback)
2892
0
{
2893
0
    assert(tox != nullptr);
2894
0
    tox->group_invite_callback = callback;
2895
0
}
2896
2897
void tox_callback_group_message(Tox *tox, tox_group_message_cb *callback)
2898
0
{
2899
0
    assert(tox != nullptr);
2900
0
    tox->group_message_callback = callback;
2901
0
}
2902
2903
void tox_callback_group_private_message(Tox *tox, tox_group_private_message_cb *callback)
2904
0
{
2905
0
    assert(tox != nullptr);
2906
0
    tox->group_private_message_callback = callback;
2907
0
}
2908
2909
void tox_callback_group_custom_packet(Tox *tox, tox_group_custom_packet_cb *callback)
2910
0
{
2911
0
    assert(tox != nullptr);
2912
0
    tox->group_custom_packet_callback = callback;
2913
0
}
2914
2915
void tox_callback_group_custom_private_packet(Tox *tox, tox_group_custom_private_packet_cb *callback)
2916
0
{
2917
0
    assert(tox != nullptr);
2918
0
    tox->group_custom_private_packet_callback = callback;
2919
0
}
2920
2921
void tox_callback_group_moderation(Tox *tox, tox_group_moderation_cb *callback)
2922
0
{
2923
0
    assert(tox != nullptr);
2924
0
    tox->group_moderation_callback = callback;
2925
0
}
2926
2927
void tox_callback_group_peer_name(Tox *tox, tox_group_peer_name_cb *callback)
2928
0
{
2929
0
    assert(tox != nullptr);
2930
0
    tox->group_peer_name_callback = callback;
2931
0
}
2932
2933
void tox_callback_group_peer_status(Tox *tox, tox_group_peer_status_cb *callback)
2934
0
{
2935
0
    assert(tox != nullptr);
2936
0
    tox->group_peer_status_callback = callback;
2937
0
}
2938
2939
void tox_callback_group_topic(Tox *tox, tox_group_topic_cb *callback)
2940
0
{
2941
0
    assert(tox != nullptr);
2942
0
    tox->group_topic_callback = callback;
2943
0
}
2944
2945
void tox_callback_group_privacy_state(Tox *tox, tox_group_privacy_state_cb *callback)
2946
0
{
2947
0
    assert(tox != nullptr);
2948
0
    tox->group_privacy_state_callback = callback;
2949
0
}
2950
2951
void tox_callback_group_topic_lock(Tox *tox, tox_group_topic_lock_cb *callback)
2952
0
{
2953
0
    assert(tox != nullptr);
2954
0
    tox->group_topic_lock_callback = callback;
2955
0
}
2956
2957
void tox_callback_group_voice_state(Tox *tox, tox_group_voice_state_cb *callback)
2958
0
{
2959
0
    assert(tox != nullptr);
2960
0
    tox->group_voice_state_callback = callback;
2961
0
}
2962
2963
void tox_callback_group_peer_limit(Tox *tox, tox_group_peer_limit_cb *callback)
2964
0
{
2965
0
    assert(tox != nullptr);
2966
0
    tox->group_peer_limit_callback = callback;
2967
0
}
2968
2969
void tox_callback_group_password(Tox *tox, tox_group_password_cb *callback)
2970
0
{
2971
0
    assert(tox != nullptr);
2972
0
    tox->group_password_callback = callback;
2973
0
}
2974
2975
void tox_callback_group_peer_join(Tox *tox, tox_group_peer_join_cb *callback)
2976
0
{
2977
0
    assert(tox != nullptr);
2978
0
    tox->group_peer_join_callback = callback;
2979
0
}
2980
2981
void tox_callback_group_peer_exit(Tox *tox, tox_group_peer_exit_cb *callback)
2982
0
{
2983
0
    assert(tox != nullptr);
2984
0
    tox->group_peer_exit_callback = callback;
2985
0
}
2986
2987
void tox_callback_group_self_join(Tox *tox, tox_group_self_join_cb *callback)
2988
0
{
2989
0
    assert(tox != nullptr);
2990
0
    tox->group_self_join_callback = callback;
2991
0
}
2992
2993
void tox_callback_group_join_fail(Tox *tox, tox_group_join_fail_cb *callback)
2994
0
{
2995
0
    assert(tox != nullptr);
2996
0
    tox->group_join_fail_callback = callback;
2997
0
}
2998
2999
uint32_t tox_group_new(Tox *tox, Tox_Group_Privacy_State privacy_state, const uint8_t *group_name,
3000
                       size_t group_name_length, const uint8_t *name, size_t name_length, Tox_Err_Group_New *error)
3001
0
{
3002
0
    assert(tox != nullptr);
3003
3004
0
    tox_lock(tox);
3005
0
    const int ret = gc_group_add(tox->m->group_handler, (Group_Privacy_State) privacy_state,
3006
0
                                 group_name, group_name_length, name, name_length);
3007
0
    tox_unlock(tox);
3008
3009
0
    if (ret >= 0) {
3010
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_NEW_OK);
3011
0
        return ret;
3012
0
    }
3013
3014
0
    switch (ret) {
3015
0
        case -1: {
3016
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_NEW_TOO_LONG);
3017
0
            return UINT32_MAX;
3018
0
        }
3019
3020
0
        case -2: {
3021
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_NEW_EMPTY);
3022
0
            return UINT32_MAX;
3023
0
        }
3024
3025
0
        case -3: {
3026
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_NEW_INIT);
3027
0
            return UINT32_MAX;
3028
0
        }
3029
3030
0
        case -4: {
3031
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_NEW_STATE);
3032
0
            return UINT32_MAX;
3033
0
        }
3034
3035
0
        case -5: {
3036
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_NEW_ANNOUNCE);
3037
0
            return UINT32_MAX;
3038
0
        }
3039
0
    }
3040
3041
    /* can't happen */
3042
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
3043
3044
0
    return UINT32_MAX;
3045
0
}
3046
3047
uint32_t tox_group_join(Tox *tox, const uint8_t chat_id[TOX_GROUP_CHAT_ID_SIZE], const uint8_t *name, size_t name_length,
3048
                        const uint8_t *password, size_t password_length, Tox_Err_Group_Join *error)
3049
0
{
3050
0
    assert(tox != nullptr);
3051
3052
0
    tox_lock(tox);
3053
0
    const int ret = gc_group_join(tox->m->group_handler, chat_id, name, name_length, password, password_length);
3054
0
    tox_unlock(tox);
3055
3056
0
    if (ret >= 0) {
3057
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_JOIN_OK);
3058
0
        return ret;
3059
0
    }
3060
3061
0
    switch (ret) {
3062
0
        case -1: {
3063
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_JOIN_INIT);
3064
0
            return UINT32_MAX;
3065
0
        }
3066
3067
0
        case -2: {
3068
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_JOIN_BAD_CHAT_ID);
3069
0
            return UINT32_MAX;
3070
0
        }
3071
3072
0
        case -3: {
3073
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_JOIN_TOO_LONG);
3074
0
            return UINT32_MAX;
3075
0
        }
3076
3077
0
        case -4: {
3078
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_JOIN_EMPTY);
3079
0
            return UINT32_MAX;
3080
0
        }
3081
3082
0
        case -5: {
3083
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_JOIN_PASSWORD);
3084
0
            return UINT32_MAX;
3085
0
        }
3086
3087
0
        case -6: {
3088
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_JOIN_CORE);
3089
0
            return UINT32_MAX;
3090
0
        }
3091
0
    }
3092
3093
    /* can't happen */
3094
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
3095
3096
0
    return UINT32_MAX;
3097
0
}
3098
3099
bool tox_group_is_connected(const Tox *tox, uint32_t group_number, Tox_Err_Group_Is_Connected *error)
3100
0
{
3101
0
    assert(tox != nullptr);
3102
3103
0
    tox_lock(tox);
3104
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3105
3106
0
    if (chat == nullptr) {
3107
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_IS_CONNECTED_GROUP_NOT_FOUND);
3108
0
        tox_unlock(tox);
3109
0
        return false;
3110
0
    }
3111
3112
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_IS_CONNECTED_OK);
3113
3114
0
    const bool ret = chat->connection_state == CS_CONNECTED || chat->connection_state == CS_CONNECTING;
3115
0
    tox_unlock(tox);
3116
3117
0
    return ret;
3118
0
}
3119
3120
bool tox_group_disconnect(const Tox *tox, uint32_t group_number, Tox_Err_Group_Disconnect *error)
3121
0
{
3122
0
    assert(tox != nullptr);
3123
3124
0
    tox_lock(tox);
3125
0
    GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3126
3127
0
    if (chat == nullptr) {
3128
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_DISCONNECT_GROUP_NOT_FOUND);
3129
0
        tox_unlock(tox);
3130
0
        return false;
3131
0
    }
3132
3133
0
    if (chat->connection_state == CS_DISCONNECTED) {
3134
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_DISCONNECT_ALREADY_DISCONNECTED);
3135
0
        tox_unlock(tox);
3136
0
        return false;
3137
0
    }
3138
3139
0
    const bool ret = gc_disconnect_from_group(tox->m->group_handler, chat);
3140
3141
0
    tox_unlock(tox);
3142
3143
0
    if (!ret) {
3144
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_DISCONNECT_GROUP_NOT_FOUND);
3145
0
        return false;
3146
0
    }
3147
3148
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_DISCONNECT_OK);
3149
3150
0
    return true;
3151
0
}
3152
3153
bool tox_group_reconnect(Tox *tox, uint32_t group_number, Tox_Err_Group_Reconnect *error)
3154
0
{
3155
0
    assert(tox != nullptr);
3156
3157
0
    tox_lock(tox);
3158
0
    GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3159
3160
0
    if (chat == nullptr) {
3161
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_RECONNECT_GROUP_NOT_FOUND);
3162
0
        tox_unlock(tox);
3163
0
        return false;
3164
0
    }
3165
3166
0
    const int ret = gc_rejoin_group(tox->m->group_handler, chat, nullptr, 0);
3167
0
    tox_unlock(tox);
3168
3169
0
    switch (ret) {
3170
0
        case 0: {
3171
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_RECONNECT_OK);
3172
0
            return true;
3173
0
        }
3174
3175
0
        case -1: {
3176
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_RECONNECT_GROUP_NOT_FOUND);
3177
0
            return false;
3178
0
        }
3179
3180
0
        case -2: {
3181
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_RECONNECT_CORE);
3182
0
            return false;
3183
0
        }
3184
0
    }
3185
3186
    /* can't happen */
3187
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
3188
3189
0
    return false;
3190
0
}
3191
3192
bool tox_group_leave(Tox *tox, uint32_t group_number, const uint8_t *part_message, size_t length,
3193
                     Tox_Err_Group_Leave *error)
3194
0
{
3195
0
    assert(tox != nullptr);
3196
3197
0
    tox_lock(tox);
3198
0
    GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3199
3200
0
    if (chat == nullptr) {
3201
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_LEAVE_GROUP_NOT_FOUND);
3202
0
        tox_unlock(tox);
3203
0
        return false;
3204
0
    }
3205
3206
0
    const int ret = gc_group_exit(tox->m->group_handler, chat, part_message, length);
3207
0
    tox_unlock(tox);
3208
3209
0
    switch (ret) {
3210
0
        case 0: {
3211
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_LEAVE_OK);
3212
0
            return true;
3213
0
        }
3214
3215
0
        case -1: {
3216
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_LEAVE_TOO_LONG);
3217
0
            return false;
3218
0
        }
3219
3220
0
        case -2: {
3221
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_LEAVE_FAIL_SEND);
3222
0
            return true;   /* the group was still successfully deleted */
3223
0
        }
3224
0
    }
3225
3226
    /* can't happen */
3227
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
3228
3229
0
    return false;
3230
0
}
3231
3232
bool tox_group_self_set_name(Tox *tox, uint32_t group_number, const uint8_t *name, size_t length,
3233
                             Tox_Err_Group_Self_Name_Set *error)
3234
0
{
3235
0
    assert(tox != nullptr);
3236
3237
0
    tox_lock(tox);
3238
0
    const int ret = gc_set_self_nick(tox->m, group_number, name, length);
3239
0
    tox_unlock(tox);
3240
3241
0
    switch (ret) {
3242
0
        case 0: {
3243
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_NAME_SET_OK);
3244
0
            return true;
3245
0
        }
3246
3247
0
        case -1: {
3248
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_NAME_SET_GROUP_NOT_FOUND);
3249
0
            return false;
3250
0
        }
3251
3252
0
        case -2: {
3253
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_NAME_SET_TOO_LONG);
3254
0
            return false;
3255
0
        }
3256
3257
0
        case -3: {
3258
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_NAME_SET_INVALID);
3259
0
            return false;
3260
0
        }
3261
3262
0
        case -4: {
3263
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_NAME_SET_FAIL_SEND);
3264
0
            return false;
3265
0
        }
3266
0
    }
3267
3268
    /* can't happen */
3269
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
3270
3271
0
    return false;
3272
0
}
3273
3274
size_t tox_group_self_get_name_size(const Tox *tox, uint32_t group_number, Tox_Err_Group_Self_Query *error)
3275
0
{
3276
0
    assert(tox != nullptr);
3277
3278
0
    tox_lock(tox);
3279
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3280
3281
0
    if (chat == nullptr) {
3282
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_QUERY_GROUP_NOT_FOUND);
3283
0
        tox_unlock(tox);
3284
0
        return -1;
3285
0
    }
3286
3287
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_QUERY_OK);
3288
3289
0
    const size_t ret = gc_get_self_nick_size(chat);
3290
0
    tox_unlock(tox);
3291
3292
0
    return ret;
3293
0
}
3294
3295
bool tox_group_self_get_name(const Tox *tox, uint32_t group_number, uint8_t *name, Tox_Err_Group_Self_Query *error)
3296
0
{
3297
0
    assert(tox != nullptr);
3298
3299
0
    tox_lock(tox);
3300
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3301
3302
0
    if (chat == nullptr) {
3303
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_QUERY_GROUP_NOT_FOUND);
3304
0
        tox_unlock(tox);
3305
0
        return false;
3306
0
    }
3307
3308
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_QUERY_OK);
3309
3310
0
    gc_get_self_nick(chat, name);
3311
0
    tox_unlock(tox);
3312
3313
0
    return true;
3314
0
}
3315
3316
bool tox_group_self_set_status(Tox *tox, uint32_t group_number, Tox_User_Status status,
3317
                               Tox_Err_Group_Self_Status_Set *error)
3318
0
{
3319
0
    assert(tox != nullptr);
3320
3321
0
    tox_lock(tox);
3322
0
    const int ret = gc_set_self_status(tox->m, group_number, (Group_Peer_Status) status);
3323
0
    tox_unlock(tox);
3324
3325
0
    switch (ret) {
3326
0
        case 0: {
3327
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_STATUS_SET_OK);
3328
0
            return true;
3329
0
        }
3330
3331
0
        case -1: {
3332
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_STATUS_SET_GROUP_NOT_FOUND);
3333
0
            return false;
3334
0
        }
3335
3336
0
        case -2: {
3337
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_STATUS_SET_FAIL_SEND);
3338
0
            return false;
3339
0
        }
3340
0
    }
3341
3342
    /* can't happen */
3343
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
3344
3345
0
    return false;
3346
0
}
3347
3348
Tox_User_Status tox_group_self_get_status(const Tox *tox, uint32_t group_number, Tox_Err_Group_Self_Query *error)
3349
0
{
3350
0
    assert(tox != nullptr);
3351
3352
0
    tox_lock(tox);
3353
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3354
3355
0
    if (chat == nullptr) {
3356
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_QUERY_GROUP_NOT_FOUND);
3357
0
        tox_unlock(tox);
3358
0
        return (Tox_User_Status) - 1;
3359
0
    }
3360
3361
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_QUERY_OK);
3362
3363
0
    const uint8_t status = gc_get_self_status(chat);
3364
0
    tox_unlock(tox);
3365
3366
0
    return (Tox_User_Status)status;
3367
0
}
3368
3369
Tox_Group_Role tox_group_self_get_role(const Tox *tox, uint32_t group_number, Tox_Err_Group_Self_Query *error)
3370
0
{
3371
0
    assert(tox != nullptr);
3372
3373
0
    tox_lock(tox);
3374
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3375
3376
0
    if (chat == nullptr) {
3377
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_QUERY_GROUP_NOT_FOUND);
3378
0
        tox_unlock(tox);
3379
0
        return (Tox_Group_Role) - 1;
3380
0
    }
3381
3382
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_QUERY_OK);
3383
3384
0
    const Group_Role role = gc_get_self_role(chat);
3385
0
    tox_unlock(tox);
3386
3387
0
    return (Tox_Group_Role)role;
3388
0
}
3389
3390
uint32_t tox_group_self_get_peer_id(const Tox *tox, uint32_t group_number, Tox_Err_Group_Self_Query *error)
3391
0
{
3392
0
    assert(tox != nullptr);
3393
3394
0
    tox_lock(tox);
3395
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3396
3397
0
    if (chat == nullptr) {
3398
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_QUERY_GROUP_NOT_FOUND);
3399
0
        tox_unlock(tox);
3400
0
        return -1;
3401
0
    }
3402
3403
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_QUERY_OK);
3404
3405
0
    const GC_Peer_Id ret = gc_get_self_peer_id(chat);
3406
0
    tox_unlock(tox);
3407
3408
0
    return gc_peer_id_to_int(ret);
3409
0
}
3410
3411
bool tox_group_self_get_public_key(const Tox *tox, uint32_t group_number, uint8_t public_key[TOX_PUBLIC_KEY_SIZE],
3412
                                   Tox_Err_Group_Self_Query *error)
3413
0
{
3414
0
    assert(tox != nullptr);
3415
3416
0
    tox_lock(tox);
3417
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3418
3419
0
    if (chat == nullptr) {
3420
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_QUERY_GROUP_NOT_FOUND);
3421
0
        tox_unlock(tox);
3422
0
        return false;
3423
0
    }
3424
3425
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SELF_QUERY_OK);
3426
3427
0
    gc_get_self_public_key(chat, public_key);
3428
0
    tox_unlock(tox);
3429
3430
0
    return true;
3431
0
}
3432
3433
size_t tox_group_peer_get_name_size(const Tox *tox, uint32_t group_number, uint32_t peer_id,
3434
                                    Tox_Err_Group_Peer_Query *error)
3435
0
{
3436
0
    assert(tox != nullptr);
3437
3438
0
    tox_lock(tox);
3439
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3440
3441
0
    if (chat == nullptr) {
3442
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_GROUP_NOT_FOUND);
3443
0
        tox_unlock(tox);
3444
0
        return -1;
3445
0
    }
3446
3447
0
    const int ret = gc_get_peer_nick_size(chat, gc_peer_id_from_int(peer_id));
3448
0
    tox_unlock(tox);
3449
3450
0
    if (ret == -1) {
3451
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_PEER_NOT_FOUND);
3452
0
        return -1;
3453
0
    } else {
3454
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_OK);
3455
0
        return ret;
3456
0
    }
3457
0
}
3458
3459
bool tox_group_peer_get_name(const Tox *tox, uint32_t group_number, uint32_t peer_id, uint8_t *name,
3460
                             Tox_Err_Group_Peer_Query *error)
3461
0
{
3462
0
    assert(tox != nullptr);
3463
3464
0
    tox_lock(tox);
3465
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3466
3467
0
    if (chat == nullptr) {
3468
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_GROUP_NOT_FOUND);
3469
0
        tox_unlock(tox);
3470
0
        return false;
3471
0
    }
3472
3473
0
    const bool ret = gc_get_peer_nick(chat, gc_peer_id_from_int(peer_id), name);
3474
0
    tox_unlock(tox);
3475
3476
0
    if (!ret) {
3477
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_PEER_NOT_FOUND);
3478
0
        return false;
3479
0
    }
3480
3481
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_OK);
3482
0
    return true;
3483
0
}
3484
3485
Tox_User_Status tox_group_peer_get_status(const Tox *tox, uint32_t group_number, uint32_t peer_id,
3486
        Tox_Err_Group_Peer_Query *error)
3487
0
{
3488
0
    assert(tox != nullptr);
3489
3490
0
    tox_lock(tox);
3491
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3492
3493
0
    if (chat == nullptr) {
3494
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_GROUP_NOT_FOUND);
3495
0
        tox_unlock(tox);
3496
0
        return (Tox_User_Status) - 1;
3497
0
    }
3498
3499
0
    const uint8_t ret = gc_get_status(chat, gc_peer_id_from_int(peer_id));
3500
0
    tox_unlock(tox);
3501
3502
0
    if (ret == UINT8_MAX) {
3503
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_PEER_NOT_FOUND);
3504
0
        return (Tox_User_Status) - 1;
3505
0
    }
3506
3507
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_OK);
3508
0
    return (Tox_User_Status)ret;
3509
0
}
3510
3511
Tox_Group_Role tox_group_peer_get_role(const Tox *tox, uint32_t group_number, uint32_t peer_id,
3512
                                       Tox_Err_Group_Peer_Query *error)
3513
0
{
3514
0
    assert(tox != nullptr);
3515
3516
0
    tox_lock(tox);
3517
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3518
3519
0
    if (chat == nullptr) {
3520
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_GROUP_NOT_FOUND);
3521
0
        tox_unlock(tox);
3522
0
        return (Tox_Group_Role) - 1;
3523
0
    }
3524
3525
0
    const uint8_t ret = gc_get_role(chat, gc_peer_id_from_int(peer_id));
3526
0
    tox_unlock(tox);
3527
3528
0
    if (ret == (uint8_t) -1) {
3529
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_PEER_NOT_FOUND);
3530
0
        return (Tox_Group_Role) - 1;
3531
0
    }
3532
3533
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_OK);
3534
0
    return (Tox_Group_Role)ret;
3535
0
}
3536
3537
bool tox_group_peer_get_public_key(const Tox *tox, uint32_t group_number, uint32_t peer_id, uint8_t public_key[TOX_PUBLIC_KEY_SIZE],
3538
                                   Tox_Err_Group_Peer_Query *error)
3539
0
{
3540
0
    assert(tox != nullptr);
3541
3542
0
    tox_lock(tox);
3543
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3544
3545
0
    if (chat == nullptr) {
3546
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_GROUP_NOT_FOUND);
3547
0
        tox_unlock(tox);
3548
0
        return false;
3549
0
    }
3550
3551
0
    const int ret = gc_get_peer_public_key_by_peer_id(chat, gc_peer_id_from_int(peer_id), public_key);
3552
0
    tox_unlock(tox);
3553
3554
0
    if (ret == -1) {
3555
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_PEER_NOT_FOUND);
3556
0
        return false;
3557
0
    }
3558
3559
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_OK);
3560
0
    return true;
3561
0
}
3562
3563
Tox_Connection tox_group_peer_get_connection_status(const Tox *tox, uint32_t group_number, uint32_t peer_id,
3564
        Tox_Err_Group_Peer_Query *error)
3565
0
{
3566
0
    assert(tox != nullptr);
3567
3568
0
    tox_lock(tox);
3569
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3570
3571
0
    if (chat == nullptr) {
3572
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_GROUP_NOT_FOUND);
3573
0
        tox_unlock(tox);
3574
0
        return TOX_CONNECTION_NONE;
3575
0
    }
3576
3577
0
    const unsigned int ret = gc_get_peer_connection_status(chat, gc_peer_id_from_int(peer_id));
3578
0
    tox_unlock(tox);
3579
3580
0
    if (ret == 0) {
3581
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_PEER_NOT_FOUND);
3582
0
        return TOX_CONNECTION_NONE;
3583
0
    }
3584
3585
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_PEER_QUERY_OK);
3586
0
    return (Tox_Connection)ret;
3587
0
}
3588
3589
bool tox_group_set_topic(Tox *tox, uint32_t group_number, const uint8_t *topic, size_t length,
3590
                         Tox_Err_Group_Topic_Set *error)
3591
0
{
3592
0
    assert(tox != nullptr);
3593
3594
0
    tox_lock(tox);
3595
0
    GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3596
3597
0
    if (chat == nullptr) {
3598
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_TOPIC_SET_GROUP_NOT_FOUND);
3599
0
        tox_unlock(tox);
3600
0
        return false;
3601
0
    }
3602
3603
0
    if (chat->connection_state == CS_DISCONNECTED) {
3604
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_TOPIC_SET_DISCONNECTED);
3605
0
        tox_unlock(tox);
3606
0
        return false;
3607
0
    }
3608
3609
0
    const int ret = gc_set_topic(chat, topic, length);
3610
0
    tox_unlock(tox);
3611
3612
0
    switch (ret) {
3613
0
        case 0: {
3614
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_TOPIC_SET_OK);
3615
0
            return true;
3616
0
        }
3617
3618
0
        case -1: {
3619
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_TOPIC_SET_TOO_LONG);
3620
0
            return false;
3621
0
        }
3622
3623
0
        case -2: {
3624
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_TOPIC_SET_PERMISSIONS);
3625
0
            return false;
3626
0
        }
3627
3628
0
        case -3: {
3629
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_TOPIC_SET_FAIL_CREATE);
3630
0
            return false;
3631
0
        }
3632
3633
0
        case -4: {
3634
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_TOPIC_SET_FAIL_SEND);
3635
0
            return false;
3636
0
        }
3637
0
    }
3638
3639
    /* can't happen */
3640
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
3641
3642
0
    return false;
3643
0
}
3644
3645
size_t tox_group_get_topic_size(const Tox *tox, uint32_t group_number, Tox_Err_Group_State_Query *error)
3646
0
{
3647
0
    assert(tox != nullptr);
3648
3649
0
    tox_lock(tox);
3650
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3651
3652
0
    if (chat == nullptr) {
3653
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_GROUP_NOT_FOUND);
3654
0
        tox_unlock(tox);
3655
0
        return -1;
3656
0
    }
3657
3658
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_OK);
3659
3660
0
    const size_t ret = gc_get_topic_size(chat);
3661
0
    tox_unlock(tox);
3662
3663
0
    return ret;
3664
0
}
3665
3666
bool tox_group_get_topic(const Tox *tox, uint32_t group_number, uint8_t *topic, Tox_Err_Group_State_Query *error)
3667
0
{
3668
0
    assert(tox != nullptr);
3669
3670
0
    tox_lock(tox);
3671
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3672
3673
0
    if (chat == nullptr) {
3674
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_GROUP_NOT_FOUND);
3675
0
        tox_unlock(tox);
3676
0
        return false;
3677
0
    }
3678
3679
0
    gc_get_topic(chat, topic);
3680
0
    tox_unlock(tox);
3681
3682
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_OK);
3683
0
    return true;
3684
0
}
3685
3686
size_t tox_group_get_name_size(const Tox *tox, uint32_t group_number, Tox_Err_Group_State_Query *error)
3687
0
{
3688
0
    assert(tox != nullptr);
3689
3690
0
    tox_lock(tox);
3691
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3692
3693
0
    if (chat == nullptr) {
3694
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_GROUP_NOT_FOUND);
3695
0
        tox_unlock(tox);
3696
0
        return -1;
3697
0
    }
3698
3699
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_OK);
3700
3701
0
    const size_t ret = gc_get_group_name_size(chat);
3702
0
    tox_unlock(tox);
3703
3704
0
    return ret;
3705
0
}
3706
3707
bool tox_group_get_name(const Tox *tox, uint32_t group_number, uint8_t *name, Tox_Err_Group_State_Query *error)
3708
0
{
3709
0
    assert(tox != nullptr);
3710
3711
0
    tox_lock(tox);
3712
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3713
3714
0
    if (chat == nullptr) {
3715
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_GROUP_NOT_FOUND);
3716
0
        tox_unlock(tox);
3717
0
        return false;
3718
0
    }
3719
3720
0
    gc_get_group_name(chat, name);
3721
0
    tox_unlock(tox);
3722
3723
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_OK);
3724
3725
0
    return true;
3726
0
}
3727
3728
bool tox_group_get_chat_id(const Tox *tox, uint32_t group_number, uint8_t chat_id[TOX_GROUP_CHAT_ID_SIZE], Tox_Err_Group_State_Query *error)
3729
0
{
3730
0
    assert(tox != nullptr);
3731
3732
0
    tox_lock(tox);
3733
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3734
3735
0
    if (chat == nullptr) {
3736
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_GROUP_NOT_FOUND);
3737
0
        tox_unlock(tox);
3738
0
        return false;
3739
0
    }
3740
3741
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_OK);
3742
0
    gc_get_chat_id(chat, chat_id);
3743
0
    tox_unlock(tox);
3744
3745
0
    return true;
3746
0
}
3747
3748
uint32_t tox_group_get_number_groups(const Tox *tox)
3749
0
{
3750
0
    assert(tox != nullptr);
3751
3752
0
    tox_lock(tox);
3753
0
    const uint32_t ret = gc_count_groups(tox->m->group_handler);
3754
0
    tox_unlock(tox);
3755
3756
0
    return ret;
3757
0
}
3758
3759
Tox_Group_Privacy_State tox_group_get_privacy_state(const Tox *tox, uint32_t group_number,
3760
        Tox_Err_Group_State_Query *error)
3761
0
{
3762
0
    assert(tox != nullptr);
3763
3764
0
    tox_lock(tox);
3765
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3766
3767
0
    if (chat == nullptr) {
3768
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_GROUP_NOT_FOUND);
3769
0
        tox_unlock(tox);
3770
0
        return (Tox_Group_Privacy_State) - 1;
3771
0
    }
3772
3773
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_OK);
3774
3775
0
    const uint8_t state = gc_get_privacy_state(chat);
3776
0
    tox_unlock(tox);
3777
3778
0
    return (Tox_Group_Privacy_State)state;
3779
0
}
3780
3781
Tox_Group_Topic_Lock tox_group_get_topic_lock(const Tox *tox, uint32_t group_number, Tox_Err_Group_State_Query *error)
3782
0
{
3783
0
    assert(tox != nullptr);
3784
3785
0
    tox_lock(tox);
3786
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3787
3788
0
    if (chat == nullptr) {
3789
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_GROUP_NOT_FOUND);
3790
0
        tox_unlock(tox);
3791
0
        return (Tox_Group_Topic_Lock) - 1;
3792
0
    }
3793
3794
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_OK);
3795
3796
0
    const Group_Topic_Lock topic_lock = gc_get_topic_lock_state(chat);
3797
0
    tox_unlock(tox);
3798
3799
0
    return (Tox_Group_Topic_Lock)topic_lock;
3800
0
}
3801
3802
Tox_Group_Voice_State tox_group_get_voice_state(const Tox *tox, uint32_t group_number,
3803
        Tox_Err_Group_State_Query *error)
3804
0
{
3805
0
    assert(tox != nullptr);
3806
3807
0
    tox_lock(tox);
3808
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3809
3810
0
    if (chat == nullptr) {
3811
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_GROUP_NOT_FOUND);
3812
0
        tox_unlock(tox);
3813
0
        return (Tox_Group_Voice_State) - 1;
3814
0
    }
3815
3816
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_OK);
3817
3818
0
    const Group_Voice_State voice_state = gc_get_voice_state(chat);
3819
0
    tox_unlock(tox);
3820
3821
0
    return (Tox_Group_Voice_State)voice_state;
3822
0
}
3823
3824
uint16_t tox_group_get_peer_limit(const Tox *tox, uint32_t group_number, Tox_Err_Group_State_Query *error)
3825
0
{
3826
0
    assert(tox != nullptr);
3827
3828
0
    tox_lock(tox);
3829
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3830
3831
0
    if (chat == nullptr) {
3832
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_GROUP_NOT_FOUND);
3833
0
        tox_unlock(tox);
3834
0
        return -1;
3835
0
    }
3836
3837
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_OK);
3838
3839
0
    const uint16_t ret = gc_get_max_peers(chat);
3840
0
    tox_unlock(tox);
3841
3842
0
    return ret;
3843
0
}
3844
3845
size_t tox_group_get_password_size(const Tox *tox, uint32_t group_number, Tox_Err_Group_State_Query *error)
3846
0
{
3847
0
    assert(tox != nullptr);
3848
3849
0
    tox_lock(tox);
3850
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3851
3852
0
    if (chat == nullptr) {
3853
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_GROUP_NOT_FOUND);
3854
0
        tox_unlock(tox);
3855
0
        return -1;
3856
0
    }
3857
3858
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_OK);
3859
3860
0
    const size_t ret = gc_get_password_size(chat);
3861
0
    tox_unlock(tox);
3862
3863
0
    return ret;
3864
0
}
3865
3866
bool tox_group_get_password(const Tox *tox, uint32_t group_number, uint8_t *password,
3867
                            Tox_Err_Group_State_Query *error)
3868
0
{
3869
0
    assert(tox != nullptr);
3870
3871
0
    tox_lock(tox);
3872
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3873
3874
0
    if (chat == nullptr) {
3875
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_GROUP_NOT_FOUND);
3876
0
        tox_unlock(tox);
3877
0
        return false;
3878
0
    }
3879
3880
0
    SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_STATE_QUERY_OK);
3881
3882
0
    gc_get_password(chat, password);
3883
0
    tox_unlock(tox);
3884
3885
0
    return true;
3886
0
}
3887
3888
Tox_Group_Message_Id tox_group_send_message(
3889
    const Tox *tox, uint32_t group_number, Tox_Message_Type message_type, const uint8_t *message,
3890
    size_t length, Tox_Err_Group_Send_Message *error)
3891
0
{
3892
0
    assert(tox != nullptr);
3893
3894
0
    tox_lock(tox);
3895
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3896
3897
0
    if (chat == nullptr) {
3898
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_MESSAGE_GROUP_NOT_FOUND);
3899
0
        tox_unlock(tox);
3900
0
        return -1;
3901
0
    }
3902
3903
0
    if (chat->connection_state == CS_DISCONNECTED) {
3904
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_MESSAGE_DISCONNECTED);
3905
0
        tox_unlock(tox);
3906
0
        return -1;
3907
0
    }
3908
3909
0
    uint32_t message_id = 0;
3910
0
    const int ret = gc_send_message(chat, message, length, message_type, &message_id);
3911
0
    tox_unlock(tox);
3912
3913
0
    switch (ret) {
3914
0
        case 0: {
3915
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_MESSAGE_OK);
3916
0
            return message_id;
3917
0
        }
3918
3919
0
        case -1: {
3920
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_MESSAGE_TOO_LONG);
3921
0
            return -1;
3922
0
        }
3923
3924
0
        case -2: {
3925
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_MESSAGE_EMPTY);
3926
0
            return -1;
3927
0
        }
3928
3929
0
        case -3: {
3930
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_MESSAGE_BAD_TYPE);
3931
0
            return -1;
3932
0
        }
3933
3934
0
        case -4: {
3935
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_MESSAGE_PERMISSIONS);
3936
0
            return -1;
3937
0
        }
3938
3939
0
        case -5: {
3940
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_MESSAGE_FAIL_SEND);
3941
0
            return -1;
3942
0
        }
3943
0
    }
3944
3945
    /* can't happen */
3946
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
3947
3948
0
    return -1;
3949
0
}
3950
3951
Tox_Group_Message_Id tox_group_send_private_message(const Tox *tox, uint32_t group_number, uint32_t peer_id,
3952
        Tox_Message_Type message_type, const uint8_t *message, size_t length, Tox_Err_Group_Send_Private_Message *error)
3953
0
{
3954
0
    assert(tox != nullptr);
3955
3956
0
    tox_lock(tox);
3957
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
3958
3959
0
    if (chat == nullptr) {
3960
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_GROUP_NOT_FOUND);
3961
0
        tox_unlock(tox);
3962
0
        return -1;
3963
0
    }
3964
3965
0
    if (chat->connection_state == CS_DISCONNECTED) {
3966
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_DISCONNECTED);
3967
0
        tox_unlock(tox);
3968
0
        return -1;
3969
0
    }
3970
3971
0
    uint32_t message_id = 0;
3972
0
    const int ret = gc_send_private_message(chat, gc_peer_id_from_int(peer_id), message_type, message, length, &message_id);
3973
0
    tox_unlock(tox);
3974
3975
0
    switch (ret) {
3976
0
        case 0: {
3977
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_OK);
3978
0
            return message_id;
3979
0
        }
3980
3981
0
        case -1: {
3982
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_TOO_LONG);
3983
0
            return -1;
3984
0
        }
3985
3986
0
        case -2: {
3987
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_EMPTY);
3988
0
            return -1;
3989
0
        }
3990
3991
0
        case -3: {
3992
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_PEER_NOT_FOUND);
3993
0
            return -1;
3994
0
        }
3995
3996
0
        case -4: {
3997
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_BAD_TYPE);
3998
0
            return -1;
3999
0
        }
4000
4001
0
        case -5: {
4002
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_PERMISSIONS);
4003
0
            return -1;
4004
0
        }
4005
4006
0
        case -6: {
4007
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_PRIVATE_MESSAGE_FAIL_SEND);
4008
0
            return -1;
4009
0
        }
4010
0
    }
4011
4012
    /* can't happen */
4013
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
4014
4015
0
    return -1;
4016
0
}
4017
4018
bool tox_group_send_custom_packet(const Tox *tox, uint32_t group_number, bool lossless, const uint8_t *data,
4019
                                  size_t length, Tox_Err_Group_Send_Custom_Packet *error)
4020
0
{
4021
0
    assert(tox != nullptr);
4022
4023
0
    tox_lock(tox);
4024
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
4025
4026
0
    if (chat == nullptr) {
4027
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_CUSTOM_PACKET_GROUP_NOT_FOUND);
4028
0
        tox_unlock(tox);
4029
0
        return false;
4030
0
    }
4031
4032
0
    if (chat->connection_state == CS_DISCONNECTED) {
4033
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_CUSTOM_PACKET_DISCONNECTED);
4034
0
        tox_unlock(tox);
4035
0
        return false;
4036
0
    }
4037
4038
0
    const int ret = gc_send_custom_packet(chat, lossless, data, length);
4039
0
    tox_unlock(tox);
4040
4041
0
    switch (ret) {
4042
0
        case 0: {
4043
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_CUSTOM_PACKET_OK);
4044
0
            return true;
4045
0
        }
4046
4047
0
        case -1: {
4048
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_CUSTOM_PACKET_TOO_LONG);
4049
0
            return false;
4050
0
        }
4051
4052
0
        case -2: {
4053
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_CUSTOM_PACKET_EMPTY);
4054
0
            return false;
4055
0
        }
4056
4057
0
        case -3: {
4058
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_CUSTOM_PACKET_FAIL_SEND);
4059
0
            return false;
4060
0
        }
4061
0
    }
4062
4063
    /* can't happen */
4064
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
4065
4066
0
    return false;
4067
0
}
4068
4069
bool tox_group_send_custom_private_packet(const Tox *tox, uint32_t group_number, uint32_t peer_id, bool lossless,
4070
        const uint8_t *data, size_t length,
4071
        Tox_Err_Group_Send_Custom_Private_Packet *error)
4072
0
{
4073
0
    assert(tox != nullptr);
4074
4075
0
    tox_lock(tox);
4076
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
4077
4078
0
    if (chat == nullptr) {
4079
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_GROUP_NOT_FOUND);
4080
0
        tox_unlock(tox);
4081
0
        return false;
4082
0
    }
4083
4084
0
    if (chat->connection_state == CS_DISCONNECTED) {
4085
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_DISCONNECTED);
4086
0
        tox_unlock(tox);
4087
0
        return false;
4088
0
    }
4089
4090
0
    const int ret = gc_send_custom_private_packet(chat, lossless, gc_peer_id_from_int(peer_id), data, length);
4091
0
    tox_unlock(tox);
4092
4093
0
    switch (ret) {
4094
0
        case 0: {
4095
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK);
4096
0
            return true;
4097
0
        }
4098
4099
0
        case -1: {
4100
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_TOO_LONG);
4101
0
            return false;
4102
0
        }
4103
4104
0
        case -2: {
4105
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_EMPTY);
4106
0
            return false;
4107
0
        }
4108
4109
0
        case -3: {
4110
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_PEER_NOT_FOUND);
4111
0
            return false;
4112
0
        }
4113
4114
0
        case -4: {
4115
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_FAIL_SEND);
4116
0
            return false;
4117
0
        }
4118
0
    }
4119
4120
    /* can't happen */
4121
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
4122
4123
0
    return false;
4124
0
}
4125
4126
bool tox_group_invite_friend(const Tox *tox, uint32_t group_number, uint32_t friend_number,
4127
                             Tox_Err_Group_Invite_Friend *error)
4128
0
{
4129
0
    assert(tox != nullptr);
4130
4131
0
    tox_lock(tox);
4132
0
    GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
4133
4134
0
    if (chat == nullptr) {
4135
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_FRIEND_GROUP_NOT_FOUND);
4136
0
        tox_unlock(tox);
4137
0
        return false;
4138
0
    }
4139
4140
0
    if (chat->connection_state == CS_DISCONNECTED) {
4141
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_FRIEND_DISCONNECTED);
4142
0
        tox_unlock(tox);
4143
0
        return false;
4144
0
    }
4145
4146
0
    if (!friend_is_valid(tox->m, friend_number)) {
4147
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_FRIEND_FRIEND_NOT_FOUND);
4148
0
        tox_unlock(tox);
4149
0
        return false;
4150
0
    }
4151
4152
0
    const int ret = gc_invite_friend(tox->m->group_handler, chat, friend_number, send_group_invite_packet);
4153
0
    tox_unlock(tox);
4154
4155
0
    switch (ret) {
4156
0
        case 0: {
4157
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_FRIEND_OK);
4158
0
            return true;
4159
0
        }
4160
4161
0
        case -1: {
4162
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_FRIEND_FRIEND_NOT_FOUND);
4163
0
            return false;
4164
0
        }
4165
4166
0
        case -2: {
4167
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_FRIEND_INVITE_FAIL);
4168
0
            return false;
4169
0
        }
4170
4171
0
        case -3: {
4172
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_FRIEND_FAIL_SEND);
4173
0
            return false;
4174
0
        }
4175
0
    }
4176
4177
    /* can't happen */
4178
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
4179
4180
0
    return false;
4181
0
}
4182
4183
uint32_t tox_group_invite_accept(Tox *tox, uint32_t friend_number, const uint8_t *invite_data, size_t length,
4184
                                 const uint8_t *name, size_t name_length, const uint8_t *password,
4185
                                 size_t password_length, Tox_Err_Group_Invite_Accept *error)
4186
0
{
4187
0
    assert(tox != nullptr);
4188
4189
0
    if (invite_data == nullptr || name == nullptr) {
4190
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_ACCEPT_NULL);
4191
0
        return UINT32_MAX;
4192
0
    }
4193
4194
0
    tox_lock(tox);
4195
0
    const int ret = gc_accept_invite(tox->m->group_handler, friend_number, invite_data, length, name, name_length, password,
4196
0
                                     password_length);
4197
0
    tox_unlock(tox);
4198
4199
0
    if (ret >= 0) {
4200
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_ACCEPT_OK);
4201
0
        return ret;
4202
0
    }
4203
4204
0
    switch (ret) {
4205
0
        case -1: {
4206
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_ACCEPT_BAD_INVITE);
4207
0
            return UINT32_MAX;
4208
0
        }
4209
4210
0
        case -2: {
4211
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_ACCEPT_INIT_FAILED);
4212
0
            return UINT32_MAX;
4213
0
        }
4214
4215
0
        case -3: {
4216
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_ACCEPT_TOO_LONG);
4217
0
            return UINT32_MAX;
4218
0
        }
4219
4220
0
        case -4: {
4221
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_ACCEPT_EMPTY);
4222
0
            return UINT32_MAX;
4223
0
        }
4224
4225
0
        case -5: {
4226
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_ACCEPT_PASSWORD);
4227
0
            return UINT32_MAX;
4228
0
        }
4229
4230
0
        case -6: {
4231
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_ACCEPT_FRIEND_NOT_FOUND);
4232
0
            return UINT32_MAX;
4233
0
        }
4234
4235
0
        case -7: {
4236
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_INVITE_ACCEPT_FAIL_SEND);
4237
0
            return UINT32_MAX;
4238
0
        }
4239
0
    }
4240
4241
    /* can't happen */
4242
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
4243
4244
0
    return UINT32_MAX;
4245
0
}
4246
4247
bool tox_group_set_password(Tox *tox, uint32_t group_number, const uint8_t *password, size_t length,
4248
                            Tox_Err_Group_Set_Password *error)
4249
0
{
4250
0
    assert(tox != nullptr);
4251
4252
0
    tox_lock(tox);
4253
0
    GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
4254
4255
0
    if (chat == nullptr) {
4256
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PASSWORD_GROUP_NOT_FOUND);
4257
0
        tox_unlock(tox);
4258
0
        return false;
4259
0
    }
4260
4261
0
    if (chat->connection_state == CS_DISCONNECTED) {
4262
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PASSWORD_DISCONNECTED);
4263
0
        tox_unlock(tox);
4264
0
        return false;
4265
0
    }
4266
4267
0
    const int ret = gc_founder_set_password(chat, password, length);
4268
0
    tox_unlock(tox);
4269
4270
0
    switch (ret) {
4271
0
        case 0: {
4272
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PASSWORD_OK);
4273
0
            return true;
4274
0
        }
4275
4276
0
        case -1: {
4277
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PASSWORD_PERMISSIONS);
4278
0
            return false;
4279
0
        }
4280
4281
0
        case -2: {
4282
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PASSWORD_TOO_LONG);
4283
0
            return false;
4284
0
        }
4285
4286
0
        case -3: {
4287
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PASSWORD_FAIL_SEND);
4288
0
            return false;
4289
0
        }
4290
4291
0
        case -4: {
4292
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PASSWORD_MALLOC);
4293
0
            return false;
4294
0
        }
4295
0
    }
4296
4297
    /* can't happen */
4298
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
4299
4300
0
    return false;
4301
0
}
4302
4303
bool tox_group_set_privacy_state(Tox *tox, uint32_t group_number, Tox_Group_Privacy_State privacy_state,
4304
                                 Tox_Err_Group_Set_Privacy_State *error)
4305
0
{
4306
0
    assert(tox != nullptr);
4307
4308
0
    tox_lock(tox);
4309
0
    const int ret = gc_founder_set_privacy_state(tox->m, group_number, (Group_Privacy_State) privacy_state);
4310
0
    tox_unlock(tox);
4311
4312
0
    switch (ret) {
4313
0
        case 0: {
4314
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PRIVACY_STATE_OK);
4315
0
            return true;
4316
0
        }
4317
4318
0
        case -1: {
4319
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PRIVACY_STATE_GROUP_NOT_FOUND);
4320
0
            return false;
4321
0
        }
4322
4323
0
        case -2: {
4324
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PRIVACY_STATE_PERMISSIONS);
4325
0
            return false;
4326
0
        }
4327
4328
0
        case -3: {
4329
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PRIVACY_STATE_DISCONNECTED);
4330
0
            return false;
4331
0
        }
4332
4333
0
        case -4: {
4334
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PRIVACY_STATE_FAIL_SET);
4335
0
            return false;
4336
0
        }
4337
4338
0
        case -5: {
4339
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PRIVACY_STATE_FAIL_SEND);
4340
0
            return false;
4341
0
        }
4342
0
    }
4343
4344
    /* can't happen */
4345
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
4346
4347
0
    return false;
4348
0
}
4349
4350
bool tox_group_set_topic_lock(Tox *tox, uint32_t group_number, Tox_Group_Topic_Lock topic_lock,
4351
                              Tox_Err_Group_Set_Topic_Lock *error)
4352
0
{
4353
0
    assert(tox != nullptr);
4354
4355
0
    tox_lock(tox);
4356
0
    const int ret = gc_founder_set_topic_lock(tox->m, group_number, (Group_Topic_Lock) topic_lock);
4357
0
    tox_unlock(tox);
4358
4359
0
    switch (ret) {
4360
0
        case 0: {
4361
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_TOPIC_LOCK_OK);
4362
0
            return true;
4363
0
        }
4364
4365
0
        case -1: {
4366
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_TOPIC_LOCK_GROUP_NOT_FOUND);
4367
0
            return false;
4368
0
        }
4369
4370
0
        case -2: {
4371
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_TOPIC_LOCK_INVALID);
4372
0
            return false;
4373
0
        }
4374
4375
0
        case -3: {
4376
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_TOPIC_LOCK_PERMISSIONS);
4377
0
            return false;
4378
0
        }
4379
4380
0
        case -4: {
4381
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_TOPIC_LOCK_DISCONNECTED);
4382
0
            return false;
4383
0
        }
4384
4385
0
        case -5: {
4386
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_TOPIC_LOCK_FAIL_SET);
4387
0
            return false;
4388
0
        }
4389
4390
0
        case -6: {
4391
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_TOPIC_LOCK_FAIL_SEND);
4392
0
            return false;
4393
0
        }
4394
0
    }
4395
4396
    /* can't happen */
4397
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
4398
4399
0
    return false;
4400
0
}
4401
4402
bool tox_group_set_voice_state(Tox *tox, uint32_t group_number, Tox_Group_Voice_State voice_state,
4403
                               Tox_Err_Group_Set_Voice_State *error)
4404
0
{
4405
0
    assert(tox != nullptr);
4406
4407
0
    tox_lock(tox);
4408
0
    const int ret = gc_founder_set_voice_state(tox->m, group_number, (Group_Voice_State)voice_state);
4409
0
    tox_unlock(tox);
4410
4411
0
    switch (ret) {
4412
0
        case 0: {
4413
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_VOICE_STATE_OK);
4414
0
            return true;
4415
0
        }
4416
4417
0
        case -1: {
4418
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_VOICE_STATE_GROUP_NOT_FOUND);
4419
0
            return false;
4420
0
        }
4421
4422
0
        case -2: {
4423
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_VOICE_STATE_PERMISSIONS);
4424
0
            return false;
4425
0
        }
4426
4427
0
        case -3: {
4428
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_VOICE_STATE_DISCONNECTED);
4429
0
            return false;
4430
0
        }
4431
4432
0
        case -4: {
4433
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_VOICE_STATE_FAIL_SET);
4434
0
            return false;
4435
0
        }
4436
4437
0
        case -5: {
4438
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_VOICE_STATE_FAIL_SEND);
4439
0
            return false;
4440
0
        }
4441
0
    }
4442
4443
    /* can't happen */
4444
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
4445
4446
0
    return false;
4447
0
}
4448
4449
bool tox_group_set_peer_limit(Tox *tox, uint32_t group_number, uint16_t peer_limit,
4450
                              Tox_Err_Group_Set_Peer_Limit *error)
4451
0
{
4452
0
    assert(tox != nullptr);
4453
4454
0
    tox_lock(tox);
4455
0
    GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
4456
4457
0
    if (chat == nullptr) {
4458
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PEER_LIMIT_GROUP_NOT_FOUND);
4459
0
        tox_unlock(tox);
4460
0
        return false;
4461
0
    }
4462
4463
0
    if (chat->connection_state == CS_DISCONNECTED) {
4464
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PEER_LIMIT_DISCONNECTED);
4465
0
        tox_unlock(tox);
4466
0
        return false;
4467
0
    }
4468
4469
0
    const int ret = gc_founder_set_max_peers(chat, peer_limit);
4470
0
    tox_unlock(tox);
4471
4472
0
    switch (ret) {
4473
0
        case 0: {
4474
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PEER_LIMIT_OK);
4475
0
            return true;
4476
0
        }
4477
4478
0
        case -1: {
4479
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PEER_LIMIT_PERMISSIONS);
4480
0
            return false;
4481
0
        }
4482
4483
0
        case -2: {
4484
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PEER_LIMIT_FAIL_SET);
4485
0
            return false;
4486
0
        }
4487
4488
0
        case -3: {
4489
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_PEER_LIMIT_FAIL_SEND);
4490
0
            return false;
4491
0
        }
4492
0
    }
4493
4494
    /* can't happen */
4495
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
4496
4497
0
    return false;
4498
0
}
4499
4500
bool tox_group_set_ignore(Tox *tox, uint32_t group_number, uint32_t peer_id, bool ignore,
4501
                          Tox_Err_Group_Set_Ignore *error)
4502
0
{
4503
0
    assert(tox != nullptr);
4504
4505
0
    tox_lock(tox);
4506
0
    const GC_Chat *chat = gc_get_group(tox->m->group_handler, group_number);
4507
4508
0
    if (chat == nullptr) {
4509
0
        SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_IGNORE_GROUP_NOT_FOUND);
4510
0
        tox_unlock(tox);
4511
0
        return false;
4512
0
    }
4513
4514
0
    const int ret = gc_set_ignore(chat, gc_peer_id_from_int(peer_id), ignore);
4515
0
    tox_unlock(tox);
4516
4517
0
    switch (ret) {
4518
0
        case 0: {
4519
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_IGNORE_OK);
4520
0
            return true;
4521
0
        }
4522
4523
0
        case -1: {
4524
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_IGNORE_PEER_NOT_FOUND);
4525
0
            return false;
4526
0
        }
4527
4528
0
        case -2: {
4529
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_IGNORE_SELF);
4530
0
            return false;
4531
0
        }
4532
0
    }
4533
4534
    /* can't happen */
4535
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
4536
4537
0
    return false;
4538
0
}
4539
4540
bool tox_group_set_role(Tox *tox, uint32_t group_number, uint32_t peer_id, Tox_Group_Role role,
4541
                        Tox_Err_Group_Set_Role *error)
4542
0
{
4543
0
    assert(tox != nullptr);
4544
4545
0
    tox_lock(tox);
4546
0
    const int ret = gc_set_peer_role(tox->m, group_number, gc_peer_id_from_int(peer_id), (Group_Role) role);
4547
0
    tox_unlock(tox);
4548
4549
0
    switch (ret) {
4550
0
        case 0: {
4551
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_ROLE_OK);
4552
0
            return true;
4553
0
        }
4554
4555
0
        case -1: {
4556
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_ROLE_GROUP_NOT_FOUND);
4557
0
            return false;
4558
0
        }
4559
4560
0
        case -2: {
4561
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_ROLE_PEER_NOT_FOUND);
4562
0
            return false;
4563
0
        }
4564
4565
0
        case -3: {
4566
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_ROLE_PERMISSIONS);
4567
0
            return false;
4568
0
        }
4569
4570
0
        case -4: {
4571
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_ROLE_ASSIGNMENT);
4572
0
            return false;
4573
0
        }
4574
4575
0
        case -5: {
4576
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_ROLE_FAIL_ACTION);
4577
0
            return false;
4578
0
        }
4579
4580
0
        case -6: {
4581
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_SET_ROLE_SELF);
4582
0
            return false;
4583
0
        }
4584
0
    }
4585
4586
    /* can't happen */
4587
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
4588
4589
0
    return false;
4590
0
}
4591
4592
bool tox_group_kick_peer(const Tox *tox, uint32_t group_number, uint32_t peer_id,
4593
                         Tox_Err_Group_Kick_Peer *error)
4594
0
{
4595
0
    assert(tox != nullptr);
4596
4597
0
    tox_lock(tox);
4598
0
    const int ret = gc_kick_peer(tox->m, group_number, gc_peer_id_from_int(peer_id));
4599
0
    tox_unlock(tox);
4600
4601
0
    switch (ret) {
4602
0
        case 0: {
4603
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_KICK_PEER_OK);
4604
0
            return true;
4605
0
        }
4606
4607
0
        case -1: {
4608
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_KICK_PEER_GROUP_NOT_FOUND);
4609
0
            return false;
4610
0
        }
4611
4612
0
        case -2: {
4613
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_KICK_PEER_PEER_NOT_FOUND);
4614
0
            return false;
4615
0
        }
4616
4617
0
        case -3: {
4618
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_KICK_PEER_PERMISSIONS);
4619
0
            return false;
4620
0
        }
4621
4622
0
        case -4: {
4623
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_KICK_PEER_FAIL_ACTION);
4624
0
            return false;
4625
0
        }
4626
4627
0
        case -5: {
4628
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_KICK_PEER_FAIL_SEND);
4629
0
            return false;
4630
0
        }
4631
4632
0
        case -6: {
4633
0
            SET_ERROR_PARAMETER(error, TOX_ERR_GROUP_KICK_PEER_SELF);
4634
0
            return false;
4635
0
        }
4636
0
    }
4637
4638
    /* can't happen */
4639
0
    LOGGER_FATAL(tox->m->log, "impossible return value: %d", ret);
4640
4641
0
    return false;
4642
0
}
4643
4644
const Tox_System *tox_get_system(Tox *tox)
4645
0
{
4646
0
    assert(tox != nullptr);
4647
0
    return &tox->sys;
4648
0
}