1 /* SPDX-License-Identifier: GPL-3.0-or-later
2  * Copyright © 2016-2018 The TokTok team.
3  * Copyright © 2013 Tox project.
4  */
5 
6 /*
7  * The Tox public API.
8  */
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12 
13 #ifndef __cplusplus
14 #ifndef _XOPEN_SOURCE
15 #define _XOPEN_SOURCE 600
16 #endif
17 #endif
18 
19 #include "tox.h"
20 #include "tox_private.h"
21 
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "Messenger.h"
27 #include "group.h"
28 #include "logger.h"
29 #include "mono_time.h"
30 
31 #include "../toxencryptsave/defines.h"
32 
33 #define SET_ERROR_PARAMETER(param, x) do { if (param) { *param = x; } } while (0)
34 
35 #if TOX_HASH_LENGTH != CRYPTO_SHA256_SIZE
36 #error "TOX_HASH_LENGTH is assumed to be equal to CRYPTO_SHA256_SIZE"
37 #endif
38 
39 #if FILE_ID_LENGTH != CRYPTO_SYMMETRIC_KEY_SIZE
40 #error "FILE_ID_LENGTH is assumed to be equal to CRYPTO_SYMMETRIC_KEY_SIZE"
41 #endif
42 
43 #if TOX_FILE_ID_LENGTH != CRYPTO_SYMMETRIC_KEY_SIZE
44 #error "TOX_FILE_ID_LENGTH is assumed to be equal to CRYPTO_SYMMETRIC_KEY_SIZE"
45 #endif
46 
47 #if TOX_FILE_ID_LENGTH != TOX_HASH_LENGTH
48 #error "TOX_FILE_ID_LENGTH is assumed to be equal to TOX_HASH_LENGTH"
49 #endif
50 
51 #if TOX_PUBLIC_KEY_SIZE != CRYPTO_PUBLIC_KEY_SIZE
52 #error "TOX_PUBLIC_KEY_SIZE is assumed to be equal to CRYPTO_PUBLIC_KEY_SIZE"
53 #endif
54 
55 #if TOX_SECRET_KEY_SIZE != CRYPTO_SECRET_KEY_SIZE
56 #error "TOX_SECRET_KEY_SIZE is assumed to be equal to CRYPTO_SECRET_KEY_SIZE"
57 #endif
58 
59 #if TOX_MAX_NAME_LENGTH != MAX_NAME_LENGTH
60 #error "TOX_MAX_NAME_LENGTH is assumed to be equal to MAX_NAME_LENGTH"
61 #endif
62 
63 #if TOX_MAX_STATUS_MESSAGE_LENGTH != MAX_STATUSMESSAGE_LENGTH
64 #error "TOX_MAX_STATUS_MESSAGE_LENGTH is assumed to be equal to MAX_STATUSMESSAGE_LENGTH"
65 #endif
66 
67 struct Tox {
68     // XXX: Messenger *must* be the first member, because toxav casts its
69     // `Tox *` to `Messenger **`.
70     Messenger *m;
71     Mono_Time *mono_time;
72     pthread_mutex_t *mutex;
73 
74     tox_self_connection_status_cb *self_connection_status_callback;
75     tox_friend_name_cb *friend_name_callback;
76     tox_friend_status_message_cb *friend_status_message_callback;
77     tox_friend_status_cb *friend_status_callback;
78     tox_friend_connection_status_cb *friend_connection_status_callback;
79     tox_friend_typing_cb *friend_typing_callback;
80     tox_friend_read_receipt_cb *friend_read_receipt_callback;
81     tox_friend_request_cb *friend_request_callback;
82     tox_friend_message_cb *friend_message_callback;
83     tox_file_recv_control_cb *file_recv_control_callback;
84     tox_file_chunk_request_cb *file_chunk_request_callback;
85     tox_file_recv_cb *file_recv_callback;
86     tox_file_recv_chunk_cb *file_recv_chunk_callback;
87     tox_conference_invite_cb *conference_invite_callback;
88     tox_conference_connected_cb *conference_connected_callback;
89     tox_conference_message_cb *conference_message_callback;
90     tox_conference_title_cb *conference_title_callback;
91     tox_conference_peer_name_cb *conference_peer_name_callback;
92     tox_conference_peer_list_changed_cb *conference_peer_list_changed_callback;
93     tox_friend_lossy_packet_cb *friend_lossy_packet_callback_per_pktid[UINT8_MAX + 1];
94     tox_friend_lossless_packet_cb *friend_lossless_packet_callback_per_pktid[UINT8_MAX + 1];
95 
96     void *toxav_object; // workaround to store a ToxAV object (setter and getter functions are available)
97 };
98 
lock(const Tox * tox)99 static void lock(const Tox *tox)
100 {
101     if (tox->mutex != nullptr) {
102         pthread_mutex_lock(tox->mutex);
103     }
104 }
105 
unlock(const Tox * tox)106 static void unlock(const Tox *tox)
107 {
108     if (tox->mutex != nullptr) {
109         pthread_mutex_unlock(tox->mutex);
110     }
111 }
112 
113 struct Tox_Userdata {
114     Tox *tox;
115     void *user_data;
116 };
117 
tox_self_connection_status_handler(Messenger * m,unsigned int connection_status,void * user_data)118 static void tox_self_connection_status_handler(Messenger *m, unsigned int connection_status, void *user_data)
119 {
120     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
121 
122     if (tox_data->tox->self_connection_status_callback != nullptr) {
123         tox_data->tox->self_connection_status_callback(tox_data->tox, (Tox_Connection)connection_status, tox_data->user_data);
124     }
125 }
126 
tox_friend_name_handler(Messenger * m,uint32_t friend_number,const uint8_t * name,size_t length,void * user_data)127 static void tox_friend_name_handler(Messenger *m, uint32_t friend_number, const uint8_t *name, size_t length,
128                                     void *user_data)
129 {
130     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
131 
132     if (tox_data->tox->friend_name_callback != nullptr) {
133         tox_data->tox->friend_name_callback(tox_data->tox, friend_number, name, length, tox_data->user_data);
134     }
135 }
136 
tox_friend_status_message_handler(Messenger * m,uint32_t friend_number,const uint8_t * message,size_t length,void * user_data)137 static void tox_friend_status_message_handler(Messenger *m, uint32_t friend_number, const uint8_t *message,
138         size_t length, void *user_data)
139 {
140     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
141 
142     if (tox_data->tox->friend_status_message_callback != nullptr) {
143         tox_data->tox->friend_status_message_callback(tox_data->tox, friend_number, message, length, tox_data->user_data);
144     }
145 }
146 
tox_friend_status_handler(Messenger * m,uint32_t friend_number,unsigned int status,void * user_data)147 static void tox_friend_status_handler(Messenger *m, uint32_t friend_number, unsigned int status, void *user_data)
148 {
149     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
150 
151     if (tox_data->tox->friend_status_callback != nullptr) {
152         tox_data->tox->friend_status_callback(tox_data->tox, friend_number, (Tox_User_Status)status, tox_data->user_data);
153     }
154 }
155 
tox_friend_connection_status_handler(Messenger * m,uint32_t friend_number,unsigned int connection_status,void * user_data)156 static void tox_friend_connection_status_handler(Messenger *m, uint32_t friend_number, unsigned int connection_status,
157         void *user_data)
158 {
159     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
160 
161     if (tox_data->tox->friend_connection_status_callback != nullptr) {
162         tox_data->tox->friend_connection_status_callback(tox_data->tox, friend_number, (Tox_Connection)connection_status,
163                 tox_data->user_data);
164     }
165 }
166 
tox_friend_typing_handler(Messenger * m,uint32_t friend_number,bool is_typing,void * user_data)167 static void tox_friend_typing_handler(Messenger *m, uint32_t friend_number, bool is_typing, void *user_data)
168 {
169     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
170 
171     if (tox_data->tox->friend_typing_callback != nullptr) {
172         tox_data->tox->friend_typing_callback(tox_data->tox, friend_number, is_typing, tox_data->user_data);
173     }
174 }
175 
tox_friend_read_receipt_handler(Messenger * m,uint32_t friend_number,uint32_t message_id,void * user_data)176 static void tox_friend_read_receipt_handler(Messenger *m, uint32_t friend_number, uint32_t message_id, void *user_data)
177 {
178     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
179 
180     if (tox_data->tox->friend_read_receipt_callback != nullptr) {
181         tox_data->tox->friend_read_receipt_callback(tox_data->tox, friend_number, message_id, tox_data->user_data);
182     }
183 }
184 
tox_friend_request_handler(Messenger * m,const uint8_t * public_key,const uint8_t * message,size_t length,void * user_data)185 static void tox_friend_request_handler(Messenger *m, const uint8_t *public_key, const uint8_t *message, size_t length,
186                                        void *user_data)
187 {
188     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
189 
190     if (tox_data->tox->friend_request_callback != nullptr) {
191         tox_data->tox->friend_request_callback(tox_data->tox, public_key, message, length, tox_data->user_data);
192     }
193 }
194 
tox_friend_message_handler(Messenger * m,uint32_t friend_number,unsigned int type,const uint8_t * message,size_t length,void * user_data)195 static void tox_friend_message_handler(Messenger *m, uint32_t friend_number, unsigned int type, const uint8_t *message,
196                                        size_t length, void *user_data)
197 {
198     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
199 
200     if (tox_data->tox->friend_message_callback != nullptr) {
201         tox_data->tox->friend_message_callback(tox_data->tox, friend_number, (Tox_Message_Type)type, message, length,
202                                                tox_data->user_data);
203     }
204 }
205 
tox_file_recv_control_handler(Messenger * m,uint32_t friend_number,uint32_t file_number,unsigned int control,void * user_data)206 static void tox_file_recv_control_handler(Messenger *m, uint32_t friend_number, uint32_t file_number,
207         unsigned int control, void *user_data)
208 {
209     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
210 
211     if (tox_data->tox->file_recv_control_callback != nullptr) {
212         tox_data->tox->file_recv_control_callback(tox_data->tox, friend_number, file_number, (Tox_File_Control)control,
213                 tox_data->user_data);
214     }
215 }
216 
tox_file_chunk_request_handler(Messenger * m,uint32_t friend_number,uint32_t file_number,uint64_t position,size_t length,void * user_data)217 static void tox_file_chunk_request_handler(Messenger *m, uint32_t friend_number, uint32_t file_number,
218         uint64_t position, size_t length, void *user_data)
219 {
220     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
221 
222     if (tox_data->tox->file_chunk_request_callback != nullptr) {
223         tox_data->tox->file_chunk_request_callback(tox_data->tox, friend_number, file_number, position, length,
224                 tox_data->user_data);
225     }
226 }
227 
tox_file_recv_handler(Messenger * m,uint32_t friend_number,uint32_t file_number,uint32_t kind,uint64_t file_size,const uint8_t * filename,size_t filename_length,void * user_data)228 static void tox_file_recv_handler(Messenger *m, uint32_t friend_number, uint32_t file_number, uint32_t kind,
229                                   uint64_t file_size, const uint8_t *filename, size_t filename_length, void *user_data)
230 {
231     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
232 
233     if (tox_data->tox->file_recv_callback != nullptr) {
234         tox_data->tox->file_recv_callback(tox_data->tox, friend_number, file_number, kind, file_size, filename, filename_length,
235                                           tox_data->user_data);
236     }
237 }
238 
tox_file_recv_chunk_handler(Messenger * m,uint32_t friend_number,uint32_t file_number,uint64_t position,const uint8_t * data,size_t length,void * user_data)239 static void tox_file_recv_chunk_handler(Messenger *m, uint32_t friend_number, uint32_t file_number, uint64_t position,
240                                         const uint8_t *data, size_t length, void *user_data)
241 {
242     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
243 
244     if (tox_data->tox->file_recv_chunk_callback != nullptr) {
245         tox_data->tox->file_recv_chunk_callback(tox_data->tox, friend_number, file_number, position, data, length,
246                                                 tox_data->user_data);
247     }
248 }
249 
tox_conference_invite_handler(Messenger * m,uint32_t friend_number,int type,const uint8_t * cookie,size_t length,void * user_data)250 static void tox_conference_invite_handler(Messenger *m, uint32_t friend_number, int type, const uint8_t *cookie,
251         size_t length, void *user_data)
252 {
253     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
254 
255     if (tox_data->tox->conference_invite_callback != nullptr) {
256         tox_data->tox->conference_invite_callback(tox_data->tox, friend_number, (Tox_Conference_Type)type, cookie, length,
257                 tox_data->user_data);
258     }
259 }
260 
tox_conference_connected_handler(Messenger * m,uint32_t conference_number,void * user_data)261 static void tox_conference_connected_handler(Messenger *m, uint32_t conference_number, void *user_data)
262 {
263     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
264 
265     if (tox_data->tox->conference_connected_callback != nullptr) {
266         tox_data->tox->conference_connected_callback(tox_data->tox, conference_number, tox_data->user_data);
267     }
268 }
269 
tox_conference_message_handler(Messenger * m,uint32_t conference_number,uint32_t peer_number,int type,const uint8_t * message,size_t length,void * user_data)270 static void tox_conference_message_handler(Messenger *m, uint32_t conference_number, uint32_t peer_number, int type,
271         const uint8_t *message, size_t length, void *user_data)
272 {
273     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
274 
275     if (tox_data->tox->conference_message_callback != nullptr) {
276         tox_data->tox->conference_message_callback(tox_data->tox, conference_number, peer_number, (Tox_Message_Type)type,
277                 message, length, tox_data->user_data);
278     }
279 }
280 
tox_conference_title_handler(Messenger * m,uint32_t conference_number,uint32_t peer_number,const uint8_t * title,size_t length,void * user_data)281 static void tox_conference_title_handler(Messenger *m, uint32_t conference_number, uint32_t peer_number,
282         const uint8_t *title, size_t length, void *user_data)
283 {
284     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
285 
286     if (tox_data->tox->conference_title_callback != nullptr) {
287         tox_data->tox->conference_title_callback(tox_data->tox, conference_number, peer_number, title, length,
288                 tox_data->user_data);
289     }
290 }
291 
tox_conference_peer_name_handler(Messenger * m,uint32_t conference_number,uint32_t peer_number,const uint8_t * name,size_t length,void * user_data)292 static void tox_conference_peer_name_handler(Messenger *m, uint32_t conference_number, uint32_t peer_number,
293         const uint8_t *name, size_t length, void *user_data)
294 {
295     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
296 
297     if (tox_data->tox->conference_peer_name_callback != nullptr) {
298         tox_data->tox->conference_peer_name_callback(tox_data->tox, conference_number, peer_number, name, length,
299                 tox_data->user_data);
300     }
301 }
302 
tox_conference_peer_list_changed_handler(Messenger * m,uint32_t conference_number,void * user_data)303 static void tox_conference_peer_list_changed_handler(Messenger *m, uint32_t conference_number, void *user_data)
304 {
305     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
306 
307     if (tox_data->tox->conference_peer_list_changed_callback != nullptr) {
308         tox_data->tox->conference_peer_list_changed_callback(tox_data->tox, conference_number, tox_data->user_data);
309     }
310 }
311 
tox_friend_lossy_packet_handler(Messenger * m,uint32_t friend_number,uint8_t packet_id,const uint8_t * data,size_t length,void * user_data)312 static void tox_friend_lossy_packet_handler(Messenger *m, uint32_t friend_number, uint8_t packet_id,
313         const uint8_t *data, size_t length, void *user_data)
314 {
315     assert(data != nullptr);
316     assert(length > 0);
317 
318     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
319 
320     if (tox_data->tox->friend_lossy_packet_callback_per_pktid[packet_id] != nullptr) {
321         tox_data->tox->friend_lossy_packet_callback_per_pktid[packet_id](tox_data->tox, friend_number, data, length,
322                 tox_data->user_data);
323     }
324 }
325 
tox_friend_lossless_packet_handler(Messenger * m,uint32_t friend_number,uint8_t packet_id,const uint8_t * data,size_t length,void * user_data)326 static void tox_friend_lossless_packet_handler(Messenger *m, uint32_t friend_number, uint8_t packet_id,
327         const uint8_t *data, size_t length, void *user_data)
328 {
329     assert(data != nullptr);
330     assert(length > 0);
331 
332     struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;
333 
334     if (tox_data->tox->friend_lossless_packet_callback_per_pktid[packet_id] != nullptr) {
335         tox_data->tox->friend_lossless_packet_callback_per_pktid[packet_id](tox_data->tox, friend_number, data, length,
336                 tox_data->user_data);
337     }
338 }
339 
340 
tox_version_is_compatible(uint32_t major,uint32_t minor,uint32_t patch)341 bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch)
342 {
343     return TOX_VERSION_IS_API_COMPATIBLE(major, minor, patch);
344 }
345 
state_load_callback(void * outer,const uint8_t * data,uint32_t length,uint16_t type)346 static State_Load_Status state_load_callback(void *outer, const uint8_t *data, uint32_t length, uint16_t type)
347 {
348     const Tox *tox = (const Tox *)outer;
349     State_Load_Status status = STATE_LOAD_STATUS_CONTINUE;
350 
351     if (messenger_load_state_section(tox->m, data, length, type, &status)
352             || conferences_load_state_section(tox->m->conferences_object, data, length, type, &status)) {
353         return status;
354     }
355 
356     if (type == STATE_TYPE_END) {
357         if (length != 0) {
358             return STATE_LOAD_STATUS_ERROR;
359         }
360 
361         return STATE_LOAD_STATUS_END;
362     }
363 
364     LOGGER_ERROR(tox->m->log, "Load state: contains unrecognized part (len %u, type %u)",
365                  length, type);
366 
367     return STATE_LOAD_STATUS_CONTINUE;
368 }
369 
370 /* Load tox from data of size length. */
tox_load(Tox * tox,const uint8_t * data,uint32_t length)371 static int tox_load(Tox *tox, const uint8_t *data, uint32_t length)
372 {
373     uint32_t data32[2];
374     const uint32_t cookie_len = sizeof(data32);
375 
376     if (length < cookie_len) {
377         return -1;
378     }
379 
380     memcpy(data32, data, sizeof(uint32_t));
381     lendian_bytes_to_host32(data32 + 1, data + sizeof(uint32_t));
382 
383     if (data32[0] != 0 || data32[1] != STATE_COOKIE_GLOBAL) {
384         return -1;
385     }
386 
387     return state_load(tox->m->log, state_load_callback, tox, data + cookie_len,
388                       length - cookie_len, STATE_COOKIE_TYPE);
389 }
390 
391 
tox_new(const struct Tox_Options * options,Tox_Err_New * error)392 Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error)
393 {
394     Tox *tox = (Tox *)calloc(1, sizeof(Tox));
395 
396     if (tox == nullptr) {
397         SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC);
398         return nullptr;
399     }
400 
401     Messenger_Options m_options = {0};
402 
403     bool load_savedata_sk = false;
404     bool load_savedata_tox = false;
405 
406     struct Tox_Options *default_options = nullptr;
407 
408     if (options == nullptr) {
409         Tox_Err_Options_New err;
410         default_options = tox_options_new(&err);
411 
412         switch (err) {
413             case TOX_ERR_OPTIONS_NEW_OK:
414                 break;
415 
416             case TOX_ERR_OPTIONS_NEW_MALLOC:
417                 SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC);
418                 free(tox);
419                 return nullptr;
420         }
421     }
422 
423     const struct Tox_Options *const opts = options != nullptr ? options : default_options;
424     assert(opts != nullptr);
425 
426     if (tox_options_get_savedata_type(opts) != TOX_SAVEDATA_TYPE_NONE) {
427         if (tox_options_get_savedata_data(opts) == nullptr || tox_options_get_savedata_length(opts) == 0) {
428             SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT);
429             tox_options_free(default_options);
430             free(tox);
431             return nullptr;
432         }
433     }
434 
435     if (tox_options_get_savedata_type(opts) == TOX_SAVEDATA_TYPE_SECRET_KEY) {
436         if (tox_options_get_savedata_length(opts) != TOX_SECRET_KEY_SIZE) {
437             SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT);
438             tox_options_free(default_options);
439             free(tox);
440             return nullptr;
441         }
442 
443         load_savedata_sk = true;
444     } else if (tox_options_get_savedata_type(opts) == TOX_SAVEDATA_TYPE_TOX_SAVE) {
445         if (tox_options_get_savedata_length(opts) < TOX_ENC_SAVE_MAGIC_LENGTH) {
446             SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT);
447             tox_options_free(default_options);
448             free(tox);
449             return nullptr;
450         }
451 
452         if (crypto_memcmp(tox_options_get_savedata_data(opts), TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0) {
453             SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_ENCRYPTED);
454             tox_options_free(default_options);
455             free(tox);
456             return nullptr;
457         }
458 
459         load_savedata_tox = true;
460     }
461 
462     m_options.ipv6enabled = tox_options_get_ipv6_enabled(opts);
463     m_options.udp_disabled = !tox_options_get_udp_enabled(opts);
464     m_options.port_range[0] = tox_options_get_start_port(opts);
465     m_options.port_range[1] = tox_options_get_end_port(opts);
466     m_options.tcp_server_port = tox_options_get_tcp_port(opts);
467     m_options.hole_punching_enabled = tox_options_get_hole_punching_enabled(opts);
468     m_options.local_discovery_enabled = tox_options_get_local_discovery_enabled(opts);
469 
470     m_options.log_callback = (logger_cb *)tox_options_get_log_callback(opts);
471     m_options.log_context = tox;
472     m_options.log_user_data = tox_options_get_log_user_data(opts);
473 
474     switch (tox_options_get_proxy_type(opts)) {
475         case TOX_PROXY_TYPE_HTTP:
476             m_options.proxy_info.proxy_type = TCP_PROXY_HTTP;
477             break;
478 
479         case TOX_PROXY_TYPE_SOCKS5:
480             m_options.proxy_info.proxy_type = TCP_PROXY_SOCKS5;
481             break;
482 
483         case TOX_PROXY_TYPE_NONE:
484             m_options.proxy_info.proxy_type = TCP_PROXY_NONE;
485             break;
486 
487         default:
488             SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_TYPE);
489             tox_options_free(default_options);
490             free(tox);
491             return nullptr;
492     }
493 
494     if (m_options.proxy_info.proxy_type != TCP_PROXY_NONE) {
495         if (tox_options_get_proxy_port(opts) == 0) {
496             SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_PORT);
497             tox_options_free(default_options);
498             free(tox);
499             return nullptr;
500         }
501 
502         ip_init(&m_options.proxy_info.ip_port.ip, m_options.ipv6enabled);
503 
504         if (m_options.ipv6enabled) {
505             m_options.proxy_info.ip_port.ip.family = net_family_unspec;
506         }
507 
508         if (addr_resolve_or_parse_ip(tox_options_get_proxy_host(opts), &m_options.proxy_info.ip_port.ip, nullptr) == 0) {
509             SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_HOST);
510             // TODO(irungentoo): TOX_ERR_NEW_PROXY_NOT_FOUND if domain.
511             tox_options_free(default_options);
512             free(tox);
513             return nullptr;
514         }
515 
516         m_options.proxy_info.ip_port.port = net_htons(tox_options_get_proxy_port(opts));
517     }
518 
519     tox->mono_time = mono_time_new();
520 
521     if (tox->mono_time == nullptr) {
522         SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC);
523         tox_options_free(default_options);
524         free(tox);
525         return nullptr;
526     }
527 
528     if (tox_options_get_experimental_thread_safety(opts)) {
529         tox->mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
530 
531         if (tox->mutex == nullptr) {
532             SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC);
533             tox_options_free(default_options);
534             free(tox);
535             return nullptr;
536         }
537 
538 
539         pthread_mutexattr_t attr;
540 
541         pthread_mutexattr_init(&attr);
542         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
543         pthread_mutex_init(tox->mutex, &attr);
544     } else {
545         tox->mutex = nullptr;
546     }
547 
548     lock(tox);
549 
550     unsigned int m_error;
551     tox->m = new_messenger(tox->mono_time, &m_options, &m_error);
552 
553     // TODO(iphydf): Clarify this code, check for NULL before new_groupchats, so
554     // new_groupchats can assume m is non-NULL.
555     if (!new_groupchats(tox->mono_time, tox->m)) {
556         kill_messenger(tox->m);
557 
558         if (m_error == MESSENGER_ERROR_PORT) {
559             SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PORT_ALLOC);
560         } else if (m_error == MESSENGER_ERROR_TCP_SERVER) {
561             SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PORT_ALLOC);
562         } else {
563             SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC);
564         }
565 
566         mono_time_free(tox->mono_time);
567         tox_options_free(default_options);
568         unlock(tox);
569 
570         if (tox->mutex != nullptr) {
571             pthread_mutex_destroy(tox->mutex);
572         }
573 
574         free(tox->mutex);
575         free(tox);
576         return nullptr;
577     }
578 
579     if (load_savedata_tox
580             && tox_load(tox, tox_options_get_savedata_data(opts), tox_options_get_savedata_length(opts)) == -1) {
581         SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT);
582     } else if (load_savedata_sk) {
583         load_secret_key(tox->m->net_crypto, tox_options_get_savedata_data(opts));
584         SET_ERROR_PARAMETER(error, TOX_ERR_NEW_OK);
585     } else {
586         SET_ERROR_PARAMETER(error, TOX_ERR_NEW_OK);
587     }
588 
589     m_callback_namechange(tox->m, tox_friend_name_handler);
590     m_callback_core_connection(tox->m, tox_self_connection_status_handler);
591     m_callback_statusmessage(tox->m, tox_friend_status_message_handler);
592     m_callback_userstatus(tox->m, tox_friend_status_handler);
593     m_callback_connectionstatus(tox->m, tox_friend_connection_status_handler);
594     m_callback_typingchange(tox->m, tox_friend_typing_handler);
595     m_callback_read_receipt(tox->m, tox_friend_read_receipt_handler);
596     m_callback_friendrequest(tox->m, tox_friend_request_handler);
597     m_callback_friendmessage(tox->m, tox_friend_message_handler);
598     callback_file_control(tox->m, tox_file_recv_control_handler);
599     callback_file_reqchunk(tox->m, tox_file_chunk_request_handler);
600     callback_file_sendrequest(tox->m, tox_file_recv_handler);
601     callback_file_data(tox->m, tox_file_recv_chunk_handler);
602     g_callback_group_invite(tox->m->conferences_object, tox_conference_invite_handler);
603     g_callback_group_connected(tox->m->conferences_object, tox_conference_connected_handler);
604     g_callback_group_message(tox->m->conferences_object, tox_conference_message_handler);
605     g_callback_group_title(tox->m->conferences_object, tox_conference_title_handler);
606     g_callback_peer_name(tox->m->conferences_object, tox_conference_peer_name_handler);
607     g_callback_peer_list_changed(tox->m->conferences_object, tox_conference_peer_list_changed_handler);
608     custom_lossy_packet_registerhandler(tox->m, tox_friend_lossy_packet_handler);
609     custom_lossless_packet_registerhandler(tox->m, tox_friend_lossless_packet_handler);
610 
611     tox_options_free(default_options);
612 
613     unlock(tox);
614     return tox;
615 }
616 
tox_kill(Tox * tox)617 void tox_kill(Tox *tox)
618 {
619     if (tox == nullptr) {
620         return;
621     }
622 
623     lock(tox);
624     LOGGER_ASSERT(tox->m->log, tox->m->msi_packet == nullptr, "Attempted to kill tox while toxav is still alive");
625     kill_groupchats(tox->m->conferences_object);
626     kill_messenger(tox->m);
627     mono_time_free(tox->mono_time);
628     unlock(tox);
629 
630     if (tox->mutex != nullptr) {
631         pthread_mutex_destroy(tox->mutex);
632         free(tox->mutex);
633     }
634 
635     free(tox);
636 }
637 
end_size(void)638 static uint32_t end_size(void)
639 {
640     return 2 * sizeof(uint32_t);
641 }
642 
end_save(uint8_t * data)643 static void end_save(uint8_t *data)
644 {
645     state_write_section_header(data, STATE_COOKIE_TYPE, 0, STATE_TYPE_END);
646 }
647 
tox_get_savedata_size(const Tox * tox)648 size_t tox_get_savedata_size(const Tox *tox)
649 {
650     assert(tox != nullptr);
651     lock(tox);
652     size_t ret = 2 * sizeof(uint32_t)
653                  + messenger_size(tox->m)
654                  + conferences_size(tox->m->conferences_object)
655                  + end_size();
656     unlock(tox);
657     return ret;
658 }
659 
tox_get_savedata(const Tox * tox,uint8_t * savedata)660 void tox_get_savedata(const Tox *tox, uint8_t *savedata)
661 {
662     assert(tox != nullptr);
663 
664     if (savedata == nullptr) {
665         return;
666     }
667 
668     memset(savedata, 0, tox_get_savedata_size(tox));
669 
670     lock(tox);
671 
672     const uint32_t size32 = sizeof(uint32_t);
673 
674     // write cookie
675     memset(savedata, 0, size32);
676     savedata += size32;
677     host_to_lendian_bytes32(savedata, STATE_COOKIE_GLOBAL);
678     savedata += size32;
679 
680     savedata = messenger_save(tox->m, savedata);
681     savedata = conferences_save(tox->m->conferences_object, savedata);
682     end_save(savedata);
683 
684     unlock(tox);
685 }
686 
tox_bootstrap(Tox * tox,const char * host,uint16_t port,const uint8_t * public_key,Tox_Err_Bootstrap * error)687 bool tox_bootstrap(Tox *tox, const char *host, uint16_t port, const uint8_t *public_key, Tox_Err_Bootstrap *error)
688 {
689     assert(tox != nullptr);
690 
691     if (!host || !public_key) {
692         SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_NULL);
693         return 0;
694     }
695 
696     if (port == 0) {
697         SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_PORT);
698         return 0;
699     }
700 
701     IP_Port *root;
702 
703     const int32_t count = net_getipport(host, &root, TOX_SOCK_DGRAM);
704 
705     if (count == -1) {
706         net_freeipport(root);
707         SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST);
708         return 0;
709     }
710 
711     unsigned int i;
712 
713     lock(tox);
714 
715     for (i = 0; i < count; ++i) {
716         root[i].port = net_htons(port);
717 
718         onion_add_bs_path_node(tox->m->onion_c, root[i], public_key);
719         dht_bootstrap(tox->m->dht, root[i], public_key);
720     }
721 
722     unlock(tox);
723 
724     net_freeipport(root);
725 
726     if (count) {
727         SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK);
728         return 1;
729     }
730 
731     SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST);
732     return 0;
733 }
734 
tox_add_tcp_relay(Tox * tox,const char * host,uint16_t port,const uint8_t * public_key,Tox_Err_Bootstrap * error)735 bool tox_add_tcp_relay(Tox *tox, const char *host, uint16_t port, const uint8_t *public_key,
736                        Tox_Err_Bootstrap *error)
737 {
738     assert(tox != nullptr);
739 
740     if (!host || !public_key) {
741         SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_NULL);
742         return 0;
743     }
744 
745     if (port == 0) {
746         SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_PORT);
747         return 0;
748     }
749 
750     IP_Port *root;
751 
752     int32_t count = net_getipport(host, &root, TOX_SOCK_STREAM);
753 
754     if (count == -1) {
755         net_freeipport(root);
756         SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST);
757         return 0;
758     }
759 
760     unsigned int i;
761 
762     lock(tox);
763 
764     for (i = 0; i < count; ++i) {
765         root[i].port = net_htons(port);
766 
767         add_tcp_relay(tox->m->net_crypto, root[i], public_key);
768     }
769 
770     unlock(tox);
771 
772     net_freeipport(root);
773 
774     if (count) {
775         SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK);
776         return 1;
777     }
778 
779     SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST);
780     return 0;
781 }
782 
tox_self_get_connection_status(const Tox * tox)783 Tox_Connection tox_self_get_connection_status(const Tox *tox)
784 {
785     assert(tox != nullptr);
786     lock(tox);
787     const unsigned int ret = onion_connection_status(tox->m->onion_c);
788     unlock(tox);
789 
790     if (ret == 2) {
791         return TOX_CONNECTION_UDP;
792     }
793 
794     if (ret == 1) {
795         return TOX_CONNECTION_TCP;
796     }
797 
798     return TOX_CONNECTION_NONE;
799 }
800 
801 
tox_callback_self_connection_status(Tox * tox,tox_self_connection_status_cb * callback)802 void tox_callback_self_connection_status(Tox *tox, tox_self_connection_status_cb *callback)
803 {
804     assert(tox != nullptr);
805     tox->self_connection_status_callback = callback;
806 }
807 
tox_iteration_interval(const Tox * tox)808 uint32_t tox_iteration_interval(const Tox *tox)
809 {
810     assert(tox != nullptr);
811     lock(tox);
812     uint32_t ret = messenger_run_interval(tox->m);
813     unlock(tox);
814     return ret;
815 }
816 
tox_iterate(Tox * tox,void * user_data)817 void tox_iterate(Tox *tox, void *user_data)
818 {
819     assert(tox != nullptr);
820     lock(tox);
821 
822     mono_time_update(tox->mono_time);
823 
824     struct Tox_Userdata tox_data = { tox, user_data };
825     do_messenger(tox->m, &tox_data);
826     do_groupchats(tox->m->conferences_object, &tox_data);
827 
828     unlock(tox);
829 }
830 
tox_self_get_address(const Tox * tox,uint8_t * address)831 void tox_self_get_address(const Tox *tox, uint8_t *address)
832 {
833     assert(tox != nullptr);
834 
835     if (address) {
836         lock(tox);
837         getaddress(tox->m, address);
838         unlock(tox);
839     }
840 }
841 
tox_self_set_nospam(Tox * tox,uint32_t nospam)842 void tox_self_set_nospam(Tox *tox, uint32_t nospam)
843 {
844     assert(tox != nullptr);
845     lock(tox);
846     set_nospam(tox->m->fr, net_htonl(nospam));
847     unlock(tox);
848 }
849 
tox_self_get_nospam(const Tox * tox)850 uint32_t tox_self_get_nospam(const Tox *tox)
851 {
852     assert(tox != nullptr);
853     lock(tox);
854     uint32_t ret = net_ntohl(get_nospam(tox->m->fr));
855     unlock(tox);
856     return ret;
857 }
858 
tox_self_get_public_key(const Tox * tox,uint8_t * public_key)859 void tox_self_get_public_key(const Tox *tox, uint8_t *public_key)
860 {
861     assert(tox != nullptr);
862 
863     if (public_key) {
864         lock(tox);
865         memcpy(public_key, nc_get_self_public_key(tox->m->net_crypto), CRYPTO_PUBLIC_KEY_SIZE);
866         unlock(tox);
867     }
868 }
869 
tox_self_get_secret_key(const Tox * tox,uint8_t * secret_key)870 void tox_self_get_secret_key(const Tox *tox, uint8_t *secret_key)
871 {
872     assert(tox != nullptr);
873 
874     if (secret_key) {
875         lock(tox);
876         memcpy(secret_key, nc_get_self_secret_key(tox->m->net_crypto), CRYPTO_SECRET_KEY_SIZE);
877         unlock(tox);
878     }
879 }
880 
tox_self_set_name(Tox * tox,const uint8_t * name,size_t length,Tox_Err_Set_Info * error)881 bool tox_self_set_name(Tox *tox, const uint8_t *name, size_t length, Tox_Err_Set_Info *error)
882 {
883     assert(tox != nullptr);
884 
885     if (!name && length != 0) {
886         SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_NULL);
887         return 0;
888     }
889 
890     lock(tox);
891 
892     if (setname(tox->m, name, length) == 0) {
893         // TODO(irungentoo): function to set different per group names?
894         send_name_all_groups(tox->m->conferences_object);
895         SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_OK);
896         unlock(tox);
897         return 1;
898     }
899 
900     SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_TOO_LONG);
901     unlock(tox);
902     return 0;
903 }
904 
tox_self_get_name_size(const Tox * tox)905 size_t tox_self_get_name_size(const Tox *tox)
906 {
907     assert(tox != nullptr);
908     lock(tox);
909     size_t ret = m_get_self_name_size(tox->m);
910     unlock(tox);
911     return ret;
912 }
913 
tox_self_get_name(const Tox * tox,uint8_t * name)914 void tox_self_get_name(const Tox *tox, uint8_t *name)
915 {
916     assert(tox != nullptr);
917 
918     if (name) {
919         lock(tox);
920         getself_name(tox->m, name);
921         unlock(tox);
922     }
923 }
924 
tox_self_set_status_message(Tox * tox,const uint8_t * status_message,size_t length,Tox_Err_Set_Info * error)925 bool tox_self_set_status_message(Tox *tox, const uint8_t *status_message, size_t length, Tox_Err_Set_Info *error)
926 {
927     assert(tox != nullptr);
928 
929     if (!status_message && length != 0) {
930         SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_NULL);
931         return 0;
932     }
933 
934     lock(tox);
935 
936     if (m_set_statusmessage(tox->m, status_message, length) == 0) {
937         SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_OK);
938         unlock(tox);
939         return 1;
940     }
941 
942     SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_TOO_LONG);
943     unlock(tox);
944     return 0;
945 }
946 
tox_self_get_status_message_size(const Tox * tox)947 size_t tox_self_get_status_message_size(const Tox *tox)
948 {
949     assert(tox != nullptr);
950     lock(tox);
951     size_t ret = m_get_self_statusmessage_size(tox->m);
952     unlock(tox);
953     return ret;
954 }
955 
tox_self_get_status_message(const Tox * tox,uint8_t * status_message)956 void tox_self_get_status_message(const Tox *tox, uint8_t *status_message)
957 {
958     assert(tox != nullptr);
959 
960     if (status_message) {
961         lock(tox);
962         m_copy_self_statusmessage(tox->m, status_message);
963         unlock(tox);
964     }
965 }
966 
tox_self_set_status(Tox * tox,Tox_User_Status status)967 void tox_self_set_status(Tox *tox, Tox_User_Status status)
968 {
969     assert(tox != nullptr);
970     lock(tox);
971     m_set_userstatus(tox->m, status);
972     unlock(tox);
973 }
974 
tox_self_get_status(const Tox * tox)975 Tox_User_Status tox_self_get_status(const Tox *tox)
976 {
977     assert(tox != nullptr);
978     lock(tox);
979     const uint8_t status = m_get_self_userstatus(tox->m);
980     unlock(tox);
981     return (Tox_User_Status)status;
982 }
983 
set_friend_error(const Logger * log,int32_t ret,Tox_Err_Friend_Add * error)984 static void set_friend_error(const Logger *log, int32_t ret, Tox_Err_Friend_Add *error)
985 {
986     switch (ret) {
987         case FAERR_TOOLONG:
988             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_TOO_LONG);
989             break;
990 
991         case FAERR_NOMESSAGE:
992             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NO_MESSAGE);
993             break;
994 
995         case FAERR_OWNKEY:
996             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OWN_KEY);
997             break;
998 
999         case FAERR_ALREADYSENT:
1000             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_ALREADY_SENT);
1001             break;
1002 
1003         case FAERR_BADCHECKSUM:
1004             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_BAD_CHECKSUM);
1005             break;
1006 
1007         case FAERR_SETNEWNOSPAM:
1008             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM);
1009             break;
1010 
1011         case FAERR_NOMEM:
1012             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_MALLOC);
1013             break;
1014 
1015         default:
1016             /* can't happen */
1017             LOGGER_FATAL(log, "impossible: unknown friend-add error");
1018             break;
1019     }
1020 }
1021 
tox_friend_add(Tox * tox,const uint8_t * address,const uint8_t * message,size_t length,Tox_Err_Friend_Add * error)1022 uint32_t tox_friend_add(Tox *tox, const uint8_t *address, const uint8_t *message, size_t length,
1023                         Tox_Err_Friend_Add *error)
1024 {
1025     assert(tox != nullptr);
1026 
1027     if (!address || !message) {
1028         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NULL);
1029         return UINT32_MAX;
1030     }
1031 
1032     lock(tox);
1033     const int32_t ret = m_addfriend(tox->m, address, message, length);
1034 
1035     if (ret >= 0) {
1036         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OK);
1037         unlock(tox);
1038         return ret;
1039     }
1040 
1041     set_friend_error(tox->m->log, ret, error);
1042     unlock(tox);
1043     return UINT32_MAX;
1044 }
1045 
tox_friend_add_norequest(Tox * tox,const uint8_t * public_key,Tox_Err_Friend_Add * error)1046 uint32_t tox_friend_add_norequest(Tox *tox, const uint8_t *public_key, Tox_Err_Friend_Add *error)
1047 {
1048     assert(tox != nullptr);
1049 
1050     if (!public_key) {
1051         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NULL);
1052         return UINT32_MAX;
1053     }
1054 
1055     lock(tox);
1056     const int32_t ret = m_addfriend_norequest(tox->m, public_key);
1057 
1058     if (ret >= 0) {
1059         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OK);
1060         unlock(tox);
1061         return ret;
1062     }
1063 
1064     set_friend_error(tox->m->log, ret, error);
1065     unlock(tox);
1066     return UINT32_MAX;
1067 }
1068 
tox_friend_delete(Tox * tox,uint32_t friend_number,Tox_Err_Friend_Delete * error)1069 bool tox_friend_delete(Tox *tox, uint32_t friend_number, Tox_Err_Friend_Delete *error)
1070 {
1071     assert(tox != nullptr);
1072     lock(tox);
1073     const int ret = m_delfriend(tox->m, friend_number);
1074     unlock(tox);
1075 
1076     // TODO(irungentoo): handle if realloc fails?
1077     if (ret == -1) {
1078         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_DELETE_FRIEND_NOT_FOUND);
1079         return 0;
1080     }
1081 
1082     SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_DELETE_OK);
1083     return 1;
1084 }
1085 
tox_friend_by_public_key(const Tox * tox,const uint8_t * public_key,Tox_Err_Friend_By_Public_Key * error)1086 uint32_t tox_friend_by_public_key(const Tox *tox, const uint8_t *public_key, Tox_Err_Friend_By_Public_Key *error)
1087 {
1088     assert(tox != nullptr);
1089 
1090     if (!public_key) {
1091         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_NULL);
1092         return UINT32_MAX;
1093     }
1094 
1095     lock(tox);
1096     const int32_t ret = getfriend_id(tox->m, public_key);
1097     unlock(tox);
1098 
1099     if (ret == -1) {
1100         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_NOT_FOUND);
1101         return UINT32_MAX;
1102     }
1103 
1104     SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK);
1105     return ret;
1106 }
1107 
tox_friend_get_public_key(const Tox * tox,uint32_t friend_number,uint8_t * public_key,Tox_Err_Friend_Get_Public_Key * error)1108 bool tox_friend_get_public_key(const Tox *tox, uint32_t friend_number, uint8_t *public_key,
1109                                Tox_Err_Friend_Get_Public_Key *error)
1110 {
1111     assert(tox != nullptr);
1112 
1113     if (!public_key) {
1114         return 0;
1115     }
1116 
1117     lock(tox);
1118 
1119     if (get_real_pk(tox->m, friend_number, public_key) == -1) {
1120         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_PUBLIC_KEY_FRIEND_NOT_FOUND);
1121         unlock(tox);
1122         return 0;
1123     }
1124 
1125     SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK);
1126     unlock(tox);
1127     return 1;
1128 }
1129 
tox_friend_exists(const Tox * tox,uint32_t friend_number)1130 bool tox_friend_exists(const Tox *tox, uint32_t friend_number)
1131 {
1132     assert(tox != nullptr);
1133     lock(tox);
1134     bool ret = m_friend_exists(tox->m, friend_number);
1135     unlock(tox);
1136     return ret;
1137 }
1138 
tox_friend_get_last_online(const Tox * tox,uint32_t friend_number,Tox_Err_Friend_Get_Last_Online * error)1139 uint64_t tox_friend_get_last_online(const Tox *tox, uint32_t friend_number, Tox_Err_Friend_Get_Last_Online *error)
1140 {
1141     assert(tox != nullptr);
1142     lock(tox);
1143     const uint64_t timestamp = m_get_last_online(tox->m, friend_number);
1144     unlock(tox);
1145 
1146     if (timestamp == UINT64_MAX) {
1147         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_LAST_ONLINE_FRIEND_NOT_FOUND);
1148         return UINT64_MAX;
1149     }
1150 
1151     SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_LAST_ONLINE_OK);
1152     return timestamp;
1153 }
1154 
tox_self_get_friend_list_size(const Tox * tox)1155 size_t tox_self_get_friend_list_size(const Tox *tox)
1156 {
1157     assert(tox != nullptr);
1158     lock(tox);
1159     size_t ret = count_friendlist(tox->m);
1160     unlock(tox);
1161     return ret;
1162 }
1163 
tox_self_get_friend_list(const Tox * tox,uint32_t * friend_list)1164 void tox_self_get_friend_list(const Tox *tox, uint32_t *friend_list)
1165 {
1166     assert(tox != nullptr);
1167 
1168     if (friend_list) {
1169         lock(tox);
1170         // TODO(irungentoo): size parameter?
1171         copy_friendlist(tox->m, friend_list, count_friendlist(tox->m));
1172         unlock(tox);
1173     }
1174 }
1175 
tox_friend_get_name_size(const Tox * tox,uint32_t friend_number,Tox_Err_Friend_Query * error)1176 size_t tox_friend_get_name_size(const Tox *tox, uint32_t friend_number, Tox_Err_Friend_Query *error)
1177 {
1178     assert(tox != nullptr);
1179     lock(tox);
1180     const int ret = m_get_name_size(tox->m, friend_number);
1181     unlock(tox);
1182 
1183     if (ret == -1) {
1184         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
1185         return SIZE_MAX;
1186     }
1187 
1188     SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);
1189     return ret;
1190 }
1191 
tox_friend_get_name(const Tox * tox,uint32_t friend_number,uint8_t * name,Tox_Err_Friend_Query * error)1192 bool tox_friend_get_name(const Tox *tox, uint32_t friend_number, uint8_t *name, Tox_Err_Friend_Query *error)
1193 {
1194     assert(tox != nullptr);
1195 
1196     if (!name) {
1197         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_NULL);
1198         return 0;
1199     }
1200 
1201     lock(tox);
1202     const int ret = getname(tox->m, friend_number, name);
1203     unlock(tox);
1204 
1205     if (ret == -1) {
1206         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
1207         return 0;
1208     }
1209 
1210     SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);
1211     return 1;
1212 }
1213 
tox_callback_friend_name(Tox * tox,tox_friend_name_cb * callback)1214 void tox_callback_friend_name(Tox *tox, tox_friend_name_cb *callback)
1215 {
1216     assert(tox != nullptr);
1217     tox->friend_name_callback = callback;
1218 }
1219 
tox_friend_get_status_message_size(const Tox * tox,uint32_t friend_number,Tox_Err_Friend_Query * error)1220 size_t tox_friend_get_status_message_size(const Tox *tox, uint32_t friend_number, Tox_Err_Friend_Query *error)
1221 {
1222     assert(tox != nullptr);
1223     lock(tox);
1224     const int ret = m_get_statusmessage_size(tox->m, friend_number);
1225     unlock(tox);
1226 
1227     if (ret == -1) {
1228         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
1229         return SIZE_MAX;
1230     }
1231 
1232     SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);
1233     return ret;
1234 }
1235 
tox_friend_get_status_message(const Tox * tox,uint32_t friend_number,uint8_t * status_message,Tox_Err_Friend_Query * error)1236 bool tox_friend_get_status_message(const Tox *tox, uint32_t friend_number, uint8_t *status_message,
1237                                    Tox_Err_Friend_Query *error)
1238 {
1239     assert(tox != nullptr);
1240 
1241     if (!status_message) {
1242         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_NULL);
1243         return false;
1244     }
1245 
1246     lock(tox);
1247     const int size = m_get_statusmessage_size(tox->m, friend_number);
1248 
1249     if (size == -1) {
1250         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
1251         unlock(tox);
1252         return false;
1253     }
1254 
1255     const int ret = m_copy_statusmessage(tox->m, friend_number, status_message, size);
1256     LOGGER_ASSERT(tox->m->log, ret == size, "concurrency problem: friend status message changed");
1257 
1258     SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);
1259     unlock(tox);
1260     return ret == size;
1261 }
1262 
tox_callback_friend_status_message(Tox * tox,tox_friend_status_message_cb * callback)1263 void tox_callback_friend_status_message(Tox *tox, tox_friend_status_message_cb *callback)
1264 {
1265     assert(tox != nullptr);
1266     tox->friend_status_message_callback = callback;
1267 }
1268 
tox_friend_get_status(const Tox * tox,uint32_t friend_number,Tox_Err_Friend_Query * error)1269 Tox_User_Status tox_friend_get_status(const Tox *tox, uint32_t friend_number, Tox_Err_Friend_Query *error)
1270 {
1271     assert(tox != nullptr);
1272     lock(tox);
1273     const int ret = m_get_userstatus(tox->m, friend_number);
1274     unlock(tox);
1275 
1276     if (ret == USERSTATUS_INVALID) {
1277         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
1278         return (Tox_User_Status)(TOX_USER_STATUS_BUSY + 1);
1279     }
1280 
1281     SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);
1282     return (Tox_User_Status)ret;
1283 }
1284 
tox_callback_friend_status(Tox * tox,tox_friend_status_cb * callback)1285 void tox_callback_friend_status(Tox *tox, tox_friend_status_cb *callback)
1286 {
1287     assert(tox != nullptr);
1288     tox->friend_status_callback = callback;
1289 }
1290 
tox_friend_get_connection_status(const Tox * tox,uint32_t friend_number,Tox_Err_Friend_Query * error)1291 Tox_Connection tox_friend_get_connection_status(const Tox *tox, uint32_t friend_number, Tox_Err_Friend_Query *error)
1292 {
1293     assert(tox != nullptr);
1294     lock(tox);
1295     const int ret = m_get_friend_connectionstatus(tox->m, friend_number);
1296     unlock(tox);
1297 
1298     if (ret == -1) {
1299         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
1300         return TOX_CONNECTION_NONE;
1301     }
1302 
1303     SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);
1304     return (Tox_Connection)ret;
1305 }
1306 
tox_callback_friend_connection_status(Tox * tox,tox_friend_connection_status_cb * callback)1307 void tox_callback_friend_connection_status(Tox *tox, tox_friend_connection_status_cb *callback)
1308 {
1309     assert(tox != nullptr);
1310     tox->friend_connection_status_callback = callback;
1311 }
1312 
tox_friend_get_typing(const Tox * tox,uint32_t friend_number,Tox_Err_Friend_Query * error)1313 bool tox_friend_get_typing(const Tox *tox, uint32_t friend_number, Tox_Err_Friend_Query *error)
1314 {
1315     assert(tox != nullptr);
1316     lock(tox);
1317     const int ret = m_get_istyping(tox->m, friend_number);
1318     unlock(tox);
1319 
1320     if (ret == -1) {
1321         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);
1322         return 0;
1323     }
1324 
1325     SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);
1326     return !!ret;
1327 }
1328 
tox_callback_friend_typing(Tox * tox,tox_friend_typing_cb * callback)1329 void tox_callback_friend_typing(Tox *tox, tox_friend_typing_cb *callback)
1330 {
1331     assert(tox != nullptr);
1332     tox->friend_typing_callback = callback;
1333 }
1334 
tox_self_set_typing(Tox * tox,uint32_t friend_number,bool typing,Tox_Err_Set_Typing * error)1335 bool tox_self_set_typing(Tox *tox, uint32_t friend_number, bool typing, Tox_Err_Set_Typing *error)
1336 {
1337     assert(tox != nullptr);
1338     lock(tox);
1339 
1340     if (m_set_usertyping(tox->m, friend_number, typing) == -1) {
1341         SET_ERROR_PARAMETER(error, TOX_ERR_SET_TYPING_FRIEND_NOT_FOUND);
1342         unlock(tox);
1343         return 0;
1344     }
1345 
1346     SET_ERROR_PARAMETER(error, TOX_ERR_SET_TYPING_OK);
1347     unlock(tox);
1348     return 1;
1349 }
1350 
set_message_error(const Logger * log,int ret,Tox_Err_Friend_Send_Message * error)1351 static void set_message_error(const Logger *log, int ret, Tox_Err_Friend_Send_Message *error)
1352 {
1353     switch (ret) {
1354         case 0:
1355             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_OK);
1356             break;
1357 
1358         case -1:
1359             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_FOUND);
1360             break;
1361 
1362         case -2:
1363             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_TOO_LONG);
1364             break;
1365 
1366         case -3:
1367             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_CONNECTED);
1368             break;
1369 
1370         case -4:
1371             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ);
1372             break;
1373 
1374         case -5:
1375             LOGGER_FATAL(log, "impossible: Messenger and Tox disagree on message types");
1376             break;
1377 
1378         default:
1379             /* can't happen */
1380             LOGGER_FATAL(log, "impossible: unknown send-message error: %d", ret);
1381             break;
1382     }
1383 }
1384 
tox_friend_send_message(Tox * tox,uint32_t friend_number,Tox_Message_Type type,const uint8_t * message,size_t length,Tox_Err_Friend_Send_Message * error)1385 uint32_t tox_friend_send_message(Tox *tox, uint32_t friend_number, Tox_Message_Type type, const uint8_t *message,
1386                                  size_t length, Tox_Err_Friend_Send_Message *error)
1387 {
1388     assert(tox != nullptr);
1389 
1390     if (!message) {
1391         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_NULL);
1392         return 0;
1393     }
1394 
1395     if (!length) {
1396         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_EMPTY);
1397         return 0;
1398     }
1399 
1400     uint32_t message_id = 0;
1401     lock(tox);
1402     set_message_error(tox->m->log, m_send_message_generic(tox->m, friend_number, type, message, length, &message_id),
1403                       error);
1404     unlock(tox);
1405     return message_id;
1406 }
1407 
tox_callback_friend_read_receipt(Tox * tox,tox_friend_read_receipt_cb * callback)1408 void tox_callback_friend_read_receipt(Tox *tox, tox_friend_read_receipt_cb *callback)
1409 {
1410     assert(tox != nullptr);
1411     tox->friend_read_receipt_callback = callback;
1412 }
1413 
tox_callback_friend_request(Tox * tox,tox_friend_request_cb * callback)1414 void tox_callback_friend_request(Tox *tox, tox_friend_request_cb *callback)
1415 {
1416     assert(tox != nullptr);
1417     tox->friend_request_callback = callback;
1418 }
1419 
tox_callback_friend_message(Tox * tox,tox_friend_message_cb * callback)1420 void tox_callback_friend_message(Tox *tox, tox_friend_message_cb *callback)
1421 {
1422     assert(tox != nullptr);
1423     tox->friend_message_callback = callback;
1424 }
1425 
tox_hash(uint8_t * hash,const uint8_t * data,size_t length)1426 bool tox_hash(uint8_t *hash, const uint8_t *data, size_t length)
1427 {
1428     if (!hash || (length && !data)) {
1429         return 0;
1430     }
1431 
1432     crypto_sha256(hash, data, length);
1433     return 1;
1434 }
1435 
tox_file_control(Tox * tox,uint32_t friend_number,uint32_t file_number,Tox_File_Control control,Tox_Err_File_Control * error)1436 bool tox_file_control(Tox *tox, uint32_t friend_number, uint32_t file_number, Tox_File_Control control,
1437                       Tox_Err_File_Control *error)
1438 {
1439     assert(tox != nullptr);
1440     lock(tox);
1441     const int ret = file_control(tox->m, friend_number, file_number, control);
1442     unlock(tox);
1443 
1444     if (ret == 0) {
1445         SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_OK);
1446         return 1;
1447     }
1448 
1449     switch (ret) {
1450         case -1:
1451             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND);
1452             return 0;
1453 
1454         case -2:
1455             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED);
1456             return 0;
1457 
1458         case -3:
1459             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_NOT_FOUND);
1460             return 0;
1461 
1462         case -4:
1463             /* can't happen */
1464             return 0;
1465 
1466         case -5:
1467             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_ALREADY_PAUSED);
1468             return 0;
1469 
1470         case -6:
1471             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_DENIED);
1472             return 0;
1473 
1474         case -7:
1475             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_NOT_PAUSED);
1476             return 0;
1477 
1478         case -8:
1479             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_SENDQ);
1480             return 0;
1481     }
1482 
1483     /* can't happen */
1484     return 0;
1485 }
1486 
tox_file_seek(Tox * tox,uint32_t friend_number,uint32_t file_number,uint64_t position,Tox_Err_File_Seek * error)1487 bool tox_file_seek(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position,
1488                    Tox_Err_File_Seek *error)
1489 {
1490     assert(tox != nullptr);
1491     lock(tox);
1492     const int ret = file_seek(tox->m, friend_number, file_number, position);
1493     unlock(tox);
1494 
1495     if (ret == 0) {
1496         SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_OK);
1497         return 1;
1498     }
1499 
1500     switch (ret) {
1501         case -1:
1502             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_FRIEND_NOT_FOUND);
1503             return 0;
1504 
1505         case -2:
1506             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_FRIEND_NOT_CONNECTED);
1507             return 0;
1508 
1509         case -3:
1510             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_NOT_FOUND);
1511             return 0;
1512 
1513         case -4: // fall-through
1514         case -5:
1515             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_DENIED);
1516             return 0;
1517 
1518         case -6:
1519             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_INVALID_POSITION);
1520             return 0;
1521 
1522         case -8:
1523             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_SENDQ);
1524             return 0;
1525     }
1526 
1527     /* can't happen */
1528     return 0;
1529 }
1530 
tox_callback_file_recv_control(Tox * tox,tox_file_recv_control_cb * callback)1531 void tox_callback_file_recv_control(Tox *tox, tox_file_recv_control_cb *callback)
1532 {
1533     assert(tox != nullptr);
1534     tox->file_recv_control_callback = callback;
1535 }
1536 
tox_file_get_file_id(const Tox * tox,uint32_t friend_number,uint32_t file_number,uint8_t * file_id,Tox_Err_File_Get * error)1537 bool tox_file_get_file_id(const Tox *tox, uint32_t friend_number, uint32_t file_number, uint8_t *file_id,
1538                           Tox_Err_File_Get *error)
1539 {
1540     assert(tox != nullptr);
1541 
1542     if (!file_id) {
1543         SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_NULL);
1544         return 0;
1545     }
1546 
1547     lock(tox);
1548     const int ret = file_get_id(tox->m, friend_number, file_number, file_id);
1549     unlock(tox);
1550 
1551     if (ret == 0) {
1552         SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_OK);
1553         return 1;
1554     }
1555 
1556     if (ret == -1) {
1557         SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_FRIEND_NOT_FOUND);
1558     } else {
1559         SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_NOT_FOUND);
1560     }
1561 
1562     return 0;
1563 }
1564 
tox_file_send(Tox * tox,uint32_t friend_number,uint32_t kind,uint64_t file_size,const uint8_t * file_id,const uint8_t * filename,size_t filename_length,Tox_Err_File_Send * error)1565 uint32_t tox_file_send(Tox *tox, uint32_t friend_number, uint32_t kind, uint64_t file_size, const uint8_t *file_id,
1566                        const uint8_t *filename, size_t filename_length, Tox_Err_File_Send *error)
1567 {
1568     assert(tox != nullptr);
1569 
1570     if (filename_length && !filename) {
1571         SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NULL);
1572         return UINT32_MAX;
1573     }
1574 
1575     uint8_t f_id[FILE_ID_LENGTH];
1576 
1577     if (!file_id) {
1578         /* Tox keys are 32 bytes like FILE_ID_LENGTH. */
1579         new_symmetric_key(f_id);
1580         file_id = f_id;
1581     }
1582 
1583     lock(tox);
1584     const long int file_num = new_filesender(tox->m, friend_number, kind, file_size, file_id, filename, filename_length);
1585     unlock(tox);
1586 
1587     if (file_num >= 0) {
1588         SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_OK);
1589         return file_num;
1590     }
1591 
1592     switch (file_num) {
1593         case -1:
1594             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND);
1595             return UINT32_MAX;
1596 
1597         case -2:
1598             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NAME_TOO_LONG);
1599             return UINT32_MAX;
1600 
1601         case -3:
1602             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_TOO_MANY);
1603             return UINT32_MAX;
1604 
1605         case -4:
1606             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED);
1607             return UINT32_MAX;
1608     }
1609 
1610     /* can't happen */
1611     return UINT32_MAX;
1612 }
1613 
tox_file_send_chunk(Tox * tox,uint32_t friend_number,uint32_t file_number,uint64_t position,const uint8_t * data,size_t length,Tox_Err_File_Send_Chunk * error)1614 bool tox_file_send_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, const uint8_t *data,
1615                          size_t length, Tox_Err_File_Send_Chunk *error)
1616 {
1617     assert(tox != nullptr);
1618     lock(tox);
1619     const int ret = file_data(tox->m, friend_number, file_number, position, data, length);
1620     unlock(tox);
1621 
1622     if (ret == 0) {
1623         SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_OK);
1624         return 1;
1625     }
1626 
1627     switch (ret) {
1628         case -1:
1629             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_FOUND);
1630             return 0;
1631 
1632         case -2:
1633             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED);
1634             return 0;
1635 
1636         case -3:
1637             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND);
1638             return 0;
1639 
1640         case -4:
1641             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING);
1642             return 0;
1643 
1644         case -5:
1645             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_INVALID_LENGTH);
1646             return 0;
1647 
1648         case -6:
1649             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_SENDQ);
1650             return 0;
1651 
1652         case -7:
1653             SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_WRONG_POSITION);
1654             return 0;
1655     }
1656 
1657     /* can't happen */
1658     return 0;
1659 }
1660 
tox_callback_file_chunk_request(Tox * tox,tox_file_chunk_request_cb * callback)1661 void tox_callback_file_chunk_request(Tox *tox, tox_file_chunk_request_cb *callback)
1662 {
1663     assert(tox != nullptr);
1664     tox->file_chunk_request_callback = callback;
1665 }
1666 
tox_callback_file_recv(Tox * tox,tox_file_recv_cb * callback)1667 void tox_callback_file_recv(Tox *tox, tox_file_recv_cb *callback)
1668 {
1669     assert(tox != nullptr);
1670     tox->file_recv_callback = callback;
1671 }
1672 
tox_callback_file_recv_chunk(Tox * tox,tox_file_recv_chunk_cb * callback)1673 void tox_callback_file_recv_chunk(Tox *tox, tox_file_recv_chunk_cb *callback)
1674 {
1675     assert(tox != nullptr);
1676     tox->file_recv_chunk_callback = callback;
1677 }
1678 
tox_callback_conference_invite(Tox * tox,tox_conference_invite_cb * callback)1679 void tox_callback_conference_invite(Tox *tox, tox_conference_invite_cb *callback)
1680 {
1681     assert(tox != nullptr);
1682     tox->conference_invite_callback = callback;
1683 }
1684 
tox_callback_conference_connected(Tox * tox,tox_conference_connected_cb * callback)1685 void tox_callback_conference_connected(Tox *tox, tox_conference_connected_cb *callback)
1686 {
1687     assert(tox != nullptr);
1688     tox->conference_connected_callback = callback;
1689 }
1690 
tox_callback_conference_message(Tox * tox,tox_conference_message_cb * callback)1691 void tox_callback_conference_message(Tox *tox, tox_conference_message_cb *callback)
1692 {
1693     assert(tox != nullptr);
1694     tox->conference_message_callback = callback;
1695 }
1696 
tox_callback_conference_title(Tox * tox,tox_conference_title_cb * callback)1697 void tox_callback_conference_title(Tox *tox, tox_conference_title_cb *callback)
1698 {
1699     assert(tox != nullptr);
1700     tox->conference_title_callback = callback;
1701 }
1702 
tox_callback_conference_peer_name(Tox * tox,tox_conference_peer_name_cb * callback)1703 void tox_callback_conference_peer_name(Tox *tox, tox_conference_peer_name_cb *callback)
1704 {
1705     assert(tox != nullptr);
1706     tox->conference_peer_name_callback = callback;
1707 }
1708 
tox_callback_conference_peer_list_changed(Tox * tox,tox_conference_peer_list_changed_cb * callback)1709 void tox_callback_conference_peer_list_changed(Tox *tox, tox_conference_peer_list_changed_cb *callback)
1710 {
1711     assert(tox != nullptr);
1712     tox->conference_peer_list_changed_callback = callback;
1713 }
1714 
tox_conference_new(Tox * tox,Tox_Err_Conference_New * error)1715 uint32_t tox_conference_new(Tox *tox, Tox_Err_Conference_New *error)
1716 {
1717     assert(tox != nullptr);
1718     lock(tox);
1719     const int ret = add_groupchat(tox->m->conferences_object, GROUPCHAT_TYPE_TEXT);
1720     unlock(tox);
1721 
1722     if (ret == -1) {
1723         SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_NEW_INIT);
1724         return UINT32_MAX;
1725     }
1726 
1727     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_NEW_OK);
1728     return ret;
1729 }
1730 
tox_conference_delete(Tox * tox,uint32_t conference_number,Tox_Err_Conference_Delete * error)1731 bool tox_conference_delete(Tox *tox, uint32_t conference_number, Tox_Err_Conference_Delete *error)
1732 {
1733     assert(tox != nullptr);
1734     lock(tox);
1735     const int ret = del_groupchat(tox->m->conferences_object, conference_number, true);
1736     unlock(tox);
1737 
1738     if (ret == -1) {
1739         SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_DELETE_CONFERENCE_NOT_FOUND);
1740         return false;
1741     }
1742 
1743     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_DELETE_OK);
1744     return true;
1745 }
1746 
tox_conference_peer_count(const Tox * tox,uint32_t conference_number,Tox_Err_Conference_Peer_Query * error)1747 uint32_t tox_conference_peer_count(const Tox *tox, uint32_t conference_number, Tox_Err_Conference_Peer_Query *error)
1748 {
1749     assert(tox != nullptr);
1750     lock(tox);
1751     const int ret = group_number_peers(tox->m->conferences_object, conference_number, false);
1752     unlock(tox);
1753 
1754     if (ret == -1) {
1755         SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
1756         return UINT32_MAX;
1757     }
1758 
1759     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
1760     return ret;
1761 }
1762 
tox_conference_peer_get_name_size(const Tox * tox,uint32_t conference_number,uint32_t peer_number,Tox_Err_Conference_Peer_Query * error)1763 size_t tox_conference_peer_get_name_size(const Tox *tox, uint32_t conference_number, uint32_t peer_number,
1764         Tox_Err_Conference_Peer_Query *error)
1765 {
1766     assert(tox != nullptr);
1767     lock(tox);
1768     const int ret = group_peername_size(tox->m->conferences_object, conference_number, peer_number, false);
1769     unlock(tox);
1770 
1771     switch (ret) {
1772         case -1:
1773             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
1774             return -1;
1775 
1776         case -2:
1777             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
1778             return -1;
1779     }
1780 
1781     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
1782     return ret;
1783 }
1784 
tox_conference_peer_get_name(const Tox * tox,uint32_t conference_number,uint32_t peer_number,uint8_t * name,Tox_Err_Conference_Peer_Query * error)1785 bool tox_conference_peer_get_name(const Tox *tox, uint32_t conference_number, uint32_t peer_number, uint8_t *name,
1786                                   Tox_Err_Conference_Peer_Query *error)
1787 {
1788     assert(tox != nullptr);
1789     lock(tox);
1790     const int ret = group_peername(tox->m->conferences_object, conference_number, peer_number, name, false);
1791     unlock(tox);
1792 
1793     switch (ret) {
1794         case -1:
1795             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
1796             return false;
1797 
1798         case -2:
1799             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
1800             return false;
1801     }
1802 
1803     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
1804     return true;
1805 }
1806 
tox_conference_peer_get_public_key(const Tox * tox,uint32_t conference_number,uint32_t peer_number,uint8_t * public_key,Tox_Err_Conference_Peer_Query * error)1807 bool tox_conference_peer_get_public_key(const Tox *tox, uint32_t conference_number, uint32_t peer_number,
1808                                         uint8_t *public_key, Tox_Err_Conference_Peer_Query *error)
1809 {
1810     assert(tox != nullptr);
1811     lock(tox);
1812     const int ret = group_peer_pubkey(tox->m->conferences_object, conference_number, peer_number, public_key, false);
1813     unlock(tox);
1814 
1815     switch (ret) {
1816         case -1:
1817             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
1818             return false;
1819 
1820         case -2:
1821             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
1822             return false;
1823     }
1824 
1825     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
1826     return true;
1827 }
1828 
tox_conference_peer_number_is_ours(const Tox * tox,uint32_t conference_number,uint32_t peer_number,Tox_Err_Conference_Peer_Query * error)1829 bool tox_conference_peer_number_is_ours(const Tox *tox, uint32_t conference_number, uint32_t peer_number,
1830                                         Tox_Err_Conference_Peer_Query *error)
1831 {
1832     assert(tox != nullptr);
1833     lock(tox);
1834     const int ret = group_peernumber_is_ours(tox->m->conferences_object, conference_number, peer_number);
1835     unlock(tox);
1836 
1837     switch (ret) {
1838         case -1:
1839             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
1840             return false;
1841 
1842         case -2:
1843             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
1844             return false;
1845 
1846         case -3:
1847             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_NO_CONNECTION);
1848             return false;
1849     }
1850 
1851     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
1852     return ret;
1853 }
1854 
tox_conference_offline_peer_count(const Tox * tox,uint32_t conference_number,Tox_Err_Conference_Peer_Query * error)1855 uint32_t tox_conference_offline_peer_count(const Tox *tox, uint32_t conference_number,
1856         Tox_Err_Conference_Peer_Query *error)
1857 {
1858     assert(tox != nullptr);
1859     lock(tox);
1860     const int ret = group_number_peers(tox->m->conferences_object, conference_number, true);
1861     unlock(tox);
1862 
1863     if (ret == -1) {
1864         SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
1865         return UINT32_MAX;
1866     }
1867 
1868     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
1869     return ret;
1870 }
1871 
tox_conference_offline_peer_get_name_size(const Tox * tox,uint32_t conference_number,uint32_t offline_peer_number,Tox_Err_Conference_Peer_Query * error)1872 size_t tox_conference_offline_peer_get_name_size(const Tox *tox, uint32_t conference_number,
1873         uint32_t offline_peer_number,
1874         Tox_Err_Conference_Peer_Query *error)
1875 {
1876     assert(tox != nullptr);
1877     lock(tox);
1878     const int ret = group_peername_size(tox->m->conferences_object, conference_number, offline_peer_number, true);
1879     unlock(tox);
1880 
1881     switch (ret) {
1882         case -1:
1883             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
1884             return -1;
1885 
1886         case -2:
1887             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
1888             return -1;
1889     }
1890 
1891     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
1892     return ret;
1893 }
1894 
tox_conference_offline_peer_get_name(const Tox * tox,uint32_t conference_number,uint32_t offline_peer_number,uint8_t * name,Tox_Err_Conference_Peer_Query * error)1895 bool tox_conference_offline_peer_get_name(const Tox *tox, uint32_t conference_number, uint32_t offline_peer_number,
1896         uint8_t *name,
1897         Tox_Err_Conference_Peer_Query *error)
1898 {
1899     assert(tox != nullptr);
1900     lock(tox);
1901     const int ret = group_peername(tox->m->conferences_object, conference_number, offline_peer_number, name, true);
1902     unlock(tox);
1903 
1904     switch (ret) {
1905         case -1:
1906             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
1907             return false;
1908 
1909         case -2:
1910             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
1911             return false;
1912     }
1913 
1914     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
1915     return true;
1916 }
1917 
tox_conference_offline_peer_get_public_key(const Tox * tox,uint32_t conference_number,uint32_t offline_peer_number,uint8_t * public_key,Tox_Err_Conference_Peer_Query * error)1918 bool tox_conference_offline_peer_get_public_key(const Tox *tox, uint32_t conference_number,
1919         uint32_t offline_peer_number,
1920         uint8_t *public_key, Tox_Err_Conference_Peer_Query *error)
1921 {
1922     assert(tox != nullptr);
1923     lock(tox);
1924     const int ret = group_peer_pubkey(tox->m->conferences_object, conference_number, offline_peer_number, public_key, true);
1925     unlock(tox);
1926 
1927     switch (ret) {
1928         case -1:
1929             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
1930             return false;
1931 
1932         case -2:
1933             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
1934             return false;
1935     }
1936 
1937     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
1938     return true;
1939 }
1940 
tox_conference_offline_peer_get_last_active(const Tox * tox,uint32_t conference_number,uint32_t offline_peer_number,Tox_Err_Conference_Peer_Query * error)1941 uint64_t tox_conference_offline_peer_get_last_active(const Tox *tox, uint32_t conference_number,
1942         uint32_t offline_peer_number,
1943         Tox_Err_Conference_Peer_Query *error)
1944 {
1945     assert(tox != nullptr);
1946     uint64_t last_active = UINT64_MAX;
1947     lock(tox);
1948     const int ret = group_frozen_last_active(tox->m->conferences_object, conference_number, offline_peer_number,
1949                     &last_active);
1950     unlock(tox);
1951 
1952     switch (ret) {
1953         case -1:
1954             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND);
1955             return UINT64_MAX;
1956 
1957         case -2:
1958             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND);
1959             return UINT64_MAX;
1960     }
1961 
1962     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK);
1963     return last_active;
1964 }
1965 
tox_conference_set_max_offline(Tox * tox,uint32_t conference_number,uint32_t max_offline_peers,Tox_Err_Conference_Set_Max_Offline * error)1966 bool tox_conference_set_max_offline(Tox *tox, uint32_t conference_number,
1967                                     uint32_t max_offline_peers,
1968                                     Tox_Err_Conference_Set_Max_Offline *error)
1969 {
1970     assert(tox != nullptr);
1971     lock(tox);
1972     const int ret = group_set_max_frozen(tox->m->conferences_object, conference_number, max_offline_peers);
1973     unlock(tox);
1974 
1975     if (ret == -1) {
1976         SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_CONFERENCE_NOT_FOUND);
1977         return false;
1978     }
1979 
1980     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SET_MAX_OFFLINE_OK);
1981     return true;
1982 }
1983 
tox_conference_invite(Tox * tox,uint32_t friend_number,uint32_t conference_number,Tox_Err_Conference_Invite * error)1984 bool tox_conference_invite(Tox *tox, uint32_t friend_number, uint32_t conference_number,
1985                            Tox_Err_Conference_Invite *error)
1986 {
1987     assert(tox != nullptr);
1988     lock(tox);
1989     const int ret = invite_friend(tox->m->conferences_object, friend_number, conference_number);
1990     unlock(tox);
1991 
1992     switch (ret) {
1993         case -1:
1994             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_CONFERENCE_NOT_FOUND);
1995             return false;
1996 
1997         case -2:
1998             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_FAIL_SEND);
1999             return false;
2000 
2001         case -3:
2002             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_NO_CONNECTION);
2003             return false;
2004     }
2005 
2006     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_OK);
2007     return true;
2008 }
2009 
tox_conference_join(Tox * tox,uint32_t friend_number,const uint8_t * cookie,size_t length,Tox_Err_Conference_Join * error)2010 uint32_t tox_conference_join(Tox *tox, uint32_t friend_number, const uint8_t *cookie, size_t length,
2011                              Tox_Err_Conference_Join *error)
2012 {
2013     assert(tox != nullptr);
2014     lock(tox);
2015     const int ret = join_groupchat(tox->m->conferences_object, friend_number, GROUPCHAT_TYPE_TEXT, cookie, length);
2016     unlock(tox);
2017 
2018     switch (ret) {
2019         case -1:
2020             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_INVALID_LENGTH);
2021             return UINT32_MAX;
2022 
2023         case -2:
2024             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_WRONG_TYPE);
2025             return UINT32_MAX;
2026 
2027         case -3:
2028             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_FRIEND_NOT_FOUND);
2029             return UINT32_MAX;
2030 
2031         case -4:
2032             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_DUPLICATE);
2033             return UINT32_MAX;
2034 
2035         case -5:
2036             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_INIT_FAIL);
2037             return UINT32_MAX;
2038 
2039         case -6:
2040             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_FAIL_SEND);
2041             return UINT32_MAX;
2042     }
2043 
2044     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_OK);
2045     return ret;
2046 }
2047 
tox_conference_send_message(Tox * tox,uint32_t conference_number,Tox_Message_Type type,const uint8_t * message,size_t length,Tox_Err_Conference_Send_Message * error)2048 bool tox_conference_send_message(Tox *tox, uint32_t conference_number, Tox_Message_Type type, const uint8_t *message,
2049                                  size_t length, Tox_Err_Conference_Send_Message *error)
2050 {
2051     assert(tox != nullptr);
2052     lock(tox);
2053     int ret = 0;
2054 
2055     if (type == TOX_MESSAGE_TYPE_NORMAL) {
2056         ret = group_message_send(tox->m->conferences_object, conference_number, message, length);
2057     } else {
2058         ret = group_action_send(tox->m->conferences_object, conference_number, message, length);
2059     }
2060 
2061     unlock(tox);
2062 
2063     switch (ret) {
2064         case -1:
2065             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_CONFERENCE_NOT_FOUND);
2066             return false;
2067 
2068         case -2:
2069             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_TOO_LONG);
2070             return false;
2071 
2072         case -3:
2073             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_NO_CONNECTION);
2074             return false;
2075 
2076         case -4:
2077             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_FAIL_SEND);
2078             return false;
2079     }
2080 
2081     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_OK);
2082     return true;
2083 }
2084 
tox_conference_get_title_size(const Tox * tox,uint32_t conference_number,Tox_Err_Conference_Title * error)2085 size_t tox_conference_get_title_size(const Tox *tox, uint32_t conference_number, Tox_Err_Conference_Title *error)
2086 {
2087     assert(tox != nullptr);
2088     lock(tox);
2089     const int ret = group_title_get_size(tox->m->conferences_object, conference_number);
2090     unlock(tox);
2091 
2092     switch (ret) {
2093         case -1:
2094             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND);
2095             return -1;
2096 
2097         case -2:
2098             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH);
2099             return -1;
2100     }
2101 
2102     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_OK);
2103     return ret;
2104 }
2105 
tox_conference_get_title(const Tox * tox,uint32_t conference_number,uint8_t * title,Tox_Err_Conference_Title * error)2106 bool tox_conference_get_title(const Tox *tox, uint32_t conference_number, uint8_t *title,
2107                               Tox_Err_Conference_Title *error)
2108 {
2109     assert(tox != nullptr);
2110     lock(tox);
2111     const int ret = group_title_get(tox->m->conferences_object, conference_number, title);
2112     unlock(tox);
2113 
2114     switch (ret) {
2115         case -1:
2116             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND);
2117             return false;
2118 
2119         case -2:
2120             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH);
2121             return false;
2122     }
2123 
2124     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_OK);
2125     return true;
2126 }
2127 
tox_conference_set_title(Tox * tox,uint32_t conference_number,const uint8_t * title,size_t length,Tox_Err_Conference_Title * error)2128 bool tox_conference_set_title(Tox *tox, uint32_t conference_number, const uint8_t *title, size_t length,
2129                               Tox_Err_Conference_Title *error)
2130 {
2131     assert(tox != nullptr);
2132     lock(tox);
2133     const int ret = group_title_send(tox->m->conferences_object, conference_number, title, length);
2134     unlock(tox);
2135 
2136     switch (ret) {
2137         case -1:
2138             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND);
2139             return false;
2140 
2141         case -2:
2142             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH);
2143             return false;
2144 
2145         case -3:
2146             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_FAIL_SEND);
2147             return false;
2148     }
2149 
2150     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_OK);
2151     return true;
2152 }
2153 
tox_conference_get_chatlist_size(const Tox * tox)2154 size_t tox_conference_get_chatlist_size(const Tox *tox)
2155 {
2156     assert(tox != nullptr);
2157     lock(tox);
2158     size_t ret = count_chatlist(tox->m->conferences_object);
2159     unlock(tox);
2160     return ret;
2161 }
2162 
tox_conference_get_chatlist(const Tox * tox,uint32_t * chatlist)2163 void tox_conference_get_chatlist(const Tox *tox, uint32_t *chatlist)
2164 {
2165     assert(tox != nullptr);
2166     lock(tox);
2167     const size_t list_size = count_chatlist(tox->m->conferences_object);
2168     copy_chatlist(tox->m->conferences_object, chatlist, list_size);
2169     unlock(tox);
2170 }
2171 
tox_conference_get_type(const Tox * tox,uint32_t conference_number,Tox_Err_Conference_Get_Type * error)2172 Tox_Conference_Type tox_conference_get_type(const Tox *tox, uint32_t conference_number,
2173         Tox_Err_Conference_Get_Type *error)
2174 {
2175     assert(tox != nullptr);
2176     lock(tox);
2177     const int ret = group_get_type(tox->m->conferences_object, conference_number);
2178     unlock(tox);
2179 
2180     if (ret == -1) {
2181         SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_GET_TYPE_CONFERENCE_NOT_FOUND);
2182         return (Tox_Conference_Type)ret;
2183     }
2184 
2185     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_GET_TYPE_OK);
2186     return (Tox_Conference_Type)ret;
2187 }
2188 
2189 /* id is TOX_CONFERENCE_ID_SIZE bytes */
tox_conference_get_id(const Tox * tox,uint32_t conference_number,uint8_t * id)2190 bool tox_conference_get_id(const Tox *tox, uint32_t conference_number, uint8_t *id)
2191 {
2192     assert(tox != nullptr);
2193     lock(tox);
2194     bool ret = conference_get_id(tox->m->conferences_object, conference_number, id);
2195     unlock(tox);
2196     return ret;
2197 }
2198 
2199 // TODO(iphydf): Delete in 0.3.0.
2200 /* uid is TOX_CONFERENCE_ID_SIZE bytes */
tox_conference_get_uid(const Tox * tox,uint32_t conference_number,uint8_t * uid)2201 bool tox_conference_get_uid(const Tox *tox, uint32_t conference_number, uint8_t *uid)
2202 {
2203     assert(tox != nullptr);
2204     return tox_conference_get_id(tox, conference_number, uid);
2205 }
2206 
tox_conference_by_id(const Tox * tox,const uint8_t * id,Tox_Err_Conference_By_Id * error)2207 uint32_t tox_conference_by_id(const Tox *tox, const uint8_t *id, Tox_Err_Conference_By_Id *error)
2208 {
2209     assert(tox != nullptr);
2210 
2211     if (!id) {
2212         SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_BY_ID_NULL);
2213         return UINT32_MAX;
2214     }
2215 
2216     lock(tox);
2217     const int32_t ret = conference_by_id(tox->m->conferences_object, id);
2218     unlock(tox);
2219 
2220     if (ret == -1) {
2221         SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_BY_ID_NOT_FOUND);
2222         return UINT32_MAX;
2223     }
2224 
2225     SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_BY_ID_OK);
2226     return ret;
2227 }
2228 
2229 // TODO(iphydf): Delete in 0.3.0.
tox_conference_by_uid(const Tox * tox,const uint8_t * uid,Tox_Err_Conference_By_Uid * error)2230 uint32_t tox_conference_by_uid(const Tox *tox, const uint8_t *uid, Tox_Err_Conference_By_Uid *error)
2231 {
2232     assert(tox != nullptr);
2233     Tox_Err_Conference_By_Id id_error;
2234     const uint32_t res = tox_conference_by_id(tox, uid, &id_error);
2235 
2236     switch (id_error) {
2237         case TOX_ERR_CONFERENCE_BY_ID_OK:
2238             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_BY_UID_OK);
2239             break;
2240 
2241         case TOX_ERR_CONFERENCE_BY_ID_NULL:
2242             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_BY_UID_NULL);
2243             break;
2244 
2245         case TOX_ERR_CONFERENCE_BY_ID_NOT_FOUND:
2246             SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_BY_UID_NOT_FOUND);
2247             break;
2248     }
2249 
2250     return res;
2251 }
2252 
set_custom_packet_error(int ret,Tox_Err_Friend_Custom_Packet * error)2253 static void set_custom_packet_error(int ret, Tox_Err_Friend_Custom_Packet *error)
2254 {
2255     switch (ret) {
2256         case 0:
2257             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_OK);
2258             break;
2259 
2260         case -1:
2261             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_FOUND);
2262             break;
2263 
2264         case -2:
2265             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_TOO_LONG);
2266             break;
2267 
2268         case -3:
2269             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID);
2270             break;
2271 
2272         case -4:
2273             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_CONNECTED);
2274             break;
2275 
2276         case -5:
2277             SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_SENDQ);
2278             break;
2279     }
2280 }
2281 
tox_friend_send_lossy_packet(Tox * tox,uint32_t friend_number,const uint8_t * data,size_t length,Tox_Err_Friend_Custom_Packet * error)2282 bool tox_friend_send_lossy_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,
2283                                   Tox_Err_Friend_Custom_Packet *error)
2284 {
2285     assert(tox != nullptr);
2286 
2287     if (!data) {
2288         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_NULL);
2289         return 0;
2290     }
2291 
2292     if (length == 0) {
2293         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY);
2294         return 0;
2295     }
2296 
2297     if (data[0] < PACKET_ID_RANGE_LOSSY_START || data[0] > PACKET_ID_RANGE_LOSSY_END) {
2298         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID);
2299         return 0;
2300     }
2301 
2302     lock(tox);
2303     const int ret = m_send_custom_lossy_packet(tox->m, friend_number, data, length);
2304     unlock(tox);
2305 
2306     set_custom_packet_error(ret, error);
2307 
2308     if (ret == 0) {
2309         return 1;
2310     }
2311 
2312     return 0;
2313 }
2314 
tox_callback_friend_lossy_packet(Tox * tox,tox_friend_lossy_packet_cb * callback)2315 void tox_callback_friend_lossy_packet(Tox *tox, tox_friend_lossy_packet_cb *callback)
2316 {
2317     assert(tox != nullptr);
2318 
2319     /* start at PACKET_ID_RANGE_LOSSY_CUSTOM_START so ToxAV Packets are excluded */
2320     for (uint8_t i = PACKET_ID_RANGE_LOSSY_CUSTOM_START; i <= PACKET_ID_RANGE_LOSSY_END; ++i) {
2321         tox->friend_lossy_packet_callback_per_pktid[i] = callback;
2322     }
2323 }
2324 
tox_callback_friend_lossy_packet_per_pktid(Tox * tox,tox_friend_lossy_packet_cb * callback,uint8_t pktid)2325 void tox_callback_friend_lossy_packet_per_pktid(Tox *tox, tox_friend_lossy_packet_cb *callback, uint8_t pktid)
2326 {
2327     assert(tox != nullptr);
2328 
2329     if (pktid >= PACKET_ID_RANGE_LOSSY_START && pktid <= PACKET_ID_RANGE_LOSSY_END) {
2330         tox->friend_lossy_packet_callback_per_pktid[pktid] = callback;
2331     }
2332 }
2333 
tox_friend_send_lossless_packet(Tox * tox,uint32_t friend_number,const uint8_t * data,size_t length,Tox_Err_Friend_Custom_Packet * error)2334 bool tox_friend_send_lossless_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,
2335                                      Tox_Err_Friend_Custom_Packet *error)
2336 {
2337     assert(tox != nullptr);
2338 
2339     if (!data) {
2340         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_NULL);
2341         return 0;
2342     }
2343 
2344     if (length == 0) {
2345         SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY);
2346         return 0;
2347     }
2348 
2349     lock(tox);
2350     const int ret = send_custom_lossless_packet(tox->m, friend_number, data, length);
2351     unlock(tox);
2352 
2353     set_custom_packet_error(ret, error);
2354 
2355     if (ret == 0) {
2356         return 1;
2357     }
2358 
2359     return 0;
2360 }
2361 
tox_callback_friend_lossless_packet(Tox * tox,tox_friend_lossless_packet_cb * callback)2362 void tox_callback_friend_lossless_packet(Tox *tox, tox_friend_lossless_packet_cb *callback)
2363 {
2364     assert(tox != nullptr);
2365 
2366     for (uint8_t i = PACKET_ID_RANGE_LOSSLESS_CUSTOM_START; i <= PACKET_ID_RANGE_LOSSLESS_CUSTOM_END; ++i) {
2367         tox->friend_lossless_packet_callback_per_pktid[i] = callback;
2368     }
2369 }
2370 
tox_callback_friend_lossless_packet_per_pktid(Tox * tox,tox_friend_lossless_packet_cb * callback,uint8_t pktid)2371 void tox_callback_friend_lossless_packet_per_pktid(Tox *tox, tox_friend_lossless_packet_cb *callback, uint8_t pktid)
2372 {
2373     assert(tox != nullptr);
2374 
2375     if ((pktid >= PACKET_ID_RANGE_LOSSLESS_CUSTOM_START && pktid <= PACKET_ID_RANGE_LOSSLESS_CUSTOM_END)
2376             || pktid == PACKET_ID_MSI) {
2377         tox->friend_lossless_packet_callback_per_pktid[pktid] = callback;
2378     }
2379 }
2380 
tox_self_get_dht_id(const Tox * tox,uint8_t * dht_id)2381 void tox_self_get_dht_id(const Tox *tox, uint8_t *dht_id)
2382 {
2383     assert(tox != nullptr);
2384 
2385     if (dht_id) {
2386         lock(tox);
2387         memcpy(dht_id, dht_get_self_public_key(tox->m->dht), CRYPTO_PUBLIC_KEY_SIZE);
2388         unlock(tox);
2389     }
2390 }
2391 
tox_set_av_object(Tox * tox,void * object)2392 void tox_set_av_object(Tox *tox, void *object)
2393 {
2394     assert(tox != nullptr);
2395     lock(tox);
2396     tox->toxav_object = object;
2397     unlock(tox);
2398 }
2399 
tox_get_av_object(const Tox * tox)2400 void *tox_get_av_object(const Tox *tox)
2401 {
2402     assert(tox != nullptr);
2403     lock(tox);
2404     void *object = tox->toxav_object;
2405     unlock(tox);
2406     return object;
2407 }
2408 
tox_self_get_udp_port(const Tox * tox,Tox_Err_Get_Port * error)2409 uint16_t tox_self_get_udp_port(const Tox *tox, Tox_Err_Get_Port *error)
2410 {
2411     assert(tox != nullptr);
2412     lock(tox);
2413     const uint16_t port = net_htons(net_port(tox->m->net));
2414     unlock(tox);
2415 
2416     if (port) {
2417         SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_OK);
2418     } else {
2419         SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_NOT_BOUND);
2420     }
2421 
2422     return port;
2423 }
2424 
tox_self_get_tcp_port(const Tox * tox,Tox_Err_Get_Port * error)2425 uint16_t tox_self_get_tcp_port(const Tox *tox, Tox_Err_Get_Port *error)
2426 {
2427     assert(tox != nullptr);
2428     lock(tox);
2429 
2430     if (tox->m->tcp_server) {
2431         SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_OK);
2432         uint16_t ret = tox->m->options.tcp_server_port;
2433         unlock(tox);
2434         return ret;
2435     }
2436 
2437     SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_NOT_BOUND);
2438     unlock(tox);
2439     return 0;
2440 }
2441