Coverage Report

Created: 2026-02-01 10:37

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