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