Coverage Report

Created: 2024-01-26 01:52

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