Coverage Report

Created: 2025-10-08 19:34

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