Coverage Report

Created: 2023-11-22 10:24

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