Coverage Report

Created: 2025-08-05 10:35

/src/c-toxcore/toxcore/Messenger.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: GPL-3.0-or-later
2
 * Copyright © 2016-2025 The TokTok team.
3
 * Copyright © 2013 Tox project.
4
 */
5
6
/**
7
 * An implementation of a simple text chat only messenger on the tox network core.
8
 */
9
#include "Messenger.h"
10
11
#include <assert.h>
12
#include <stdio.h>
13
#include <string.h>
14
#include <time.h>
15
16
#include "DHT.h"
17
#include "TCP_client.h"
18
#include "TCP_connection.h"
19
#include "TCP_server.h"
20
#include "announce.h"
21
#include "attributes.h"
22
#include "bin_pack.h"
23
#include "bin_unpack.h"
24
#include "ccompat.h"
25
#include "crypto_core.h"
26
#include "forwarding.h"
27
#include "friend_connection.h"
28
#include "friend_requests.h"
29
#include "group_announce.h"
30
#include "group_chats.h"
31
#include "group_common.h"
32
#include "group_onion_announce.h"
33
#include "logger.h"
34
#include "mem.h"
35
#include "mono_time.h"
36
#include "net_crypto.h"
37
#include "net_profile.h"
38
#include "network.h"
39
#include "onion.h"
40
#include "onion_announce.h"
41
#include "onion_client.h"
42
#include "state.h"
43
#include "util.h"
44
45
static_assert(MAX_CONCURRENT_FILE_PIPES <= UINT8_MAX + 1,
46
              "uint8_t cannot represent all file transfer numbers");
47
48
static const Friend empty_friend = {{0}};
49
50
/**
51
 * Determines if the friendnumber passed is valid in the Messenger object.
52
 *
53
 * @param friendnumber The index in the friend list.
54
 */
55
bool friend_is_valid(const Messenger *m, int32_t friendnumber)
56
0
{
57
0
    return (uint32_t)friendnumber < m->numfriends && m->friendlist[friendnumber].status != 0;
58
0
}
59
60
/** @brief Set the size of the friend list to numfriends.
61
 *
62
 * @retval -1 if mem_vrealloc fails.
63
 */
64
static int realloc_friendlist(Messenger *_Nonnull m, uint32_t num)
65
272
{
66
272
    if (num == 0) {
67
0
        mem_delete(m->mem, m->friendlist);
68
0
        m->friendlist = nullptr;
69
0
        return 0;
70
0
    }
71
72
272
    Friend *newfriendlist = (Friend *)mem_vrealloc(m->mem, m->friendlist, num, sizeof(Friend));
73
74
272
    if (newfriendlist == nullptr) {
75
0
        return -1;
76
0
    }
77
78
272
    m->friendlist = newfriendlist;
79
272
    return 0;
80
272
}
81
82
/** @return the friend number associated to that public key.
83
 * @retval -1 if no such friend.
84
 */
85
int32_t getfriend_id(const Messenger *m, const uint8_t *real_pk)
86
6.76k
{
87
10.8k
    for (uint32_t i = 0; i < m->numfriends; ++i) {
88
4.42k
        if (m->friendlist[i].status > 0 && pk_equal(real_pk, m->friendlist[i].real_pk)) {
89
331
            return i;
90
331
        }
91
4.42k
    }
92
93
6.43k
    return -1;
94
6.76k
}
95
96
/** @brief Copies the public key associated to that friend id into real_pk buffer.
97
 *
98
 * Make sure that real_pk is of size CRYPTO_PUBLIC_KEY_SIZE.
99
 *
100
 * @retval 0 if success.
101
 * @retval -1 if failure.
102
 */
103
int get_real_pk(const Messenger *m, int32_t friendnumber, uint8_t *real_pk)
104
0
{
105
0
    if (!m_friend_exists(m, friendnumber)) {
106
0
        return -1;
107
0
    }
108
109
0
    memcpy(real_pk, m->friendlist[friendnumber].real_pk, CRYPTO_PUBLIC_KEY_SIZE);
110
0
    return 0;
111
0
}
112
113
/** @return friend connection id on success.
114
 * @retval -1 if failure.
115
 */
116
int getfriendcon_id(const Messenger *m, int32_t friendnumber)
117
0
{
118
0
    if (!m_friend_exists(m, friendnumber)) {
119
0
        return -1;
120
0
    }
121
122
0
    return m->friendlist[friendnumber].friendcon_id;
123
0
}
124
125
/**
126
 * Format: `[real_pk (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)]`
127
 *
128
 * @param[out] address FRIEND_ADDRESS_SIZE byte address to give to others.
129
 */
130
void getaddress(const Messenger *m, uint8_t *address)
131
0
{
132
0
    pk_copy(address, nc_get_self_public_key(m->net_crypto));
133
0
    uint32_t nospam = get_nospam(m->fr);
134
0
    memcpy(address + CRYPTO_PUBLIC_KEY_SIZE, &nospam, sizeof(nospam));
135
0
    uint16_t checksum = data_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));
136
0
    memcpy(address + CRYPTO_PUBLIC_KEY_SIZE + sizeof(nospam), &checksum, sizeof(checksum));
137
0
}
138
139
static bool send_online_packet(const Messenger *_Nonnull m, int friendcon_id)
140
0
{
141
0
    const uint8_t packet[1] = {PACKET_ID_ONLINE};
142
0
    return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, friendcon_id), packet,
143
0
                             sizeof(packet), false) != -1;
144
0
}
145
146
static bool send_offline_packet(const Messenger *_Nonnull m, int friendcon_id)
147
0
{
148
0
    const uint8_t packet[1] = {PACKET_ID_OFFLINE};
149
0
    return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, friendcon_id), packet,
150
0
                             sizeof(packet), false) != -1;
151
0
}
152
153
static int m_handle_status(void *_Nonnull object, int friendcon_id, bool status, void *_Nullable userdata);
154
static int m_handle_packet(void *_Nonnull object, int friendcon_id, const uint8_t *_Nonnull data, uint16_t length, void *_Nullable userdata);
155
static int m_handle_lossy_packet(void *_Nonnull object, int friendcon_id, const uint8_t *_Nonnull data, uint16_t length,
156
                                 void *_Nullable userdata);
157
static int32_t init_new_friend(Messenger *_Nonnull m, const uint8_t *_Nonnull real_pk, uint8_t status)
158
272
{
159
272
    if (m->numfriends == UINT32_MAX) {
160
0
        LOGGER_ERROR(m->log, "Friend list full: we have more than 4 billion friends");
161
        /* This is technically incorrect, but close enough. */
162
0
        return FAERR_NOMEM;
163
0
    }
164
165
    /* Resize the friend list if necessary. */
166
272
    if (realloc_friendlist(m, m->numfriends + 1) != 0) {
167
0
        return FAERR_NOMEM;
168
0
    }
169
170
272
    m->friendlist[m->numfriends] = empty_friend;
171
172
272
    const int friendcon_id = new_friend_connection(m->fr_c, real_pk);
173
174
272
    if (friendcon_id == -1) {
175
0
        return FAERR_NOMEM;
176
0
    }
177
178
589
    for (uint32_t i = 0; i <= m->numfriends; ++i) {
179
589
        if (m->friendlist[i].status == NOFRIEND) {
180
272
            m->friendlist[i].status = status;
181
272
            m->friendlist[i].friendcon_id = friendcon_id;
182
272
            m->friendlist[i].friendrequest_lastsent = 0;
183
272
            pk_copy(m->friendlist[i].real_pk, real_pk);
184
272
            m->friendlist[i].statusmessage_length = 0;
185
272
            m->friendlist[i].userstatus = USERSTATUS_NONE;
186
272
            m->friendlist[i].is_typing = false;
187
272
            m->friendlist[i].message_id = 0;
188
272
            friend_connection_callbacks(m->fr_c, friendcon_id, MESSENGER_CALLBACK_INDEX, &m_handle_status, &m_handle_packet,
189
272
                                        &m_handle_lossy_packet, m, i);
190
191
272
            if (m->numfriends == i) {
192
272
                ++m->numfriends;
193
272
            }
194
195
272
            if (friend_con_connected(m->fr_c, friendcon_id) == FRIENDCONN_STATUS_CONNECTED) {
196
0
                send_online_packet(m, friendcon_id);
197
0
            }
198
199
272
            return i;
200
272
        }
201
589
    }
202
203
0
    return FAERR_NOMEM;
204
272
}
205
206
static int32_t m_add_friend_contact_norequest(Messenger *_Nonnull m, const uint8_t *_Nonnull real_pk)
207
241
{
208
241
    if (getfriend_id(m, real_pk) != -1) {
209
11
        return FAERR_ALREADYSENT;
210
11
    }
211
212
230
    if (pk_equal(real_pk, nc_get_self_public_key(m->net_crypto))) {
213
0
        return FAERR_OWNKEY;
214
0
    }
215
216
230
    return init_new_friend(m, real_pk, FRIEND_CONFIRMED);
217
230
}
218
219
/**
220
 * Add a friend.
221
 *
222
 * Set the data that will be sent along with friend request.
223
 *
224
 * @param address is the address of the friend (returned by getaddress of the friend
225
 *   you wish to add) it must be FRIEND_ADDRESS_SIZE bytes.
226
 *   TODO(irungentoo): add checksum.
227
 * @param data is the data.
228
 * @param length is the length.
229
 *
230
 * @return the friend number if success.
231
 * @retval FA_TOOLONG if message length is too long.
232
 * @retval FAERR_NOMESSAGE if no message (message length must be >= 1 byte).
233
 * @retval FAERR_OWNKEY if user's own key.
234
 * @retval FAERR_ALREADYSENT if friend request already sent or already a friend.
235
 * @retval FAERR_BADCHECKSUM if bad checksum in address.
236
 * @retval FAERR_SETNEWNOSPAM if the friend was already there but the nospam was different.
237
 *   (the nospam for that friend was set to the new one).
238
 * @retval FAERR_NOMEM if increasing the friend list size fails.
239
 */
240
int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, uint16_t length)
241
128
{
242
128
    if (length > MAX_FRIEND_REQUEST_DATA_SIZE) {
243
11
        return FAERR_TOOLONG;
244
11
    }
245
246
117
    uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE];
247
117
    pk_copy(real_pk, address);
248
249
117
    if (!public_key_valid(real_pk)) {
250
10
        return FAERR_BADCHECKSUM;
251
10
    }
252
253
107
    uint16_t check;
254
107
    const uint16_t checksum = data_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));
255
107
    memcpy(&check, address + CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t), sizeof(check));
256
257
107
    if (check != checksum) {
258
0
        return FAERR_BADCHECKSUM;
259
0
    }
260
261
107
    if (length < 1) {
262
10
        return FAERR_NOMESSAGE;
263
10
    }
264
265
97
    if (pk_equal(real_pk, nc_get_self_public_key(m->net_crypto))) {
266
10
        return FAERR_OWNKEY;
267
10
    }
268
269
87
    const int32_t friend_id = getfriend_id(m, real_pk);
270
271
87
    if (friend_id != -1) {
272
45
        if (m->friendlist[friend_id].status >= FRIEND_CONFIRMED) {
273
10
            return FAERR_ALREADYSENT;
274
10
        }
275
276
35
        uint32_t nospam;
277
35
        memcpy(&nospam, address + CRYPTO_PUBLIC_KEY_SIZE, sizeof(nospam));
278
279
35
        if (m->friendlist[friend_id].friendrequest_nospam == nospam) {
280
18
            return FAERR_ALREADYSENT;
281
18
        }
282
283
17
        m->friendlist[friend_id].friendrequest_nospam = nospam;
284
17
        return FAERR_SETNEWNOSPAM;
285
35
    }
286
287
42
    const int32_t ret = init_new_friend(m, real_pk, FRIEND_ADDED);
288
289
42
    if (ret < 0) {
290
0
        return ret;
291
0
    }
292
293
42
    m->friendlist[ret].friendrequest_timeout = FRIENDREQUEST_TIMEOUT;
294
42
    memcpy(m->friendlist[ret].info, data, length);
295
42
    m->friendlist[ret].info_size = length;
296
42
    memcpy(&m->friendlist[ret].friendrequest_nospam, address + CRYPTO_PUBLIC_KEY_SIZE, sizeof(uint32_t));
297
298
42
    return ret;
299
42
}
300
301
int32_t m_addfriend_norequest(Messenger *m, const uint8_t *real_pk)
302
280
{
303
280
    if (!public_key_valid(real_pk)) {
304
29
        return FAERR_BADCHECKSUM;
305
29
    }
306
307
251
    if (pk_equal(real_pk, nc_get_self_public_key(m->net_crypto))) {
308
10
        return FAERR_OWNKEY;
309
10
    }
310
311
241
    return m_add_friend_contact_norequest(m, real_pk);
312
251
}
313
314
static int clear_receipts(Messenger *_Nonnull m, int32_t friendnumber)
315
272
{
316
272
    if (!m_friend_exists(m, friendnumber)) {
317
0
        return -1;
318
0
    }
319
320
272
    struct Receipts *receipts = m->friendlist[friendnumber].receipts_start;
321
322
272
    while (receipts != nullptr) {
323
0
        struct Receipts *temp_r = receipts->next;
324
0
        mem_delete(m->mem, receipts);
325
0
        receipts = temp_r;
326
0
    }
327
328
272
    m->friendlist[friendnumber].receipts_start = nullptr;
329
272
    m->friendlist[friendnumber].receipts_end = nullptr;
330
272
    return 0;
331
272
}
332
333
static int add_receipt(Messenger *_Nonnull m, int32_t friendnumber, uint32_t packet_num, uint32_t msg_id)
334
0
{
335
0
    if (!m_friend_exists(m, friendnumber)) {
336
0
        return -1;
337
0
    }
338
339
0
    struct Receipts *new_receipts = (struct Receipts *)mem_alloc(m->mem, sizeof(struct Receipts));
340
341
0
    if (new_receipts == nullptr) {
342
0
        return -1;
343
0
    }
344
345
0
    new_receipts->packet_num = packet_num;
346
0
    new_receipts->msg_id = msg_id;
347
348
0
    if (m->friendlist[friendnumber].receipts_start == nullptr) {
349
0
        m->friendlist[friendnumber].receipts_start = new_receipts;
350
0
    } else {
351
0
        m->friendlist[friendnumber].receipts_end->next = new_receipts;
352
0
    }
353
354
0
    m->friendlist[friendnumber].receipts_end = new_receipts;
355
0
    new_receipts->next = nullptr;
356
0
    return 0;
357
0
}
358
/**
359
 * return -1 on failure.
360
 * return 0 if packet was received.
361
 */
362
static int friend_received_packet(const Messenger *_Nonnull m, int32_t friendnumber, uint32_t number)
363
0
{
364
0
    if (!m_friend_exists(m, friendnumber)) {
365
0
        return -1;
366
0
    }
367
368
0
    return cryptpacket_received(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
369
0
                                m->friendlist[friendnumber].friendcon_id), number);
370
0
}
371
372
bool m_create_group_connection(Messenger *m, GC_Chat *chat)
373
90
{
374
90
    random_bytes(m->rng, chat->m_group_public_key, CRYPTO_PUBLIC_KEY_SIZE);
375
90
    const int friendcon_id = new_friend_connection(m->fr_c, chat->m_group_public_key);
376
377
90
    if (friendcon_id == -1) {
378
0
        return false;
379
0
    }
380
381
90
    const Friend_Conn *connection = get_conn(m->fr_c, friendcon_id);
382
383
90
    if (connection == nullptr) {
384
0
        return false;
385
0
    }
386
387
90
    chat->friend_connection_id = friendcon_id;
388
389
90
    if (friend_con_connected(m->fr_c, friendcon_id) == FRIENDCONN_STATUS_CONNECTED) {
390
0
        send_online_packet(m, friendcon_id);
391
0
    }
392
393
90
    const int onion_friend_number = friend_conn_get_onion_friendnum(connection);
394
90
    Onion_Friend *onion_friend = onion_get_friend(m->onion_c, (uint16_t)onion_friend_number);
395
396
90
    onion_friend_set_gc_public_key(onion_friend, get_chat_id(&chat->chat_public_key));
397
90
    onion_friend_set_gc_data(onion_friend, nullptr, 0);
398
399
90
    return true;
400
90
}
401
402
/**
403
 * Kills the friend connection for a groupchat.
404
 */
405
void m_kill_group_connection(Messenger *m, const GC_Chat *chat)
406
90
{
407
90
    remove_request_received(m->fr, chat->m_group_public_key);
408
409
90
    friend_connection_callbacks(m->fr_c, chat->friend_connection_id, MESSENGER_CALLBACK_INDEX, nullptr,
410
90
                                nullptr, nullptr, nullptr, 0);
411
412
90
    if (friend_con_connected(m->fr_c, chat->friend_connection_id) == FRIENDCONN_STATUS_CONNECTED) {
413
0
        send_offline_packet(m, chat->friend_connection_id);
414
0
    }
415
416
90
    kill_friend_connection(m->fr_c, chat->friend_connection_id);
417
90
}
418
419
static int do_receipts(Messenger *_Nonnull m, int32_t friendnumber, void *_Nullable userdata)
420
0
{
421
0
    if (!m_friend_exists(m, friendnumber)) {
422
0
        return -1;
423
0
    }
424
425
0
    struct Receipts *receipts = m->friendlist[friendnumber].receipts_start;
426
427
0
    while (receipts != nullptr) {
428
0
        if (friend_received_packet(m, friendnumber, receipts->packet_num) == -1) {
429
0
            break;
430
0
        }
431
432
0
        if (m->read_receipt != nullptr) {
433
0
            m->read_receipt(m, friendnumber, receipts->msg_id, userdata);
434
0
        }
435
436
0
        struct Receipts *r_next = receipts->next;
437
438
0
        mem_delete(m->mem, receipts);
439
440
0
        m->friendlist[friendnumber].receipts_start = r_next;
441
442
0
        receipts = r_next;
443
0
    }
444
445
0
    if (m->friendlist[friendnumber].receipts_start == nullptr) {
446
0
        m->friendlist[friendnumber].receipts_end = nullptr;
447
0
    }
448
449
0
    return 0;
450
0
}
451
452
/** @brief Remove a friend.
453
 *
454
 * @retval 0 if success.
455
 * @retval -1 if failure.
456
 */
457
int m_delfriend(Messenger *m, int32_t friendnumber)
458
0
{
459
0
    if (!m_friend_exists(m, friendnumber)) {
460
0
        return -1;
461
0
    }
462
463
0
    clear_receipts(m, friendnumber);
464
0
    remove_request_received(m->fr, m->friendlist[friendnumber].real_pk);
465
0
    friend_connection_callbacks(m->fr_c, m->friendlist[friendnumber].friendcon_id, MESSENGER_CALLBACK_INDEX, nullptr,
466
0
                                nullptr, nullptr, nullptr, 0);
467
468
0
    if (friend_con_connected(m->fr_c, m->friendlist[friendnumber].friendcon_id) == FRIENDCONN_STATUS_CONNECTED) {
469
0
        send_offline_packet(m, m->friendlist[friendnumber].friendcon_id);
470
0
    }
471
472
0
    kill_friend_connection(m->fr_c, m->friendlist[friendnumber].friendcon_id);
473
0
    m->friendlist[friendnumber] = empty_friend;
474
475
0
    uint32_t i;
476
477
0
    for (i = m->numfriends; i != 0; --i) {
478
0
        if (m->friendlist[i - 1].status != NOFRIEND) {
479
0
            break;
480
0
        }
481
0
    }
482
483
0
    m->numfriends = i;
484
485
0
    if (realloc_friendlist(m, m->numfriends) != 0) {
486
0
        return FAERR_NOMEM;
487
0
    }
488
489
0
    return 0;
490
0
}
491
492
int m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber)
493
0
{
494
0
    if (!m_friend_exists(m, friendnumber)) {
495
0
        return -1;
496
0
    }
497
498
0
    if (m->friendlist[friendnumber].status != FRIEND_ONLINE) {
499
0
        return CONNECTION_NONE;
500
0
    }
501
502
0
    bool direct_connected = false;
503
0
    uint32_t num_online_relays = 0;
504
0
    const int crypt_conn_id = friend_connection_crypt_connection_id(m->fr_c, m->friendlist[friendnumber].friendcon_id);
505
506
0
    if (!crypto_connection_status(m->net_crypto, crypt_conn_id, &direct_connected, &num_online_relays)) {
507
0
        return CONNECTION_NONE;
508
0
    }
509
510
0
    if (direct_connected) {
511
0
        return CONNECTION_UDP;
512
0
    }
513
514
0
    if (num_online_relays != 0) {
515
0
        return CONNECTION_TCP;
516
0
    }
517
518
    /* if we have a valid friend connection but do not have an established connection
519
     * we leave the connection status unchanged until the friend connection is either
520
     * established or dropped.
521
     */
522
0
    return m->friendlist[friendnumber].last_connection_udp_tcp;
523
0
}
524
525
/**
526
 * Checks if there exists a friend with given friendnumber.
527
 *
528
 * @param friendnumber The index in the friend list.
529
 *
530
 * @retval true if friend exists.
531
 * @retval false if friend doesn't exist.
532
 */
533
bool m_friend_exists(const Messenger *m, int32_t friendnumber)
534
732
{
535
732
    return (unsigned int)friendnumber < m->numfriends && m->friendlist[friendnumber].status != 0;
536
732
}
537
538
/** @brief Send a message of type to an online friend.
539
 *
540
 * @retval -1 if friend not valid.
541
 * @retval -2 if too large.
542
 * @retval -3 if friend not online.
543
 * @retval -4 if send failed (because queue is full).
544
 * @retval -5 if bad type.
545
 * @retval 0 if success.
546
 *
547
 * The value in message_id will be passed to your read_receipt callback when the other receives the message.
548
 */
549
int m_send_message_generic(Messenger *m, int32_t friendnumber, uint8_t type, const uint8_t *message, uint32_t length,
550
                           uint32_t *message_id)
551
0
{
552
0
    if (type > MESSAGE_ACTION) {
553
0
        LOGGER_WARNING(m->log, "message type %d is invalid", type);
554
0
        return -5;
555
0
    }
556
557
0
    if (!m_friend_exists(m, friendnumber)) {
558
0
        LOGGER_WARNING(m->log, "friend number %d is invalid", friendnumber);
559
0
        return -1;
560
0
    }
561
562
0
    if (length >= MAX_CRYPTO_DATA_SIZE) {
563
0
        LOGGER_WARNING(m->log, "message length %u is too large", length);
564
0
        return -2;
565
0
    }
566
567
0
    if (m->friendlist[friendnumber].status != FRIEND_ONLINE) {
568
0
        LOGGER_WARNING(m->log, "friend %d is not online", friendnumber);
569
0
        return -3;
570
0
    }
571
572
0
    VLA(uint8_t, packet, length + 1);
573
0
    packet[0] = PACKET_ID_MESSAGE + type;
574
575
0
    assert(message != nullptr);
576
0
    memcpy(packet + 1, message, length);
577
578
0
    const int64_t packet_num = write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
579
0
                               m->friendlist[friendnumber].friendcon_id), packet, length + 1, false);
580
581
0
    if (packet_num == -1) {
582
0
        return -4;
583
0
    }
584
585
0
    const uint32_t msg_id = ++m->friendlist[friendnumber].message_id;
586
587
0
    add_receipt(m, friendnumber, packet_num, msg_id);
588
589
0
    if (message_id != nullptr) {
590
0
        *message_id = msg_id;
591
0
    }
592
593
0
    return 0;
594
0
}
595
596
static bool write_cryptpacket_id(const Messenger *_Nonnull m, int32_t friendnumber, uint8_t packet_id, const uint8_t *_Nonnull data, uint32_t length, bool congestion_control)
597
0
{
598
0
    if (!m_friend_exists(m, friendnumber)) {
599
0
        return false;
600
0
    }
601
602
0
    if (length >= MAX_CRYPTO_DATA_SIZE || m->friendlist[friendnumber].status != FRIEND_ONLINE) {
603
0
        return false;
604
0
    }
605
606
0
    VLA(uint8_t, packet, length + 1);
607
0
    packet[0] = packet_id;
608
609
0
    assert(data != nullptr);
610
0
    memcpy(packet + 1, data, length);
611
612
0
    return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
613
0
                             m->friendlist[friendnumber].friendcon_id), packet, length + 1, congestion_control) != -1;
614
0
}
615
616
/** @brief Send a name packet to friendnumber.
617
 * length is the length with the NULL terminator.
618
 */
619
static bool m_sendname(const Messenger *_Nonnull m, int32_t friendnumber, const uint8_t *_Nonnull name, uint16_t length)
620
0
{
621
0
    if (length > MAX_NAME_LENGTH) {
622
0
        return false;
623
0
    }
624
625
0
    return write_cryptpacket_id(m, friendnumber, PACKET_ID_NICKNAME, name, length, false);
626
0
}
627
628
/** @brief Set the name and name_length of a friend.
629
 *
630
 * name must be a string of maximum MAX_NAME_LENGTH length.
631
 * length must be at least 1 byte.
632
 * length is the length of name with the NULL terminator.
633
 *
634
 * @retval 0 if success.
635
 * @retval -1 if failure.
636
 */
637
int setfriendname(Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length)
638
230
{
639
230
    if (!m_friend_exists(m, friendnumber)) {
640
0
        return -1;
641
0
    }
642
643
230
    if (length > MAX_NAME_LENGTH || length == 0) {
644
182
        return -1;
645
182
    }
646
647
48
    m->friendlist[friendnumber].name_length = length;
648
48
    memcpy(m->friendlist[friendnumber].name, name, length);
649
48
    return 0;
650
230
}
651
652
/** @brief Set our nickname.
653
 *
654
 * name must be a string of maximum MAX_NAME_LENGTH length.
655
 * length must be at least 1 byte.
656
 * length is the length of name with the NULL terminator.
657
 *
658
 * @retval 0 if success.
659
 * @retval -1 if failure.
660
 */
661
int setname(Messenger *m, const uint8_t *name, uint16_t length)
662
329
{
663
329
    if (length > MAX_NAME_LENGTH) {
664
0
        return -1;
665
0
    }
666
667
329
    if (m->name_length == length && (length == 0 || memcmp(name, m->name, length) == 0)) {
668
84
        return 0;
669
84
    }
670
671
245
    if (length > 0) {
672
245
        memcpy(m->name, name, length);
673
245
    }
674
675
245
    m->name_length = length;
676
677
571
    for (uint32_t i = 0; i < m->numfriends; ++i) {
678
326
        m->friendlist[i].name_sent = false;
679
326
    }
680
681
245
    return 0;
682
329
}
683
684
/**
685
 * @brief Get your nickname.
686
 *
687
 * m - The messenger context to use.
688
 * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes.
689
 *
690
 * @return length of the name.
691
 * @retval 0 on error.
692
 */
693
uint16_t getself_name(const Messenger *m, uint8_t *name)
694
0
{
695
0
    if (name == nullptr) {
696
0
        return 0;
697
0
    }
698
699
0
    memcpy(name, m->name, m->name_length);
700
701
0
    return m->name_length;
702
0
}
703
704
/** @brief Get name of friendnumber and put it in name.
705
 *
706
 * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes.
707
 *
708
 * @return length of name if success.
709
 * @retval -1 if failure.
710
 */
711
int getname(const Messenger *m, int32_t friendnumber, uint8_t *name)
712
0
{
713
0
    if (!m_friend_exists(m, friendnumber)) {
714
0
        return -1;
715
0
    }
716
717
0
    memcpy(name, m->friendlist[friendnumber].name, m->friendlist[friendnumber].name_length);
718
0
    return m->friendlist[friendnumber].name_length;
719
0
}
720
721
int m_get_name_size(const Messenger *m, int32_t friendnumber)
722
0
{
723
0
    if (!m_friend_exists(m, friendnumber)) {
724
0
        return -1;
725
0
    }
726
727
0
    return m->friendlist[friendnumber].name_length;
728
0
}
729
730
int m_get_self_name_size(const Messenger *m)
731
0
{
732
0
    return m->name_length;
733
0
}
734
735
int m_set_statusmessage(Messenger *m, const uint8_t *status, uint16_t length)
736
623
{
737
623
    if (length > MAX_STATUSMESSAGE_LENGTH) {
738
0
        return -1;
739
0
    }
740
741
623
    if (m->statusmessage_length == length && (length == 0 || memcmp(m->statusmessage, status, length) == 0)) {
742
152
        return 0;
743
152
    }
744
745
471
    if (length > 0) {
746
471
        memcpy(m->statusmessage, status, length);
747
471
    }
748
749
471
    m->statusmessage_length = length;
750
751
820
    for (uint32_t i = 0; i < m->numfriends; ++i) {
752
349
        m->friendlist[i].statusmessage_sent = false;
753
349
    }
754
755
471
    return 0;
756
623
}
757
758
static bool userstatus_from_int(uint8_t status, Userstatus *_Nonnull out_enum)
759
378
{
760
378
    switch (status) {
761
169
        case USERSTATUS_NONE: {
762
169
            *out_enum = USERSTATUS_NONE;
763
169
            return true;
764
0
        }
765
766
6
        case USERSTATUS_AWAY: {
767
6
            *out_enum = USERSTATUS_AWAY;
768
6
            return true;
769
0
        }
770
771
75
        case USERSTATUS_BUSY: {
772
75
            *out_enum = USERSTATUS_BUSY;
773
75
            return true;
774
0
        }
775
776
0
        case USERSTATUS_INVALID: {
777
0
            *out_enum = USERSTATUS_INVALID;
778
0
            return true;
779
0
        }
780
781
128
        default: {
782
128
            *out_enum = USERSTATUS_INVALID;
783
128
            return false;
784
0
        }
785
378
    }
786
378
}
787
788
int m_set_userstatus(Messenger *m, uint8_t status)
789
612
{
790
612
    if (status >= USERSTATUS_INVALID) {
791
256
        return -1;
792
256
    }
793
794
356
    if (m->userstatus == status) {
795
208
        return 0;
796
208
    }
797
798
148
    userstatus_from_int(status, &m->userstatus);
799
800
266
    for (uint32_t i = 0; i < m->numfriends; ++i) {
801
118
        m->friendlist[i].userstatus_sent = false;
802
118
    }
803
804
148
    return 0;
805
356
}
806
807
/**
808
 * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH.
809
 *
810
 * @return the length of friendnumber's status message, including null on success.
811
 * @retval -1 on failure.
812
 */
813
int m_get_statusmessage_size(const Messenger *m, int32_t friendnumber)
814
0
{
815
0
    if (!m_friend_exists(m, friendnumber)) {
816
0
        return -1;
817
0
    }
818
819
0
    return m->friendlist[friendnumber].statusmessage_length;
820
0
}
821
822
/** @brief Copy friendnumber's status message into buf, truncating if size is over maxlen.
823
 *
824
 * Get the size you need to allocate from m_get_statusmessage_size.
825
 * The self variant will copy our own status message.
826
 *
827
 * @return the length of the copied data on success
828
 * @retval -1 on failure.
829
 */
830
int m_copy_statusmessage(const Messenger *m, int32_t friendnumber, uint8_t *buf, uint32_t maxlen)
831
0
{
832
0
    if (!m_friend_exists(m, friendnumber)) {
833
0
        return -1;
834
0
    }
835
836
    // TODO(iphydf): This should be uint16_t and min_u16. If maxlen exceeds
837
    // uint16_t's range, it won't affect the result.
838
0
    const uint32_t msglen = min_u32(maxlen, m->friendlist[friendnumber].statusmessage_length);
839
840
0
    memcpy(buf, m->friendlist[friendnumber].statusmessage, msglen);
841
0
    memzero(buf + msglen, maxlen - msglen);
842
0
    return msglen;
843
0
}
844
845
/** @return the size of friendnumber's user status.
846
 * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH.
847
 */
848
int m_get_self_statusmessage_size(const Messenger *m)
849
0
{
850
0
    return m->statusmessage_length;
851
0
}
852
853
int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf)
854
0
{
855
0
    memcpy(buf, m->statusmessage, m->statusmessage_length);
856
0
    return m->statusmessage_length;
857
0
}
858
859
uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber)
860
0
{
861
0
    if (!m_friend_exists(m, friendnumber)) {
862
0
        return USERSTATUS_INVALID;
863
0
    }
864
865
0
    uint8_t status = m->friendlist[friendnumber].userstatus;
866
867
0
    if (status >= USERSTATUS_INVALID) {
868
0
        status = USERSTATUS_NONE;
869
0
    }
870
871
0
    return status;
872
0
}
873
874
uint8_t m_get_self_userstatus(const Messenger *m)
875
0
{
876
0
    return m->userstatus;
877
0
}
878
879
uint64_t m_get_last_online(const Messenger *m, int32_t friendnumber)
880
0
{
881
0
    if (!m_friend_exists(m, friendnumber)) {
882
0
        return UINT64_MAX;
883
0
    }
884
885
0
    return m->friendlist[friendnumber].last_seen_time;
886
0
}
887
888
int m_set_usertyping(Messenger *m, int32_t friendnumber, bool is_typing)
889
0
{
890
0
    if (!m_friend_exists(m, friendnumber)) {
891
0
        return -1;
892
0
    }
893
894
0
    if (m->friendlist[friendnumber].user_istyping == is_typing) {
895
0
        return 0;
896
0
    }
897
898
0
    m->friendlist[friendnumber].user_istyping = is_typing;
899
0
    m->friendlist[friendnumber].user_istyping_sent = false;
900
901
0
    return 0;
902
0
}
903
904
int m_get_istyping(const Messenger *m, int32_t friendnumber)
905
0
{
906
0
    if (!m_friend_exists(m, friendnumber)) {
907
0
        return -1;
908
0
    }
909
910
0
    return m->friendlist[friendnumber].is_typing ? 1 : 0;
911
0
}
912
913
static bool send_statusmessage(const Messenger *_Nonnull m, int32_t friendnumber, const uint8_t *_Nonnull status, uint16_t length)
914
0
{
915
0
    return write_cryptpacket_id(m, friendnumber, PACKET_ID_STATUSMESSAGE, status, length, false);
916
0
}
917
918
static bool send_userstatus(const Messenger *_Nonnull m, int32_t friendnumber, uint8_t status)
919
0
{
920
0
    return write_cryptpacket_id(m, friendnumber, PACKET_ID_USERSTATUS, &status, sizeof(status), false);
921
0
}
922
923
static bool send_user_istyping(const Messenger *_Nonnull m, int32_t friendnumber, bool is_typing)
924
0
{
925
0
    const uint8_t typing = is_typing ? 1 : 0;
926
0
    return write_cryptpacket_id(m, friendnumber, PACKET_ID_TYPING, &typing, sizeof(typing), false);
927
0
}
928
929
static int set_friend_statusmessage(const Messenger *_Nonnull m, int32_t friendnumber, const uint8_t *_Nonnull status, uint16_t length)
930
230
{
931
230
    if (!m_friend_exists(m, friendnumber)) {
932
0
        return -1;
933
0
    }
934
935
230
    if (length > MAX_STATUSMESSAGE_LENGTH) {
936
135
        return -1;
937
135
    }
938
939
95
    if (length > 0) {
940
49
        memcpy(m->friendlist[friendnumber].statusmessage, status, length);
941
49
    }
942
943
95
    m->friendlist[friendnumber].statusmessage_length = length;
944
95
    return 0;
945
230
}
946
947
static void set_friend_userstatus(const Messenger *_Nonnull m, int32_t friendnumber, uint8_t status)
948
230
{
949
230
    userstatus_from_int(status, &m->friendlist[friendnumber].userstatus);
950
230
}
951
952
static void set_friend_typing(const Messenger *_Nonnull m, int32_t friendnumber, bool is_typing)
953
0
{
954
0
    m->friendlist[friendnumber].is_typing = is_typing;
955
0
}
956
957
/** Set the function that will be executed when a friend request is received. */
958
void m_callback_friendrequest(Messenger *m, m_friend_request_cb *function)
959
1.46k
{
960
1.46k
    m->friend_request = function;
961
1.46k
}
962
963
/** Set the function that will be executed when a message from a friend is received. */
964
void m_callback_friendmessage(Messenger *m, m_friend_message_cb *function)
965
1.46k
{
966
1.46k
    m->friend_message = function;
967
1.46k
}
968
969
void m_callback_namechange(Messenger *m, m_friend_name_cb *function)
970
1.46k
{
971
1.46k
    m->friend_namechange = function;
972
1.46k
}
973
974
void m_callback_statusmessage(Messenger *m, m_friend_status_message_cb *function)
975
1.46k
{
976
1.46k
    m->friend_statusmessagechange = function;
977
1.46k
}
978
979
void m_callback_userstatus(Messenger *m, m_friend_status_cb *function)
980
1.46k
{
981
1.46k
    m->friend_userstatuschange = function;
982
1.46k
}
983
984
void m_callback_typingchange(Messenger *m, m_friend_typing_cb *function)
985
1.46k
{
986
1.46k
    m->friend_typingchange = function;
987
1.46k
}
988
989
void m_callback_read_receipt(Messenger *m, m_friend_read_receipt_cb *function)
990
1.46k
{
991
1.46k
    m->read_receipt = function;
992
1.46k
}
993
994
void m_callback_connectionstatus(Messenger *m, m_friend_connection_status_cb *function)
995
1.46k
{
996
1.46k
    m->friend_connectionstatuschange = function;
997
1.46k
}
998
999
void m_callback_core_connection(Messenger *m, m_self_connection_status_cb *function)
1000
1.46k
{
1001
1.46k
    m->core_connection_change = function;
1002
1.46k
}
1003
1004
static void check_friend_tcp_udp(Messenger *_Nonnull m, int32_t friendnumber, void *_Nullable userdata)
1005
0
{
1006
0
    const int last_connection_udp_tcp = m->friendlist[friendnumber].last_connection_udp_tcp;
1007
0
    const int ret = m_get_friend_connectionstatus(m, friendnumber);
1008
1009
0
    if (ret == -1) {
1010
0
        return;
1011
0
    }
1012
1013
0
    if (last_connection_udp_tcp != ret) {
1014
0
        if (m->friend_connectionstatuschange != nullptr) {
1015
0
            m->friend_connectionstatuschange(m, friendnumber, ret, userdata);
1016
0
        }
1017
0
    }
1018
1019
0
    m->friendlist[friendnumber].last_connection_udp_tcp = (Connection_Status)ret;
1020
0
}
1021
1022
static void break_files(const Messenger *_Nonnull m, int32_t friendnumber);
1023
1024
static void check_friend_connectionstatus(Messenger *_Nonnull m, int32_t friendnumber, uint8_t status, void *_Nullable userdata)
1025
0
{
1026
0
    if (status == NOFRIEND) {
1027
0
        return;
1028
0
    }
1029
1030
0
    const bool was_online = m->friendlist[friendnumber].status == FRIEND_ONLINE;
1031
0
    const bool is_online = status == FRIEND_ONLINE;
1032
1033
0
    if (is_online != was_online) {
1034
0
        if (was_online) {
1035
0
            break_files(m, friendnumber);
1036
0
            clear_receipts(m, friendnumber);
1037
0
        } else {
1038
0
            m->friendlist[friendnumber].name_sent = false;
1039
0
            m->friendlist[friendnumber].userstatus_sent = false;
1040
0
            m->friendlist[friendnumber].statusmessage_sent = false;
1041
0
            m->friendlist[friendnumber].user_istyping_sent = false;
1042
0
        }
1043
1044
0
        m->friendlist[friendnumber].status = status;
1045
1046
0
        check_friend_tcp_udp(m, friendnumber, userdata);
1047
0
    }
1048
0
}
1049
1050
static void set_friend_status(Messenger *_Nonnull m, int32_t friendnumber, uint8_t status, void *_Nullable userdata)
1051
0
{
1052
0
    check_friend_connectionstatus(m, friendnumber, status, userdata);
1053
0
    m->friendlist[friendnumber].status = status;
1054
0
}
1055
1056
/*** CONFERENCES */
1057
1058
/** @brief Set the callback for conference invites. */
1059
void m_callback_conference_invite(Messenger *m, m_conference_invite_cb *function)
1060
3.93k
{
1061
3.93k
    m->conference_invite = function;
1062
3.93k
}
1063
1064
/** @brief the callback for group invites. */
1065
void m_callback_group_invite(Messenger *m, m_group_invite_cb *function)
1066
1.46k
{
1067
1.46k
    m->group_invite = function;
1068
1.46k
}
1069
1070
/** @brief Send a conference invite packet.
1071
 *
1072
 * return true on success
1073
 * return false on failure
1074
 */
1075
bool send_conference_invite_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length)
1076
0
{
1077
0
    return write_cryptpacket_id(m, friendnumber, PACKET_ID_INVITE_CONFERENCE, data, length, false);
1078
0
}
1079
1080
/** @brief Send a group invite packet.
1081
 *
1082
 * @retval true if success
1083
 */
1084
bool send_group_invite_packet(const Messenger *m, uint32_t friendnumber, const uint8_t *packet, uint16_t length)
1085
0
{
1086
0
    return write_cryptpacket_id(m, friendnumber, PACKET_ID_INVITE_GROUPCHAT, packet, length, false);
1087
0
}
1088
1089
/*** FILE SENDING */
1090
1091
/** @brief Set the callback for file send requests. */
1092
void callback_file_sendrequest(Messenger *m, m_file_recv_cb *function)
1093
1.46k
{
1094
1.46k
    m->file_sendrequest = function;
1095
1.46k
}
1096
1097
/** @brief Set the callback for file control requests. */
1098
void callback_file_control(Messenger *m, m_file_recv_control_cb *function)
1099
1.46k
{
1100
1.46k
    m->file_filecontrol = function;
1101
1.46k
}
1102
1103
/** @brief Set the callback for file data. */
1104
void callback_file_data(Messenger *m, m_file_recv_chunk_cb *function)
1105
1.46k
{
1106
1.46k
    m->file_filedata = function;
1107
1.46k
}
1108
1109
/** @brief Set the callback for file request chunk. */
1110
void callback_file_reqchunk(Messenger *m, m_file_chunk_request_cb *function)
1111
1.46k
{
1112
1.46k
    m->file_reqchunk = function;
1113
1.46k
}
1114
1115
0
#define MAX_FILENAME_LENGTH 255
1116
1117
/** @brief Copy the file transfer file id to file_id
1118
 *
1119
 * @retval 0 on success.
1120
 * @retval -1 if friend not valid.
1121
 * @retval -2 if filenumber not valid
1122
 */
1123
int file_get_id(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint8_t *file_id)
1124
0
{
1125
0
    if (!m_friend_exists(m, friendnumber)) {
1126
0
        return -1;
1127
0
    }
1128
1129
0
    if (m->friendlist[friendnumber].status != FRIEND_ONLINE) {
1130
0
        return -2;
1131
0
    }
1132
1133
0
    uint32_t temp_filenum;
1134
0
    bool inbound;
1135
0
    uint8_t file_number;
1136
1137
0
    if (filenumber >= (1 << 16)) {
1138
0
        inbound = true;
1139
0
        temp_filenum = (filenumber >> 16) - 1;
1140
0
    } else {
1141
0
        inbound = false;
1142
0
        temp_filenum = filenumber;
1143
0
    }
1144
1145
0
    if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES) {
1146
0
        return -2;
1147
0
    }
1148
1149
0
    file_number = temp_filenum;
1150
1151
0
    const struct File_Transfers *const ft = inbound
1152
0
                                                ? &m->friendlist[friendnumber].file_receiving[file_number]
1153
0
                                                : &m->friendlist[friendnumber].file_sending[file_number];
1154
1155
0
    if (ft->status == FILESTATUS_NONE) {
1156
0
        return -2;
1157
0
    }
1158
1159
0
    memcpy(file_id, ft->id, FILE_ID_LENGTH);
1160
0
    return 0;
1161
0
}
1162
1163
/** @brief Send a file send request.
1164
 * Maximum filename length is 255 bytes.
1165
 * @retval 1 on success
1166
 * @retval 0 on failure
1167
 */
1168
static bool file_sendrequest(const Messenger *_Nonnull m, int32_t friendnumber, uint8_t filenumber, uint32_t file_type, uint64_t filesize, const uint8_t *_Nonnull file_id,
1169
                             const uint8_t *_Nonnull filename, uint16_t filename_length)
1170
0
{
1171
0
    if (!m_friend_exists(m, friendnumber)) {
1172
0
        return false;
1173
0
    }
1174
1175
0
    if (filename_length > MAX_FILENAME_LENGTH) {
1176
0
        return false;
1177
0
    }
1178
1179
0
    const uint16_t packet_size = 1 + sizeof(file_type) + sizeof(filesize) + FILE_ID_LENGTH + filename_length;
1180
0
    VLA(uint8_t, packet, packet_size);
1181
0
    packet[0] = filenumber;
1182
0
    file_type = net_htonl(file_type);
1183
0
    memcpy(packet + 1, &file_type, sizeof(file_type));
1184
0
    net_pack_u64(packet + 1 + sizeof(file_type), filesize);
1185
0
    memcpy(packet + 1 + sizeof(file_type) + sizeof(filesize), file_id, FILE_ID_LENGTH);
1186
1187
0
    if (filename_length > 0) {
1188
0
        memcpy(packet + 1 + sizeof(file_type) + sizeof(filesize) + FILE_ID_LENGTH, filename, filename_length);
1189
0
    }
1190
1191
0
    return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_SENDREQUEST, packet, packet_size, false);
1192
0
}
1193
1194
/** @brief Send a file send request.
1195
 *
1196
 * Maximum filename length is 255 bytes.
1197
 *
1198
 * @return file number on success
1199
 * @retval -1 if friend not found.
1200
 * @retval -2 if filename length invalid.
1201
 * @retval -3 if no more file sending slots left.
1202
 * @retval -4 if could not send packet (friend offline).
1203
 */
1204
long int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_type, uint64_t filesize,
1205
                        const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length)
1206
0
{
1207
0
    if (!m_friend_exists(m, friendnumber)) {
1208
0
        return -1;
1209
0
    }
1210
1211
0
    if (filename_length > MAX_FILENAME_LENGTH) {
1212
0
        return -2;
1213
0
    }
1214
1215
0
    uint32_t i;
1216
1217
0
    for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {
1218
0
        if (m->friendlist[friendnumber].file_sending[i].status == FILESTATUS_NONE) {
1219
0
            break;
1220
0
        }
1221
0
    }
1222
1223
0
    if (i == MAX_CONCURRENT_FILE_PIPES) {
1224
0
        return -3;
1225
0
    }
1226
1227
0
    if (!file_sendrequest(m, friendnumber, i, file_type, filesize, file_id, filename, filename_length)) {
1228
0
        return -4;
1229
0
    }
1230
1231
0
    struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[i];
1232
1233
0
    ft->status = FILESTATUS_NOT_ACCEPTED;
1234
1235
0
    ft->size = filesize;
1236
1237
0
    ft->transferred = 0;
1238
1239
0
    ft->requested = 0;
1240
1241
0
    ft->paused = FILE_PAUSE_NOT;
1242
1243
0
    memcpy(ft->id, file_id, FILE_ID_LENGTH);
1244
1245
0
    return i;
1246
0
}
1247
1248
static bool send_file_control_packet(const Messenger *_Nonnull m, int32_t friendnumber, bool inbound, uint8_t filenumber,
1249
                                     uint8_t control_type, const uint8_t *_Nullable data, uint16_t data_length)
1250
0
{
1251
0
    assert(data_length == 0 || data != nullptr);
1252
0
    if ((unsigned int)(1 + 3 + data_length) > MAX_CRYPTO_DATA_SIZE) {
1253
0
        return false;
1254
0
    }
1255
1256
0
    const uint16_t packet_size = 3 + data_length;
1257
0
    VLA(uint8_t, packet, packet_size);
1258
1259
0
    packet[0] = inbound ? 1 : 0;
1260
0
    packet[1] = filenumber;
1261
0
    packet[2] = control_type;
1262
1263
0
    if (data_length > 0) {
1264
0
        memcpy(packet + 3, data, data_length);
1265
0
    }
1266
1267
0
    return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_CONTROL, packet, packet_size, false);
1268
0
}
1269
1270
/** @brief Send a file control request.
1271
 *
1272
 * @retval 0 on success
1273
 * @retval -1 if friend not valid.
1274
 * @retval -2 if friend not online.
1275
 * @retval -3 if file number invalid.
1276
 * @retval -4 if file control is bad.
1277
 * @retval -5 if file already paused.
1278
 * @retval -6 if resume file failed because it was only paused by the other.
1279
 * @retval -7 if resume file failed because it wasn't paused.
1280
 * @retval -8 if packet failed to send.
1281
 */
1282
int file_control(const Messenger *m, int32_t friendnumber, uint32_t filenumber, unsigned int control)
1283
0
{
1284
0
    if (!m_friend_exists(m, friendnumber)) {
1285
0
        return -1;
1286
0
    }
1287
1288
0
    if (m->friendlist[friendnumber].status != FRIEND_ONLINE) {
1289
0
        return -2;
1290
0
    }
1291
1292
0
    uint32_t temp_filenum;
1293
0
    bool inbound;
1294
0
    uint8_t file_number;
1295
1296
0
    if (filenumber >= (1 << 16)) {
1297
0
        inbound = true;
1298
0
        temp_filenum = (filenumber >> 16) - 1;
1299
0
    } else {
1300
0
        inbound = false;
1301
0
        temp_filenum = filenumber;
1302
0
    }
1303
1304
0
    if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES) {
1305
0
        return -3;
1306
0
    }
1307
1308
0
    file_number = temp_filenum;
1309
1310
0
    struct File_Transfers *ft;
1311
1312
0
    if (inbound) {
1313
0
        ft = &m->friendlist[friendnumber].file_receiving[file_number];
1314
0
    } else {
1315
0
        ft = &m->friendlist[friendnumber].file_sending[file_number];
1316
0
    }
1317
1318
0
    if (ft->status == FILESTATUS_NONE) {
1319
0
        return -3;
1320
0
    }
1321
1322
0
    if (control > FILECONTROL_KILL) {
1323
0
        return -4;
1324
0
    }
1325
1326
0
    if (control == FILECONTROL_PAUSE && ((ft->paused & FILE_PAUSE_US) != 0 || ft->status != FILESTATUS_TRANSFERRING)) {
1327
0
        return -5;
1328
0
    }
1329
1330
0
    if (control == FILECONTROL_ACCEPT) {
1331
0
        if (ft->status == FILESTATUS_TRANSFERRING) {
1332
0
            if ((ft->paused & FILE_PAUSE_US) == 0) {
1333
0
                if ((ft->paused & FILE_PAUSE_OTHER) != 0) {
1334
0
                    return -6;
1335
0
                }
1336
1337
0
                return -7;
1338
0
            }
1339
0
        } else {
1340
0
            if (ft->status != FILESTATUS_NOT_ACCEPTED) {
1341
0
                return -7;
1342
0
            }
1343
1344
0
            if (!inbound) {
1345
0
                return -6;
1346
0
            }
1347
0
        }
1348
0
    }
1349
1350
0
    if (send_file_control_packet(m, friendnumber, inbound, file_number, control, nullptr, 0)) {
1351
0
        switch (control) {
1352
0
            case FILECONTROL_KILL: {
1353
0
                if (!inbound && (ft->status == FILESTATUS_TRANSFERRING || ft->status == FILESTATUS_FINISHED)) {
1354
                    // We are actively sending that file, remove from list
1355
0
                    --m->friendlist[friendnumber].num_sending_files;
1356
0
                }
1357
1358
0
                ft->status = FILESTATUS_NONE;
1359
0
                break;
1360
0
            }
1361
0
            case FILECONTROL_PAUSE: {
1362
0
                ft->paused |= FILE_PAUSE_US;
1363
0
                break;
1364
0
            }
1365
0
            case FILECONTROL_ACCEPT: {
1366
0
                ft->status = FILESTATUS_TRANSFERRING;
1367
1368
0
                if ((ft->paused & FILE_PAUSE_US) != 0) {
1369
0
                    ft->paused ^= FILE_PAUSE_US;
1370
0
                }
1371
0
                break;
1372
0
            }
1373
0
        }
1374
0
    } else {
1375
0
        return -8;
1376
0
    }
1377
1378
0
    return 0;
1379
0
}
1380
1381
/** @brief Send a seek file control request.
1382
 *
1383
 * @retval 0 on success
1384
 * @retval -1 if friend not valid.
1385
 * @retval -2 if friend not online.
1386
 * @retval -3 if file number invalid.
1387
 * @retval -4 if not receiving file.
1388
 * @retval -5 if file status wrong.
1389
 * @retval -6 if position bad.
1390
 * @retval -8 if packet failed to send.
1391
 */
1392
int file_seek(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position)
1393
0
{
1394
0
    if (!m_friend_exists(m, friendnumber)) {
1395
0
        return -1;
1396
0
    }
1397
1398
0
    if (m->friendlist[friendnumber].status != FRIEND_ONLINE) {
1399
0
        return -2;
1400
0
    }
1401
1402
0
    if (filenumber < (1 << 16)) {
1403
        // Not receiving.
1404
0
        return -4;
1405
0
    }
1406
1407
0
    const uint32_t temp_filenum = (filenumber >> 16) - 1;
1408
1409
0
    if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES) {
1410
0
        return -3;
1411
0
    }
1412
1413
0
    assert(temp_filenum <= UINT8_MAX);
1414
0
    const uint8_t file_number = temp_filenum;
1415
1416
    // We're always receiving at this point.
1417
0
    struct File_Transfers *ft = &m->friendlist[friendnumber].file_receiving[file_number];
1418
1419
0
    if (ft->status == FILESTATUS_NONE) {
1420
0
        return -3;
1421
0
    }
1422
1423
0
    if (ft->status != FILESTATUS_NOT_ACCEPTED) {
1424
0
        return -5;
1425
0
    }
1426
1427
0
    if (position >= ft->size) {
1428
0
        return -6;
1429
0
    }
1430
1431
0
    uint8_t sending_pos[sizeof(uint64_t)];
1432
0
    net_pack_u64(sending_pos, position);
1433
1434
0
    if (send_file_control_packet(m, friendnumber, true, file_number, FILECONTROL_SEEK, sending_pos,
1435
0
                                 sizeof(sending_pos))) {
1436
0
        ft->transferred = position;
1437
0
    } else {
1438
0
        return -8;
1439
0
    }
1440
1441
0
    return 0;
1442
0
}
1443
1444
/** @return packet number on success.
1445
 * @retval -1 on failure.
1446
 */
1447
static int64_t send_file_data_packet(const Messenger *_Nonnull m, int32_t friendnumber, uint8_t filenumber, const uint8_t *_Nullable data,
1448
                                     uint16_t length)
1449
0
{
1450
0
    assert(length == 0 || data != nullptr);
1451
0
    if (!m_friend_exists(m, friendnumber)) {
1452
0
        return -1;
1453
0
    }
1454
1455
0
    const uint16_t packet_size = 2 + length;
1456
0
    VLA(uint8_t, packet, packet_size);
1457
0
    packet[0] = PACKET_ID_FILE_DATA;
1458
0
    packet[1] = filenumber;
1459
1460
0
    if (length > 0) {
1461
0
        memcpy(packet + 2, data, length);
1462
0
    }
1463
1464
0
    return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
1465
0
                             m->friendlist[friendnumber].friendcon_id), packet, packet_size, true);
1466
0
}
1467
1468
0
#define MAX_FILE_DATA_SIZE (MAX_CRYPTO_DATA_SIZE - 2)
1469
0
#define MIN_SLOTS_FREE (CRYPTO_MIN_QUEUE_LENGTH / 4)
1470
/** @brief Send file data.
1471
 *
1472
 * @retval 0 on success
1473
 * @retval -1 if friend not valid.
1474
 * @retval -2 if friend not online.
1475
 * @retval -3 if filenumber invalid.
1476
 * @retval -4 if file transfer not transferring.
1477
 * @retval -5 if bad data size.
1478
 * @retval -6 if packet queue full.
1479
 * @retval -7 if wrong position.
1480
 */
1481
int send_file_data(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position,
1482
                   const uint8_t *data, uint16_t length)
1483
0
{
1484
0
    assert(length == 0 || data != nullptr);
1485
1486
0
    if (!m_friend_exists(m, friendnumber)) {
1487
0
        return -1;
1488
0
    }
1489
1490
0
    if (m->friendlist[friendnumber].status != FRIEND_ONLINE) {
1491
0
        return -2;
1492
0
    }
1493
1494
0
    if (filenumber >= MAX_CONCURRENT_FILE_PIPES) {
1495
0
        return -3;
1496
0
    }
1497
1498
0
    struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[filenumber];
1499
1500
0
    if (ft->status != FILESTATUS_TRANSFERRING) {
1501
0
        return -4;
1502
0
    }
1503
1504
0
    if (length > MAX_FILE_DATA_SIZE) {
1505
0
        return -5;
1506
0
    }
1507
1508
0
    if (ft->size - ft->transferred < length) {
1509
0
        return -5;
1510
0
    }
1511
1512
0
    if (ft->size != UINT64_MAX && length != MAX_FILE_DATA_SIZE && (ft->transferred + length) != ft->size) {
1513
0
        return -5;
1514
0
    }
1515
1516
0
    if (position != ft->transferred || (ft->requested <= position && ft->size != 0)) {
1517
0
        return -7;
1518
0
    }
1519
1520
    /* Prevent file sending from filling up the entire buffer preventing messages from being sent.
1521
     * TODO(irungentoo): remove */
1522
0
    if (crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
1523
0
                                        m->friendlist[friendnumber].friendcon_id)) < MIN_SLOTS_FREE) {
1524
0
        return -6;
1525
0
    }
1526
1527
0
    const int64_t ret = send_file_data_packet(m, friendnumber, filenumber, data, length);
1528
1529
0
    if (ret != -1) {
1530
        // TODO(irungentoo): record packet ids to check if other received complete file.
1531
0
        ft->transferred += length;
1532
1533
0
        if (length != MAX_FILE_DATA_SIZE || ft->size == ft->transferred) {
1534
0
            ft->status = FILESTATUS_FINISHED;
1535
0
            ft->last_packet_number = ret;
1536
0
        }
1537
1538
0
        return 0;
1539
0
    }
1540
1541
0
    return -6;
1542
0
}
1543
1544
/**
1545
 * Iterate over all file transfers and request chunks (from the client) for each
1546
 * of them.
1547
 *
1548
 * The free_slots parameter is updated by this function.
1549
 *
1550
 * @param m Our messenger object.
1551
 * @param friendnumber The friend we're sending files to.
1552
 * @param userdata The client userdata to pass along to chunk request callbacks.
1553
 * @param free_slots A pointer to the number of free send queue slots in the
1554
 *   crypto connection.
1555
 * @return true if there's still work to do, false otherwise.
1556
 *
1557
 */
1558
static bool do_all_filetransfers(Messenger *_Nonnull m, int32_t friendnumber, void *_Nonnull userdata, uint32_t *_Nonnull free_slots)
1559
0
{
1560
0
    Friend *const friendcon = &m->friendlist[friendnumber];
1561
1562
    // Iterate over file transfers as long as we're sending files
1563
0
    for (uint32_t i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {
1564
0
        if (friendcon->num_sending_files == 0) {
1565
            // no active file transfers anymore
1566
0
            return false;
1567
0
        }
1568
1569
0
        if (*free_slots == 0) {
1570
            // send buffer full enough
1571
0
            return false;
1572
0
        }
1573
1574
0
        struct File_Transfers *const ft = &friendcon->file_sending[i];
1575
1576
0
        if (ft->status == FILESTATUS_NONE || ft->status == FILESTATUS_NOT_ACCEPTED) {
1577
            // Filetransfers not actively sending, nothing to do
1578
0
            continue;
1579
0
        }
1580
1581
0
        if (max_speed_reached(m->net_crypto, friend_connection_crypt_connection_id(
1582
0
                                  m->fr_c, friendcon->friendcon_id))) {
1583
0
            LOGGER_DEBUG(m->log, "maximum connection speed reached");
1584
            // connection doesn't support any more data
1585
0
            return false;
1586
0
        }
1587
1588
        // If the file transfer is complete, we request a chunk of size 0.
1589
0
        if (ft->status == FILESTATUS_FINISHED && friend_received_packet(m, friendnumber, ft->last_packet_number) == 0) {
1590
0
            if (m->file_reqchunk != nullptr) {
1591
0
                m->file_reqchunk(m, friendnumber, i, ft->transferred, 0, userdata);
1592
0
            }
1593
1594
            // Now it's inactive, we're no longer sending this.
1595
0
            ft->status = FILESTATUS_NONE;
1596
0
            --friendcon->num_sending_files;
1597
0
        } else if (ft->status == FILESTATUS_TRANSFERRING && ft->paused == FILE_PAUSE_NOT) {
1598
0
            if (ft->size == 0) {
1599
                /* Send 0 data to friend if file is 0 length. */
1600
0
                send_file_data(m, friendnumber, i, 0, nullptr, 0);
1601
0
                continue;
1602
0
            }
1603
1604
0
            if (ft->size == ft->requested) {
1605
                // This file transfer is done.
1606
0
                continue;
1607
0
            }
1608
1609
0
            const uint16_t length = min_u64(ft->size - ft->requested, MAX_FILE_DATA_SIZE);
1610
0
            const uint64_t position = ft->requested;
1611
0
            ft->requested += length;
1612
1613
0
            if (m->file_reqchunk != nullptr) {
1614
0
                m->file_reqchunk(m, friendnumber, i, position, length, userdata);
1615
0
            }
1616
1617
            // The allocated slot is no longer free.
1618
0
            --*free_slots;
1619
0
        }
1620
0
    }
1621
1622
0
    return true;
1623
0
}
1624
1625
static void do_reqchunk_filecb(Messenger *_Nonnull m, int32_t friendnumber, void *_Nullable userdata)
1626
0
{
1627
    // We're not currently doing any file transfers.
1628
0
    if (m->friendlist[friendnumber].num_sending_files == 0) {
1629
0
        return;
1630
0
    }
1631
1632
    // The number of packet slots left in the sendbuffer.
1633
    // This is a per friend count (CRYPTO_PACKET_BUFFER_SIZE).
1634
0
    uint32_t free_slots = crypto_num_free_sendqueue_slots(
1635
0
                              m->net_crypto,
1636
0
                              friend_connection_crypt_connection_id(
1637
0
                                  m->fr_c,
1638
0
                                  m->friendlist[friendnumber].friendcon_id));
1639
1640
    // We keep MIN_SLOTS_FREE slots free for other packets, otherwise file
1641
    // transfers might block other traffic for a long time.
1642
0
    free_slots = max_s32(0, (int32_t)free_slots - MIN_SLOTS_FREE);
1643
1644
    // Maximum number of outer loops below. If the client doesn't send file
1645
    // chunks from within the chunk request callback handler, we never realise
1646
    // that the file transfer has finished and may end up in an infinite loop.
1647
    //
1648
    // Request up to that number of chunks per file from the client
1649
    //
1650
    // TODO(Jfreegman): set this cap dynamically
1651
0
    const uint32_t max_ft_loops = 128;
1652
1653
0
    for (uint32_t i = 0; i < max_ft_loops; ++i) {
1654
0
        if (!do_all_filetransfers(m, friendnumber, userdata, &free_slots)) {
1655
0
            break;
1656
0
        }
1657
1658
0
        if (free_slots == 0) {
1659
            // stop when the buffer is full enough
1660
0
            break;
1661
0
        }
1662
0
    }
1663
0
}
1664
1665
/** @brief Run this when the friend disconnects.
1666
 * Kill all current file transfers.
1667
 */
1668
static void break_files(const Messenger *m, int32_t friendnumber)
1669
0
{
1670
0
    Friend *const f = &m->friendlist[friendnumber];
1671
1672
    // TODO(irungentoo): Inform the client which file transfers get killed with a callback?
1673
0
    for (uint32_t i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {
1674
0
        f->file_sending[i].status = FILESTATUS_NONE;
1675
0
        f->file_receiving[i].status = FILESTATUS_NONE;
1676
0
    }
1677
0
}
1678
1679
static struct File_Transfers *get_file_transfer(bool outbound, uint8_t filenumber, uint32_t *_Nonnull real_filenumber, Friend *_Nonnull sender)
1680
0
{
1681
0
    struct File_Transfers *ft;
1682
1683
0
    if (outbound) {
1684
0
        *real_filenumber = filenumber;
1685
0
        ft = &sender->file_sending[filenumber];
1686
0
    } else {
1687
0
        *real_filenumber = (filenumber + 1) << 16;
1688
0
        ft = &sender->file_receiving[filenumber];
1689
0
    }
1690
1691
0
    if (ft->status == FILESTATUS_NONE) {
1692
0
        return nullptr;
1693
0
    }
1694
1695
0
    return ft;
1696
0
}
1697
1698
/** @retval -1 on failure
1699
 * @retval 0 on success.
1700
 */
1701
static int handle_filecontrol(Messenger *_Nonnull m, int32_t friendnumber, bool outbound, uint8_t filenumber,
1702
                              uint8_t control_type, const uint8_t *_Nonnull data, uint16_t length, void *_Nullable userdata)
1703
0
{
1704
0
    uint32_t real_filenumber;
1705
0
    struct File_Transfers *ft = get_file_transfer(outbound, filenumber, &real_filenumber, &m->friendlist[friendnumber]);
1706
1707
0
    if (ft == nullptr) {
1708
0
        LOGGER_DEBUG(m->log, "file control (friend %d, file %d): file transfer does not exist; telling the other to kill it",
1709
0
                     friendnumber, filenumber);
1710
0
        send_file_control_packet(m, friendnumber, !outbound, filenumber, FILECONTROL_KILL, nullptr, 0);
1711
0
        return -1;
1712
0
    }
1713
1714
0
    switch (control_type) {
1715
0
        case FILECONTROL_ACCEPT: {
1716
0
            if (outbound && ft->status == FILESTATUS_NOT_ACCEPTED) {
1717
0
                ft->status = FILESTATUS_TRANSFERRING;
1718
0
                ++m->friendlist[friendnumber].num_sending_files;
1719
0
            } else {
1720
0
                if ((ft->paused & FILE_PAUSE_OTHER) != 0) {
1721
0
                    ft->paused ^= FILE_PAUSE_OTHER;
1722
0
                } else {
1723
0
                    LOGGER_DEBUG(m->log, "file control (friend %d, file %d): friend told us to resume file transfer that wasn't paused",
1724
0
                                 friendnumber, filenumber);
1725
0
                    return -1;
1726
0
                }
1727
0
            }
1728
1729
0
            if (m->file_filecontrol != nullptr) {
1730
0
                m->file_filecontrol(m, friendnumber, real_filenumber, control_type, userdata);
1731
0
            }
1732
1733
0
            return 0;
1734
0
        }
1735
1736
0
        case FILECONTROL_PAUSE: {
1737
0
            if ((ft->paused & FILE_PAUSE_OTHER) != 0 || ft->status != FILESTATUS_TRANSFERRING) {
1738
0
                LOGGER_DEBUG(m->log, "file control (friend %d, file %d): friend told us to pause file transfer that is already paused",
1739
0
                             friendnumber, filenumber);
1740
0
                return -1;
1741
0
            }
1742
1743
0
            ft->paused |= FILE_PAUSE_OTHER;
1744
1745
0
            if (m->file_filecontrol != nullptr) {
1746
0
                m->file_filecontrol(m, friendnumber, real_filenumber, control_type, userdata);
1747
0
            }
1748
1749
0
            return 0;
1750
0
        }
1751
1752
0
        case FILECONTROL_KILL: {
1753
0
            if (m->file_filecontrol != nullptr) {
1754
0
                m->file_filecontrol(m, friendnumber, real_filenumber, control_type, userdata);
1755
0
            }
1756
1757
0
            if (outbound && (ft->status == FILESTATUS_TRANSFERRING || ft->status == FILESTATUS_FINISHED)) {
1758
0
                --m->friendlist[friendnumber].num_sending_files;
1759
0
            }
1760
1761
0
            ft->status = FILESTATUS_NONE;
1762
1763
0
            return 0;
1764
0
        }
1765
1766
0
        case FILECONTROL_SEEK: {
1767
0
            uint64_t position;
1768
1769
0
            if (length != sizeof(position)) {
1770
0
                LOGGER_DEBUG(m->log, "file control (friend %d, file %d): expected payload of length %u, but got %d",
1771
0
                             friendnumber, filenumber, (unsigned int)sizeof(position), length);
1772
0
                return -1;
1773
0
            }
1774
1775
            /* seek can only be sent by the receiver to seek before resuming broken transfers. */
1776
0
            if (ft->status != FILESTATUS_NOT_ACCEPTED || !outbound) {
1777
0
                LOGGER_DEBUG(m->log,
1778
0
                             "file control (friend %d, file %d): seek was either sent by a sender or by the receiver after accepting",
1779
0
                             friendnumber, filenumber);
1780
0
                return -1;
1781
0
            }
1782
1783
0
            net_unpack_u64(data, &position);
1784
1785
0
            if (position >= ft->size) {
1786
0
                LOGGER_DEBUG(m->log,
1787
0
                             "file control (friend %d, file %d): seek position %lu exceeds file size %lu",
1788
0
                             friendnumber, filenumber, (unsigned long)position, (unsigned long)ft->size);
1789
0
                return -1;
1790
0
            }
1791
1792
0
            ft->requested = position;
1793
0
            ft->transferred = position;
1794
0
            return 0;
1795
0
        }
1796
1797
0
        default: {
1798
0
            LOGGER_DEBUG(m->log, "file control (friend %d, file %d): invalid file control: %d",
1799
0
                         friendnumber, filenumber, control_type);
1800
0
            return -1;
1801
0
        }
1802
0
    }
1803
0
}
1804
1805
static int m_handle_lossy_packet(void *object, int friendcon_id, const uint8_t *data, uint16_t length,
1806
                                 void *userdata)
1807
0
{
1808
0
    Messenger *m = (Messenger *)object;
1809
1810
0
    if (!m_friend_exists(m, friendcon_id)) {
1811
0
        return 1;
1812
0
    }
1813
1814
0
    if (m->lossy_packethandler != nullptr) {
1815
0
        m->lossy_packethandler(m, friendcon_id, data[0], data, length, userdata);
1816
0
    }
1817
1818
0
    return 1;
1819
0
}
1820
1821
void custom_lossy_packet_registerhandler(Messenger *m, m_friend_lossy_packet_cb *lossy_packethandler)
1822
1.46k
{
1823
1.46k
    m->lossy_packethandler = lossy_packethandler;
1824
1.46k
}
1825
1826
int m_send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length)
1827
0
{
1828
0
    if (!m_friend_exists(m, friendnumber)) {
1829
0
        return -1;
1830
0
    }
1831
1832
0
    if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) {
1833
0
        return -2;
1834
0
    }
1835
1836
0
    if (data[0] < PACKET_ID_RANGE_LOSSY_START || data[0] > PACKET_ID_RANGE_LOSSY_END) {
1837
0
        return -3;
1838
0
    }
1839
1840
0
    if (m->friendlist[friendnumber].status != FRIEND_ONLINE) {
1841
0
        return -4;
1842
0
    }
1843
1844
0
    if (send_lossy_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
1845
0
                               m->friendlist[friendnumber].friendcon_id), data, length) == -1) {
1846
0
        return -5;
1847
0
    }
1848
1849
0
    return 0;
1850
0
}
1851
1852
static int handle_custom_lossless_packet(void *_Nonnull object, int friend_num, const uint8_t *_Nonnull packet, uint16_t length,
1853
        void *_Nullable userdata)
1854
0
{
1855
0
    Messenger *m = (Messenger *)object;
1856
0
    if (!m_friend_exists(m, friend_num)) {
1857
0
        return -1;
1858
0
    }
1859
1860
0
    if (packet[0] < PACKET_ID_RANGE_LOSSLESS_CUSTOM_START || packet[0] > PACKET_ID_RANGE_LOSSLESS_CUSTOM_END) {
1861
        // allow PACKET_ID_MSI packets to be handled by custom packet handler
1862
0
        if (packet[0] != PACKET_ID_MSI) {
1863
0
            return -1;
1864
0
        }
1865
0
    }
1866
1867
0
    if (m->lossless_packethandler != nullptr) {
1868
0
        m->lossless_packethandler(m, friend_num, packet[0], packet, length, userdata);
1869
0
    }
1870
1871
0
    return 1;
1872
0
}
1873
1874
void custom_lossless_packet_registerhandler(Messenger *m, m_friend_lossless_packet_cb *lossless_packethandler)
1875
1.46k
{
1876
1.46k
    m->lossless_packethandler = lossless_packethandler;
1877
1.46k
}
1878
1879
int send_custom_lossless_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length)
1880
0
{
1881
0
    if (!m_friend_exists(m, friendnumber)) {
1882
0
        return -1;
1883
0
    }
1884
1885
0
    if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) {
1886
0
        return -2;
1887
0
    }
1888
1889
0
    if ((data[0] < PACKET_ID_RANGE_LOSSLESS_CUSTOM_START || data[0] > PACKET_ID_RANGE_LOSSLESS_CUSTOM_END)
1890
0
            && data[0] != PACKET_ID_MSI) {
1891
0
        return -3;
1892
0
    }
1893
1894
0
    if (m->friendlist[friendnumber].status != FRIEND_ONLINE) {
1895
0
        return -4;
1896
0
    }
1897
1898
0
    if (write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,
1899
0
                          m->friendlist[friendnumber].friendcon_id), data, length, true) == -1) {
1900
0
        return -5;
1901
0
    }
1902
1903
0
    return 0;
1904
0
}
1905
1906
/** Function to filter out some friend requests*/
1907
static int friend_already_added(void *_Nonnull object, const uint8_t *_Nonnull public_key)
1908
0
{
1909
0
    const Messenger *m = (const Messenger *)object;
1910
1911
0
    if (getfriend_id(m, public_key) == -1) {
1912
0
        return 0;
1913
0
    }
1914
1915
0
    return -1;
1916
0
}
1917
1918
/** @brief Check for and handle a timed-out friend request.
1919
 *
1920
 * If the request has timed-out then the friend status is set back to FRIEND_ADDED.
1921
 * @param friendcon_id friendlist index of the timed-out friend
1922
 * @param t time
1923
 */
1924
static void check_friend_request_timed_out(Messenger *_Nonnull m, uint32_t friendcon_id, uint64_t t, void *_Nullable userdata)
1925
0
{
1926
0
    Friend *f = &m->friendlist[friendcon_id];
1927
0
    if (f->friendrequest_lastsent + f->friendrequest_timeout < t) {
1928
0
        set_friend_status(m, friendcon_id, FRIEND_ADDED, userdata);
1929
        /* Double the default timeout every time if friendrequest is assumed
1930
         * to have been sent unsuccessfully.
1931
         */
1932
0
        f->friendrequest_timeout *= 2;
1933
0
    }
1934
0
}
1935
1936
static int m_handle_status(void *_Nonnull object, int friendcon_id, bool status, void *_Nullable userdata)
1937
0
{
1938
0
    Messenger *m = (Messenger *)object;
1939
0
    if (status) { /* Went online. */
1940
0
        send_online_packet(m, m->friendlist[friendcon_id].friendcon_id);
1941
0
    } else { /* Went offline. */
1942
0
        if (m->friendlist[friendcon_id].status == FRIEND_ONLINE) {
1943
0
            set_friend_status(m, friendcon_id, FRIEND_CONFIRMED, userdata);
1944
0
        }
1945
0
    }
1946
1947
0
    return 0;
1948
0
}
1949
1950
static int m_handle_packet_offline(Messenger *_Nonnull m, const int friendcon_id, const uint8_t *_Nonnull data, const uint16_t data_length, void *_Nullable userdata)
1951
0
{
1952
0
    if (data_length == 0) {
1953
0
        set_friend_status(m, friendcon_id, FRIEND_CONFIRMED, userdata);
1954
0
    }
1955
1956
0
    return 0;
1957
0
}
1958
1959
static int m_handle_packet_nickname(Messenger *_Nonnull m, const int friendcon_id, const uint8_t *_Nonnull data, const uint16_t data_length, void *_Nullable userdata)
1960
0
{
1961
0
    if (data_length > MAX_NAME_LENGTH) {
1962
0
        return 0;
1963
0
    }
1964
1965
    /* Make sure the NULL terminator is present. */
1966
0
    VLA(uint8_t, data_terminated, data_length + 1);
1967
0
    memcpy(data_terminated, data, data_length);
1968
0
    data_terminated[data_length] = 0;
1969
1970
    /* inform of namechange before we overwrite the old name */
1971
0
    if (m->friend_namechange != nullptr) {
1972
0
        m->friend_namechange(m, friendcon_id, data_terminated, data_length, userdata);
1973
0
    }
1974
1975
0
    memcpy(m->friendlist[friendcon_id].name, data_terminated, data_length);
1976
0
    m->friendlist[friendcon_id].name_length = data_length;
1977
1978
0
    return 0;
1979
0
}
1980
1981
static int m_handle_packet_statusmessage(Messenger *_Nonnull m, const int friendcon_id, const uint8_t *_Nonnull data, const uint16_t data_length, void *_Nullable userdata)
1982
0
{
1983
0
    if (data_length > MAX_STATUSMESSAGE_LENGTH) {
1984
0
        return 0;
1985
0
    }
1986
1987
    /* Make sure the NULL terminator is present. */
1988
0
    VLA(uint8_t, data_terminated, data_length + 1);
1989
0
    memcpy(data_terminated, data, data_length);
1990
0
    data_terminated[data_length] = 0;
1991
1992
0
    if (m->friend_statusmessagechange != nullptr) {
1993
0
        m->friend_statusmessagechange(m, friendcon_id, data_terminated, data_length, userdata);
1994
0
    }
1995
1996
0
    set_friend_statusmessage(m, friendcon_id, data_terminated, data_length);
1997
1998
0
    return 0;
1999
0
}
2000
2001
static int m_handle_packet_userstatus(Messenger *_Nonnull m, const int friendcon_id, const uint8_t *_Nonnull data, const uint16_t data_length, void *_Nullable userdata)
2002
0
{
2003
0
    if (data_length != 1) {
2004
0
        return 0;
2005
0
    }
2006
2007
0
    Userstatus status;
2008
0
    if (!userstatus_from_int(data[0], &status)) {
2009
0
        return 0;
2010
0
    }
2011
2012
0
    if (m->friend_userstatuschange != nullptr) {
2013
0
        m->friend_userstatuschange(m, friendcon_id, status, userdata);
2014
0
    }
2015
2016
0
    set_friend_userstatus(m, friendcon_id, status);
2017
2018
0
    return 0;
2019
0
}
2020
2021
static int m_handle_packet_typing(Messenger *_Nonnull m, const int friendcon_id, const uint8_t *_Nonnull data, const uint16_t data_length, void *_Nullable userdata)
2022
0
{
2023
0
    if (data_length != 1) {
2024
0
        return 0;
2025
0
    }
2026
2027
0
    const bool typing = data[0] != 0;
2028
2029
0
    set_friend_typing(m, friendcon_id, typing);
2030
2031
0
    if (m->friend_typingchange != nullptr) {
2032
0
        m->friend_typingchange(m, friendcon_id, typing, userdata);
2033
0
    }
2034
2035
0
    return 0;
2036
0
}
2037
2038
static int m_handle_packet_message(Messenger *_Nonnull m, const int friendcon_id, const uint8_t *_Nonnull data, const uint16_t data_length, const Message_Type message_type,
2039
                                   void *_Nullable userdata)
2040
0
{
2041
0
    if (data_length == 0) {
2042
0
        return 0;
2043
0
    }
2044
2045
0
    const uint8_t *message = data;
2046
0
    const uint16_t message_length = data_length;
2047
2048
    /* Make sure the NULL terminator is present. */
2049
0
    VLA(uint8_t, message_terminated, message_length + 1);
2050
0
    memcpy(message_terminated, message, message_length);
2051
0
    message_terminated[message_length] = 0;
2052
2053
0
    if (m->friend_message != nullptr) {
2054
0
        m->friend_message(m, friendcon_id, message_type, message_terminated, message_length, userdata);
2055
0
    }
2056
2057
0
    return 0;
2058
0
}
2059
2060
static int m_handle_packet_invite_conference(Messenger *_Nonnull m, const int friendcon_id, const uint8_t *_Nonnull data, const uint16_t data_length, void *_Nullable userdata)
2061
0
{
2062
0
    if (data_length == 0) {
2063
0
        return 0;
2064
0
    }
2065
2066
0
    if (m->conference_invite != nullptr) {
2067
0
        m->conference_invite(m, friendcon_id, data, data_length, userdata);
2068
0
    }
2069
2070
0
    return 0;
2071
0
}
2072
2073
static int m_handle_packet_file_sendrequest(Messenger *_Nonnull m, const int friendcon_id, const uint8_t *_Nonnull data, const uint16_t data_length, void *_Nullable userdata)
2074
0
{
2075
0
    const unsigned int head_length = 1 + sizeof(uint32_t) + sizeof(uint64_t) + FILE_ID_LENGTH;
2076
0
    if (data_length < head_length) {
2077
0
        return 0;
2078
0
    }
2079
2080
0
    const uint8_t filenumber = data[0];
2081
2082
#if UINT8_MAX >= MAX_CONCURRENT_FILE_PIPES
2083
2084
    if (filenumber >= MAX_CONCURRENT_FILE_PIPES) {
2085
        return 0;
2086
    }
2087
2088
#endif /* UINT8_MAX >= MAX_CONCURRENT_FILE_PIPES */
2089
2090
0
    uint64_t filesize;
2091
0
    uint32_t file_type;
2092
0
    const uint16_t filename_length = data_length - head_length;
2093
2094
0
    if (filename_length > MAX_FILENAME_LENGTH) {
2095
0
        return 0;
2096
0
    }
2097
2098
0
    memcpy(&file_type, data + 1, sizeof(file_type));
2099
0
    file_type = net_ntohl(file_type);
2100
2101
0
    net_unpack_u64(data + 1 + sizeof(uint32_t), &filesize);
2102
0
    struct File_Transfers *ft = &m->friendlist[friendcon_id].file_receiving[filenumber];
2103
2104
0
    if (ft->status != FILESTATUS_NONE) {
2105
0
        return 0;
2106
0
    }
2107
2108
0
    ft->status = FILESTATUS_NOT_ACCEPTED;
2109
0
    ft->size = filesize;
2110
0
    ft->transferred = 0;
2111
0
    ft->paused = FILE_PAUSE_NOT;
2112
0
    memcpy(ft->id, data + 1 + sizeof(uint32_t) + sizeof(uint64_t), FILE_ID_LENGTH);
2113
2114
0
    VLA(uint8_t, filename_terminated, filename_length + 1);
2115
0
    const uint8_t *filename = nullptr;
2116
2117
0
    if (filename_length > 0) {
2118
        /* Force NULL terminate file name. */
2119
0
        memcpy(filename_terminated, data + head_length, filename_length);
2120
0
        filename_terminated[filename_length] = 0;
2121
0
        filename = filename_terminated;
2122
0
    }
2123
2124
0
    uint32_t real_filenumber = filenumber;
2125
0
    real_filenumber += 1;
2126
0
    real_filenumber <<= 16;
2127
2128
0
    if (m->file_sendrequest != nullptr) {
2129
0
        m->file_sendrequest(m, friendcon_id, real_filenumber, file_type, filesize, filename, filename_length,
2130
0
                            userdata);
2131
0
    }
2132
2133
0
    return 0;
2134
0
}
2135
2136
static int m_handle_packet_file_control(Messenger *_Nonnull m, const int friendcon_id, const uint8_t *_Nonnull data, const uint16_t data_length, void *_Nullable userdata)
2137
0
{
2138
0
    if (data_length < 3) {
2139
0
        return 0;
2140
0
    }
2141
2142
    // On the other side, "outbound" is "inbound", i.e. if they send 1,
2143
    // that means "inbound" on their side, but we call it "outbound"
2144
    // here.
2145
0
    const bool outbound = data[0] == 1;
2146
0
    const uint8_t filenumber = data[1];
2147
0
    const uint8_t control_type = data[2];
2148
2149
#if UINT8_MAX >= MAX_CONCURRENT_FILE_PIPES
2150
2151
    if (filenumber >= MAX_CONCURRENT_FILE_PIPES) {
2152
        return 0;
2153
    }
2154
2155
#endif /* UINT8_MAX >= MAX_CONCURRENT_FILE_PIPES */
2156
2157
0
    if (handle_filecontrol(m, friendcon_id, outbound, filenumber, control_type, data + 3, data_length - 3, userdata) == -1) {
2158
        // TODO(iphydf): Do something different here? Right now, this
2159
        // check is pointless.
2160
0
        return 0;
2161
0
    }
2162
2163
0
    return 0;
2164
0
}
2165
2166
static int m_handle_packet_file_data(Messenger *_Nonnull m, const int friendcon_id, const uint8_t *_Nonnull data, const uint16_t data_length, void *_Nullable userdata)
2167
0
{
2168
0
    if (data_length < 1) {
2169
0
        return 0;
2170
0
    }
2171
2172
0
    const uint8_t filenumber = data[0];
2173
2174
#if UINT8_MAX >= MAX_CONCURRENT_FILE_PIPES
2175
2176
    if (filenumber >= MAX_CONCURRENT_FILE_PIPES) {
2177
        return 0;
2178
    }
2179
2180
#endif /* UINT8_MAX >= MAX_CONCURRENT_FILE_PIPES */
2181
2182
0
    struct File_Transfers *ft = &m->friendlist[friendcon_id].file_receiving[filenumber];
2183
2184
0
    if (ft->status != FILESTATUS_TRANSFERRING) {
2185
0
        return 0;
2186
0
    }
2187
2188
0
    uint64_t position = ft->transferred;
2189
0
    uint32_t real_filenumber = filenumber;
2190
0
    real_filenumber += 1;
2191
0
    real_filenumber <<= 16;
2192
0
    uint16_t file_data_length = data_length - 1;
2193
0
    const uint8_t *file_data;
2194
2195
0
    if (file_data_length == 0) {
2196
0
        file_data = nullptr;
2197
0
    } else {
2198
0
        file_data = data + 1;
2199
0
    }
2200
2201
    /* Prevent more data than the filesize from being passed to clients. */
2202
0
    if ((ft->transferred + file_data_length) > ft->size) {
2203
0
        file_data_length = ft->size - ft->transferred;
2204
0
    }
2205
2206
0
    if (m->file_filedata != nullptr) {
2207
0
        m->file_filedata(m, friendcon_id, real_filenumber, position, file_data, file_data_length, userdata);
2208
0
    }
2209
2210
0
    ft->transferred += file_data_length;
2211
2212
0
    if (file_data_length > 0 && (ft->transferred >= ft->size || file_data_length != MAX_FILE_DATA_SIZE)) {
2213
0
        file_data_length = 0;
2214
0
        file_data = nullptr;
2215
0
        position = ft->transferred;
2216
2217
        /* Full file received. */
2218
0
        if (m->file_filedata != nullptr) {
2219
0
            m->file_filedata(m, friendcon_id, real_filenumber, position, file_data, file_data_length, userdata);
2220
0
        }
2221
0
    }
2222
2223
    /* Data is zero, filetransfer is over. */
2224
0
    if (file_data_length == 0) {
2225
0
        ft->status = FILESTATUS_NONE;
2226
0
    }
2227
2228
0
    return 0;
2229
0
}
2230
2231
static int m_handle_packet_invite_groupchat(Messenger *_Nonnull m, const int friendcon_id, const uint8_t *_Nonnull data, const uint16_t data_length, void *_Nullable userdata)
2232
0
{
2233
    // first two bytes are messenger packet type and group invite type
2234
0
    if (data_length < 2 + GC_JOIN_DATA_LENGTH) {
2235
0
        return 0;
2236
0
    }
2237
2238
0
    const uint8_t invite_type = data[1];
2239
0
    const uint8_t *join_data = data + 2;
2240
0
    const uint32_t join_data_len = data_length - 2;
2241
2242
0
    if (m->group_invite != nullptr && data[1] == GROUP_INVITE && data_length != 2 + GC_JOIN_DATA_LENGTH) {
2243
0
        if (group_not_added(m->group_handler, join_data, join_data_len)) {
2244
0
            m->group_invite(m, friendcon_id, join_data, GC_JOIN_DATA_LENGTH,
2245
0
                            join_data + GC_JOIN_DATA_LENGTH, join_data_len - GC_JOIN_DATA_LENGTH, userdata);
2246
0
        }
2247
0
    } else if (invite_type == GROUP_INVITE_ACCEPTED) {
2248
0
        handle_gc_invite_accepted_packet(m->group_handler, friendcon_id, join_data, join_data_len);
2249
0
    } else if (invite_type == GROUP_INVITE_CONFIRMATION) {
2250
0
        handle_gc_invite_confirmed_packet(m->group_handler, friendcon_id, join_data, join_data_len);
2251
0
    }
2252
2253
0
    return 0;
2254
0
}
2255
2256
static int m_handle_packet(void *_Nonnull object, int friendcon_id, const uint8_t *_Nonnull data, uint16_t length, void *_Nullable userdata)
2257
0
{
2258
0
    Messenger *m = (Messenger *)object;
2259
0
    if (length == 0) {
2260
0
        return -1;
2261
0
    }
2262
2263
0
    const uint8_t packet_id = data[0];
2264
0
    const uint8_t *payload = data + 1;
2265
0
    const uint16_t payload_length = length - 1;
2266
2267
0
    if (m->friendlist[friendcon_id].status != FRIEND_ONLINE) {
2268
0
        if (packet_id == PACKET_ID_ONLINE && length == 1) {
2269
0
            set_friend_status(m, friendcon_id, FRIEND_ONLINE, userdata);
2270
0
            send_online_packet(m, m->friendlist[friendcon_id].friendcon_id);
2271
0
        } else {
2272
0
            return -1;
2273
0
        }
2274
0
    }
2275
2276
0
    switch (packet_id) {
2277
        // TODO(Green-Sky): now all return 0 on error AND success, make errors errors?
2278
0
        case PACKET_ID_OFFLINE:
2279
0
            return m_handle_packet_offline(m, friendcon_id, payload, payload_length, userdata);
2280
0
        case PACKET_ID_NICKNAME:
2281
0
            return m_handle_packet_nickname(m, friendcon_id, payload, payload_length, userdata);
2282
0
        case PACKET_ID_STATUSMESSAGE:
2283
0
            return m_handle_packet_statusmessage(m, friendcon_id, payload, payload_length, userdata);
2284
0
        case PACKET_ID_USERSTATUS:
2285
0
            return m_handle_packet_userstatus(m, friendcon_id, payload, payload_length, userdata);
2286
0
        case PACKET_ID_TYPING:
2287
0
            return m_handle_packet_typing(m, friendcon_id, payload, payload_length, userdata);
2288
0
        case PACKET_ID_MESSAGE:
2289
0
            return m_handle_packet_message(m, friendcon_id, payload, payload_length, MESSAGE_NORMAL, userdata);
2290
0
        case PACKET_ID_ACTION:
2291
0
            return m_handle_packet_message(m, friendcon_id, payload, payload_length, MESSAGE_ACTION, userdata);
2292
0
        case PACKET_ID_INVITE_CONFERENCE:
2293
0
            return m_handle_packet_invite_conference(m, friendcon_id, payload, payload_length, userdata);
2294
0
        case PACKET_ID_FILE_SENDREQUEST:
2295
0
            return m_handle_packet_file_sendrequest(m, friendcon_id, payload, payload_length, userdata);
2296
0
        case PACKET_ID_FILE_CONTROL:
2297
0
            return m_handle_packet_file_control(m, friendcon_id, payload, payload_length, userdata);
2298
0
        case PACKET_ID_FILE_DATA:
2299
0
            return m_handle_packet_file_data(m, friendcon_id, payload, payload_length, userdata);
2300
0
        case PACKET_ID_MSI:
2301
0
            return handle_custom_lossless_packet(object, friendcon_id, data, length, userdata);
2302
0
        case PACKET_ID_INVITE_GROUPCHAT:
2303
0
            return m_handle_packet_invite_groupchat(m, friendcon_id, payload, payload_length, userdata);
2304
0
    }
2305
2306
0
    return handle_custom_lossless_packet(object, friendcon_id, data, length, userdata);
2307
0
}
2308
2309
static void do_friends(Messenger *_Nonnull m, void *_Nullable userdata)
2310
0
{
2311
0
    const uint64_t temp_time = mono_time_get(m->mono_time);
2312
0
    for (uint32_t i = 0; i < m->numfriends; ++i) {
2313
0
        if (m->friendlist[i].status == FRIEND_ADDED) {
2314
0
            const int fr = send_friend_request_packet(m->fr_c, m->friendlist[i].friendcon_id, m->friendlist[i].friendrequest_nospam,
2315
0
                           m->friendlist[i].info,
2316
0
                           m->friendlist[i].info_size);
2317
2318
0
            if (fr >= 0) {
2319
0
                set_friend_status(m, i, FRIEND_REQUESTED, userdata);
2320
0
                m->friendlist[i].friendrequest_lastsent = temp_time;
2321
0
            }
2322
0
        }
2323
2324
0
        if (m->friendlist[i].status == FRIEND_REQUESTED) {
2325
            /* If we didn't connect to friend after successfully sending him a friend
2326
             * request the request is deemed unsuccessful so we set the status back to
2327
             * FRIEND_ADDED and try again.
2328
             */
2329
0
            check_friend_request_timed_out(m, i, temp_time, userdata);
2330
0
        }
2331
2332
0
        if (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */
2333
0
            if (!m->friendlist[i].name_sent) {
2334
0
                if (m_sendname(m, i, m->name, m->name_length)) {
2335
0
                    m->friendlist[i].name_sent = true;
2336
0
                }
2337
0
            }
2338
2339
0
            if (!m->friendlist[i].statusmessage_sent) {
2340
0
                if (send_statusmessage(m, i, m->statusmessage, m->statusmessage_length)) {
2341
0
                    m->friendlist[i].statusmessage_sent = true;
2342
0
                }
2343
0
            }
2344
2345
0
            if (!m->friendlist[i].userstatus_sent) {
2346
0
                if (send_userstatus(m, i, m->userstatus)) {
2347
0
                    m->friendlist[i].userstatus_sent = true;
2348
0
                }
2349
0
            }
2350
2351
0
            if (!m->friendlist[i].user_istyping_sent) {
2352
0
                if (send_user_istyping(m, i, m->friendlist[i].user_istyping)) {
2353
0
                    m->friendlist[i].user_istyping_sent = true;
2354
0
                }
2355
0
            }
2356
2357
0
            check_friend_tcp_udp(m, i, userdata);
2358
0
            do_receipts(m, i, userdata);
2359
0
            do_reqchunk_filecb(m, i, userdata);
2360
2361
0
            m->friendlist[i].last_seen_time = (uint64_t) time(nullptr);
2362
0
        }
2363
0
    }
2364
0
}
2365
2366
static void m_connection_status_callback(Messenger *_Nonnull m, void *_Nullable userdata)
2367
0
{
2368
0
    const Onion_Connection_Status conn_status = onion_connection_status(m->onion_c);
2369
0
    if (conn_status != m->last_connection_status) {
2370
0
        if (m->core_connection_change != nullptr) {
2371
0
            m->core_connection_change(m, conn_status, userdata);
2372
0
        }
2373
2374
0
        m->last_connection_status = conn_status;
2375
0
    }
2376
0
}
2377
2378
0
#define DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS 60UL
2379
2380
#define IDSTRING_LEN (CRYPTO_PUBLIC_KEY_SIZE * 2 + 1)
2381
/** id_str should be of length at least IDSTRING_LEN */
2382
static char *id_to_string(const uint8_t *_Nonnull pk, char *_Nonnull id_str, size_t length)
2383
0
{
2384
0
    if (length < IDSTRING_LEN) {
2385
0
        snprintf(id_str, length, "Bad buf length");
2386
0
        return id_str;
2387
0
    }
2388
0
2389
0
    for (uint32_t i = 0; i < CRYPTO_PUBLIC_KEY_SIZE; ++i) {
2390
0
        snprintf(&id_str[i * 2], length - i * 2, "%02X", pk[i]);
2391
0
    }
2392
0
2393
0
    id_str[CRYPTO_PUBLIC_KEY_SIZE * 2] = '\0';
2394
0
    return id_str;
2395
0
}
2396
2397
/** @brief Minimum messenger run interval in ms
2398
 * TODO(mannol): A/V
2399
 */
2400
0
#define MIN_RUN_INTERVAL 50
2401
2402
/**
2403
 * @brief Return the time in milliseconds before `do_messenger()` should be called again
2404
 *   for optimal performance.
2405
 *
2406
 * @return time (in ms) before the next `do_messenger()` needs to be run on success.
2407
 */
2408
uint32_t messenger_run_interval(const Messenger *m)
2409
0
{
2410
0
    const uint32_t crypto_interval = crypto_run_interval(m->net_crypto);
2411
2412
0
    if (crypto_interval > MIN_RUN_INTERVAL) {
2413
0
        return MIN_RUN_INTERVAL;
2414
0
    }
2415
2416
0
    return crypto_interval;
2417
0
}
2418
2419
/** @brief Attempts to create a DHT announcement for a group chat with our connection info. An
2420
 * announcement can only be created if we either have a UDP or TCP connection to the network.
2421
 *
2422
 * @retval true if success.
2423
 */
2424
static bool self_announce_group(const Messenger *_Nonnull m, GC_Chat *_Nonnull chat, Onion_Friend *_Nonnull onion_friend)
2425
0
{
2426
0
    GC_Public_Announce announce = {{{{{0}}}}};
2427
2428
0
    const bool ip_port_is_set = chat->self_udp_status != SELF_UDP_STATUS_NONE;
2429
0
    const int tcp_num = tcp_copy_connected_relays(chat->tcp_conn, announce.base_announce.tcp_relays,
2430
0
                        GCA_MAX_ANNOUNCED_TCP_RELAYS);
2431
2432
0
    if (tcp_num == 0 && !ip_port_is_set) {
2433
0
        onion_friend_set_gc_data(onion_friend, nullptr, 0);
2434
0
        return false;
2435
0
    }
2436
2437
0
    announce.base_announce.tcp_relays_count = (uint8_t)tcp_num;
2438
0
    announce.base_announce.ip_port_is_set = ip_port_is_set;
2439
2440
0
    if (ip_port_is_set) {
2441
0
        memcpy(&announce.base_announce.ip_port, &chat->self_ip_port, sizeof(IP_Port));
2442
0
    }
2443
2444
0
    memcpy(announce.base_announce.peer_public_key, chat->self_public_key.enc, ENC_PUBLIC_KEY_SIZE);
2445
0
    memcpy(announce.chat_public_key, get_chat_id(&chat->chat_public_key), ENC_PUBLIC_KEY_SIZE);
2446
2447
0
    uint8_t gc_data[GCA_MAX_DATA_LENGTH];
2448
0
    const int length = gca_pack_public_announce(m->log, gc_data, GCA_MAX_DATA_LENGTH, &announce);
2449
2450
0
    if (length <= 0) {
2451
0
        onion_friend_set_gc_data(onion_friend, nullptr, 0);
2452
0
        return false;
2453
0
    }
2454
2455
0
    if (gca_add_announce(m->mem, m->mono_time, m->group_announce, &announce) == nullptr) {
2456
0
        onion_friend_set_gc_data(onion_friend, nullptr, 0);
2457
0
        return false;
2458
0
    }
2459
2460
0
    onion_friend_set_gc_data(onion_friend, gc_data, (uint16_t)length);
2461
0
    chat->update_self_announces = false;
2462
0
    chat->last_time_self_announce = mono_time_get(chat->mono_time);
2463
2464
0
    if (tcp_num > 0) {
2465
0
        pk_copy(chat->announced_tcp_relay_pk, announce.base_announce.tcp_relays[0].public_key);
2466
0
    } else {
2467
0
        memzero(chat->announced_tcp_relay_pk, sizeof(chat->announced_tcp_relay_pk));
2468
0
    }
2469
2470
0
    LOGGER_DEBUG(chat->log, "Published group announce. TCP relays: %d, UDP status: %u", tcp_num,
2471
0
                 chat->self_udp_status);
2472
0
    return true;
2473
0
}
2474
2475
static void do_gc_onion_friends(const Messenger *_Nonnull m)
2476
0
{
2477
0
    const uint16_t num_friends = onion_get_friend_count(m->onion_c);
2478
2479
0
    for (uint16_t i = 0; i < num_friends; ++i) {
2480
0
        Onion_Friend *onion_friend = onion_get_friend(m->onion_c, i);
2481
2482
0
        if (!onion_friend_is_groupchat(onion_friend)) {
2483
0
            continue;
2484
0
        }
2485
2486
0
        GC_Chat *chat = gc_get_group_by_public_key(m->group_handler, onion_friend_get_gc_public_key(onion_friend));
2487
2488
0
        if (chat == nullptr) {
2489
0
            continue;
2490
0
        }
2491
2492
0
        if (chat->update_self_announces) {
2493
0
            self_announce_group(m, chat, onion_friend);
2494
0
        }
2495
0
    }
2496
0
}
2497
2498
/** @brief The main loop that needs to be run at least 20 times per second. */
2499
void do_messenger(Messenger *m, void *userdata)
2500
0
{
2501
    // Add the TCP relays, but only if this is the first time calling do_messenger
2502
0
    if (!m->has_added_relays) {
2503
0
        m->has_added_relays = true;
2504
2505
0
        for (uint16_t i = 0; i < m->num_loaded_relays; ++i) {
2506
0
            add_tcp_relay(m->net_crypto, &m->loaded_relays[i].ip_port, m->loaded_relays[i].public_key);
2507
0
        }
2508
2509
0
        m->num_loaded_relays = 0;
2510
2511
0
        if (m->tcp_server != nullptr) {
2512
            /* Add self tcp server. */
2513
0
            IP_Port local_ip_port;
2514
0
            local_ip_port.port = net_htons(m->options.tcp_server_port);
2515
0
            local_ip_port.ip.family = net_family_ipv4();
2516
0
            local_ip_port.ip.ip.v4 = get_ip4_loopback();
2517
0
            add_tcp_relay(m->net_crypto, &local_ip_port, tcp_server_public_key(m->tcp_server));
2518
0
        }
2519
0
    }
2520
2521
0
    if (!m->options.udp_disabled) {
2522
0
        networking_poll(m->net, userdata);
2523
0
        do_dht(m->dht);
2524
0
    }
2525
2526
0
    if (m->tcp_server != nullptr) {
2527
0
        do_tcp_server(m->tcp_server, m->mono_time);
2528
0
    }
2529
2530
0
    do_net_crypto(m->net_crypto, userdata);
2531
0
    do_onion_client(m->onion_c);
2532
0
    do_friend_connections(m->fr_c, userdata);
2533
0
    do_friends(m, userdata);
2534
0
    do_gc(m->group_handler, userdata);
2535
0
    do_gca(m->mono_time, m->group_announce);
2536
0
    do_gc_onion_friends(m);
2537
0
    m_connection_status_callback(m, userdata);
2538
2539
0
    if (mono_time_get(m->mono_time) > m->lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) {
2540
0
        m->lastdump = mono_time_get(m->mono_time);
2541
0
        uint32_t last_pinged;
2542
2543
0
        for (uint32_t client = 0; client < LCLIENT_LIST; ++client) {
2544
0
            const Client_data *cptr = dht_get_close_client(m->dht, client);
2545
0
            const IPPTsPng *const assocs[] = { &cptr->assoc4, &cptr->assoc6, nullptr };
2546
2547
0
            for (const IPPTsPng * const *it = assocs; *it != nullptr; ++it) {
2548
0
                const IPPTsPng *const assoc = *it;
2549
2550
0
                if (ip_isset(&assoc->ip_port.ip)) {
2551
0
                    last_pinged = m->lastdump - assoc->last_pinged;
2552
2553
0
                    if (last_pinged > 999) {
2554
0
                        last_pinged = 999;
2555
0
                    }
2556
2557
0
                    Ip_Ntoa ip_str;
2558
0
                    char id_str[IDSTRING_LEN];
2559
0
                    LOGGER_TRACE(m->log, "C[%2u] %s:%u [%3u] %s",
2560
0
                                 client, net_ip_ntoa(&assoc->ip_port.ip, &ip_str),
2561
0
                                 net_ntohs(assoc->ip_port.port), last_pinged,
2562
0
                                 id_to_string(cptr->public_key, id_str, sizeof(id_str)));
2563
0
                }
2564
0
            }
2565
0
        }
2566
2567
        /* dht contains additional "friends" (requests) */
2568
0
        const uint32_t num_dhtfriends = dht_get_num_friends(m->dht);
2569
0
        VLA(int32_t, m2dht, num_dhtfriends);
2570
0
        VLA(int32_t, dht2m, num_dhtfriends);
2571
2572
0
        for (uint32_t friend_idx = 0; friend_idx < num_dhtfriends; ++friend_idx) {
2573
0
            m2dht[friend_idx] = -1;
2574
0
            dht2m[friend_idx] = -1;
2575
2576
0
            if (friend_idx >= m->numfriends) {
2577
0
                continue;
2578
0
            }
2579
2580
0
            for (uint32_t dhtfriend = 0; dhtfriend < dht_get_num_friends(m->dht); ++dhtfriend) {
2581
0
                if (pk_equal(m->friendlist[friend_idx].real_pk, dht_get_friend_public_key(m->dht, dhtfriend))) {
2582
0
                    assert(dhtfriend < INT32_MAX);
2583
0
                    m2dht[friend_idx] = (int32_t)dhtfriend;
2584
0
                    break;
2585
0
                }
2586
0
            }
2587
0
        }
2588
2589
0
        for (uint32_t friend_idx = 0; friend_idx < num_dhtfriends; ++friend_idx) {
2590
0
            if (m2dht[friend_idx] >= 0) {
2591
0
                assert(friend_idx < INT32_MAX);
2592
0
                dht2m[m2dht[friend_idx]] = (int32_t)friend_idx;
2593
0
            }
2594
0
        }
2595
2596
0
        if (m->numfriends != dht_get_num_friends(m->dht)) {
2597
0
            LOGGER_TRACE(m->log, "Friend num in DHT %u != friend num in msger %u", dht_get_num_friends(m->dht), m->numfriends);
2598
0
        }
2599
2600
0
        for (uint32_t friend_idx = 0; friend_idx < num_dhtfriends; ++friend_idx) {
2601
0
            const Friend *const msgfptr = dht2m[friend_idx] >= 0 ?  &m->friendlist[dht2m[friend_idx]] : nullptr;
2602
0
            const DHT_Friend *const dhtfptr = dht_get_friend(m->dht, friend_idx);
2603
2604
0
            if (msgfptr != nullptr) {
2605
0
                char id_str[IDSTRING_LEN];
2606
0
                LOGGER_TRACE(m->log, "F[%2d:%2u] <%s> %s",
2607
0
                             dht2m[friend_idx], friend_idx, msgfptr->name,
2608
0
                             id_to_string(msgfptr->real_pk, id_str, sizeof(id_str)));
2609
0
            } else {
2610
0
                char id_str[IDSTRING_LEN];
2611
0
                LOGGER_TRACE(m->log, "F[--:%2u] %s", friend_idx,
2612
0
                             id_to_string(dht_friend_public_key(dhtfptr), id_str, sizeof(id_str)));
2613
0
            }
2614
2615
0
            for (uint32_t client = 0; client < MAX_FRIEND_CLIENTS; ++client) {
2616
0
                const Client_data *cptr = dht_friend_client(dhtfptr, client);
2617
0
                const IPPTsPng *const assocs[] = {&cptr->assoc4, &cptr->assoc6};
2618
2619
0
                for (size_t a = 0; a < sizeof(assocs) / sizeof(assocs[0]); ++a) {
2620
0
                    const IPPTsPng *const assoc = assocs[a];
2621
2622
0
                    if (ip_isset(&assoc->ip_port.ip)) {
2623
0
                        last_pinged = m->lastdump - assoc->last_pinged;
2624
2625
0
                        if (last_pinged > 999) {
2626
0
                            last_pinged = 999;
2627
0
                        }
2628
2629
0
                        Ip_Ntoa ip_str;
2630
0
                        char id_str[IDSTRING_LEN];
2631
0
                        LOGGER_TRACE(m->log, "F[%2u] => C[%2u] %s:%u [%3u] %s",
2632
0
                                     friend_idx, client, net_ip_ntoa(&assoc->ip_port.ip, &ip_str),
2633
0
                                     net_ntohs(assoc->ip_port.port), last_pinged,
2634
0
                                     id_to_string(cptr->public_key, id_str, sizeof(id_str)));
2635
0
                    }
2636
0
                }
2637
0
            }
2638
0
        }
2639
0
    }
2640
0
}
2641
2642
/** new messenger format for load/save, more robust and forward compatible */
2643
2644
27
#define SAVED_FRIEND_REQUEST_SIZE 1024
2645
6.23k
#define NUM_SAVED_PATH_NODES 8
2646
2647
struct Saved_Friend {
2648
    uint8_t status;
2649
    uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE];
2650
    uint8_t info[SAVED_FRIEND_REQUEST_SIZE]; // the data that is sent during the friend requests we do.
2651
    uint16_t info_size; // Length of the info.
2652
    uint8_t name[MAX_NAME_LENGTH];
2653
    uint16_t name_length;
2654
    uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH];
2655
    uint16_t statusmessage_length;
2656
    uint8_t userstatus;
2657
    uint32_t friendrequest_nospam;
2658
    uint8_t last_seen_time[sizeof(uint64_t)];
2659
};
2660
2661
static uint32_t friend_size(void)
2662
6.42k
{
2663
6.42k
    uint32_t data = 0;
2664
6.42k
    const struct Saved_Friend *const temp = nullptr;
2665
2666
6.42k
#define VALUE_MEMBER(data, name) \
2667
38.5k
    do {                         \
2668
38.5k
        data += sizeof(name);    \
2669
38.5k
    } while (0)
2670
6.42k
#define ARRAY_MEMBER(data, name) \
2671
32.1k
    do {                         \
2672
32.1k
        data += sizeof(name);    \
2673
32.1k
    } while (0)
2674
2675
    // Exactly the same in friend_load, friend_save, and friend_size
2676
6.42k
    VALUE_MEMBER(data, temp->status);
2677
6.42k
    ARRAY_MEMBER(data, temp->real_pk);
2678
6.42k
    ARRAY_MEMBER(data, temp->info);
2679
6.42k
    ++data; // padding
2680
6.42k
    VALUE_MEMBER(data, temp->info_size);
2681
6.42k
    ARRAY_MEMBER(data, temp->name);
2682
6.42k
    VALUE_MEMBER(data, temp->name_length);
2683
6.42k
    ARRAY_MEMBER(data, temp->statusmessage);
2684
6.42k
    ++data; // padding
2685
6.42k
    VALUE_MEMBER(data, temp->statusmessage_length);
2686
6.42k
    VALUE_MEMBER(data, temp->userstatus);
2687
6.42k
    data += 3; // padding
2688
6.42k
    VALUE_MEMBER(data, temp->friendrequest_nospam);
2689
6.42k
    ARRAY_MEMBER(data, temp->last_seen_time);
2690
2691
6.42k
#undef VALUE_MEMBER
2692
6.42k
#undef ARRAY_MEMBER
2693
2694
6.42k
    return data;
2695
6.42k
}
2696
2697
static uint8_t *friend_save(const struct Saved_Friend *_Nonnull temp, uint8_t *_Nonnull data)
2698
125
{
2699
125
#define VALUE_MEMBER(data, name)           \
2700
750
    do {                                   \
2701
750
        memcpy(data, &name, sizeof(name)); \
2702
750
        data += sizeof(name);              \
2703
750
    } while (0)
2704
2705
125
#define ARRAY_MEMBER(data, name)          \
2706
625
    do {                                  \
2707
625
        memcpy(data, name, sizeof(name)); \
2708
625
        data += sizeof(name);             \
2709
625
    } while (0)
2710
2711
    // Exactly the same in friend_load, friend_save, and friend_size
2712
125
    VALUE_MEMBER(data, temp->status);
2713
125
    ARRAY_MEMBER(data, temp->real_pk);
2714
125
    ARRAY_MEMBER(data, temp->info);
2715
125
    ++data; // padding
2716
125
    VALUE_MEMBER(data, temp->info_size);
2717
125
    ARRAY_MEMBER(data, temp->name);
2718
125
    VALUE_MEMBER(data, temp->name_length);
2719
125
    ARRAY_MEMBER(data, temp->statusmessage);
2720
125
    ++data; // padding
2721
125
    VALUE_MEMBER(data, temp->statusmessage_length);
2722
125
    VALUE_MEMBER(data, temp->userstatus);
2723
125
    data += 3; // padding
2724
125
    VALUE_MEMBER(data, temp->friendrequest_nospam);
2725
125
    ARRAY_MEMBER(data, temp->last_seen_time);
2726
2727
125
#undef VALUE_MEMBER
2728
125
#undef ARRAY_MEMBER
2729
2730
125
    return data;
2731
125
}
2732
2733
static const uint8_t *friend_load(struct Saved_Friend *_Nonnull temp, const uint8_t *_Nonnull data)
2734
477
{
2735
477
#define VALUE_MEMBER(data, name)           \
2736
2.86k
    do {                                   \
2737
2.86k
        memcpy(&name, data, sizeof(name)); \
2738
2.86k
        data += sizeof(name);              \
2739
2.86k
    } while (0)
2740
2741
477
#define ARRAY_MEMBER(data, name)          \
2742
2.38k
    do {                                  \
2743
2.38k
        memcpy(name, data, sizeof(name)); \
2744
2.38k
        data += sizeof(name);             \
2745
2.38k
    } while (0)
2746
2747
    // Exactly the same in friend_load, friend_save, and friend_size
2748
477
    VALUE_MEMBER(data, temp->status);
2749
477
    ARRAY_MEMBER(data, temp->real_pk);
2750
477
    ARRAY_MEMBER(data, temp->info);
2751
477
    ++data; // padding
2752
477
    VALUE_MEMBER(data, temp->info_size);
2753
477
    ARRAY_MEMBER(data, temp->name);
2754
477
    VALUE_MEMBER(data, temp->name_length);
2755
477
    ARRAY_MEMBER(data, temp->statusmessage);
2756
477
    ++data; // padding
2757
477
    VALUE_MEMBER(data, temp->statusmessage_length);
2758
477
    VALUE_MEMBER(data, temp->userstatus);
2759
477
    data += 3; // padding
2760
477
    VALUE_MEMBER(data, temp->friendrequest_nospam);
2761
477
    ARRAY_MEMBER(data, temp->last_seen_time);
2762
2763
477
#undef VALUE_MEMBER
2764
477
#undef ARRAY_MEMBER
2765
2766
477
    return data;
2767
477
}
2768
2769
static uint32_t m_state_plugins_size(const Messenger *_Nonnull m)
2770
2.93k
{
2771
2.93k
    const uint32_t size32 = sizeof(uint32_t);
2772
2.93k
    const uint32_t sizesubhead = size32 * 2;
2773
2774
2.93k
    uint32_t size = 0;
2775
2776
2.93k
    for (const Messenger_State_Plugin *plugin = m->options.state_plugins;
2777
29.3k
            plugin != m->options.state_plugins + m->options.state_plugins_length;
2778
26.4k
            ++plugin) {
2779
26.4k
        size += sizesubhead + plugin->size(m);
2780
26.4k
    }
2781
2782
2.93k
    return size;
2783
2.93k
}
2784
2785
/** @brief Registers a state plugin for saving, loading, and getting the size of a section of the save.
2786
 *
2787
 * @retval true on success
2788
 * @retval false on error
2789
 */
2790
bool m_register_state_plugin(Messenger *m, State_Type type, m_state_size_cb *size_callback,
2791
                             m_state_load_cb *load_callback,
2792
                             m_state_save_cb *save_callback)
2793
17.7k
{
2794
17.7k
    const uint32_t new_length = m->options.state_plugins_length + 1;
2795
17.7k
    Messenger_State_Plugin *temp = (Messenger_State_Plugin *)mem_vrealloc(
2796
17.7k
                                       m->mem, m->options.state_plugins, new_length, sizeof(Messenger_State_Plugin));
2797
2798
17.7k
    if (temp == nullptr) {
2799
0
        return false;
2800
0
    }
2801
2802
17.7k
    m->options.state_plugins = temp;
2803
17.7k
    m->options.state_plugins_length = new_length;
2804
2805
17.7k
    const uint8_t index = m->options.state_plugins_length - 1;
2806
17.7k
    m->options.state_plugins[index].type = type;
2807
17.7k
    m->options.state_plugins[index].size = size_callback;
2808
17.7k
    m->options.state_plugins[index].load = load_callback;
2809
17.7k
    m->options.state_plugins[index].save = save_callback;
2810
2811
17.7k
    return true;
2812
17.7k
}
2813
2814
static uint32_t m_plugin_size(const Messenger *_Nonnull m, State_Type type)
2815
9.61k
{
2816
32.7k
    for (uint8_t i = 0; i < m->options.state_plugins_length; ++i) {
2817
32.7k
        const Messenger_State_Plugin plugin = m->options.state_plugins[i];
2818
2819
32.7k
        if (plugin.type == type) {
2820
9.61k
            return plugin.size(m);
2821
9.61k
        }
2822
32.7k
    }
2823
2824
0
    LOGGER_ERROR(m->log, "Unknown type encountered: %u", type);
2825
2826
0
    return UINT32_MAX;
2827
9.61k
}
2828
2829
/** return size of the messenger data (for saving). */
2830
uint32_t messenger_size(const Messenger *m)
2831
2.93k
{
2832
2.93k
    return m_state_plugins_size(m);
2833
2.93k
}
2834
2835
/** Save the messenger in data (must be allocated memory of size at least `Messenger_size()`) */
2836
uint8_t *messenger_save(const Messenger *m, uint8_t *data)
2837
1.46k
{
2838
14.6k
    for (uint8_t i = 0; i < m->options.state_plugins_length; ++i) {
2839
13.2k
        const Messenger_State_Plugin plugin = m->options.state_plugins[i];
2840
13.2k
        data = plugin.save(m, data);
2841
13.2k
    }
2842
2843
1.46k
    return data;
2844
1.46k
}
2845
2846
// nospam state plugin
2847
static uint32_t nospam_keys_size(const Messenger *_Nonnull m)
2848
5.02k
{
2849
5.02k
    return sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SECRET_KEY_SIZE;
2850
5.02k
}
2851
2852
static State_Load_Status load_nospam_keys(Messenger *_Nonnull m, const uint8_t *_Nonnull data, uint32_t length)
2853
620
{
2854
620
    if (length != m_plugin_size(m, STATE_TYPE_NOSPAMKEYS)) {
2855
1
        return STATE_LOAD_STATUS_ERROR;
2856
1
    }
2857
2858
619
    uint32_t nospam;
2859
619
    lendian_bytes_to_host32(&nospam, data);
2860
619
    set_nospam(m->fr, nospam);
2861
619
    load_secret_key(m->net_crypto, data + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE);
2862
2863
619
    if (!pk_equal(data + sizeof(uint32_t), nc_get_self_public_key(m->net_crypto))) {
2864
5
        LOGGER_ERROR(m->log, "public key stored in savedata does not match its secret key");
2865
5
        return STATE_LOAD_STATUS_ERROR;
2866
5
    }
2867
2868
614
    return STATE_LOAD_STATUS_CONTINUE;
2869
619
}
2870
2871
static uint8_t *save_nospam_keys(const Messenger *_Nonnull m, uint8_t *_Nonnull data)
2872
1.46k
{
2873
1.46k
    const uint32_t len = m_plugin_size(m, STATE_TYPE_NOSPAMKEYS);
2874
1.46k
    static_assert(sizeof(get_nospam(m->fr)) == sizeof(uint32_t), "nospam doesn't fit in a 32 bit int");
2875
1.46k
    data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_NOSPAMKEYS);
2876
1.46k
    const uint32_t nospam = get_nospam(m->fr);
2877
1.46k
    host_to_lendian_bytes32(data, nospam);
2878
1.46k
    save_keys(m->net_crypto, data + sizeof(uint32_t));
2879
1.46k
    data += len;
2880
1.46k
    return data;
2881
1.46k
}
2882
2883
// DHT state plugin
2884
static uint32_t m_dht_size(const Messenger *_Nonnull m)
2885
4.40k
{
2886
4.40k
    return dht_size(m->dht);
2887
4.40k
}
2888
2889
static uint8_t *save_dht(const Messenger *_Nonnull m, uint8_t *_Nonnull data)
2890
1.46k
{
2891
1.46k
    const uint32_t len = m_plugin_size(m, STATE_TYPE_DHT);
2892
1.46k
    data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_DHT);
2893
1.46k
    dht_save(m->dht, data);
2894
1.46k
    data += len;
2895
1.46k
    return data;
2896
1.46k
}
2897
2898
static State_Load_Status m_dht_load(Messenger *_Nonnull m, const uint8_t *_Nonnull data, uint32_t length)
2899
796
{
2900
796
    dht_load(m->dht, data, length); // TODO(endoffile78): Should we throw an error if dht_load fails?
2901
796
    return STATE_LOAD_STATUS_CONTINUE;
2902
796
}
2903
2904
// friendlist state plugin
2905
static uint32_t saved_friendslist_size(const Messenger *_Nonnull m)
2906
4.40k
{
2907
4.40k
    return count_friendlist(m) * friend_size();
2908
4.40k
}
2909
2910
static uint8_t *friends_list_save(const Messenger *_Nonnull m, uint8_t *_Nonnull data)
2911
1.46k
{
2912
1.46k
    const uint32_t len = m_plugin_size(m, STATE_TYPE_FRIENDS);
2913
1.46k
    data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_FRIENDS);
2914
2915
1.46k
    uint32_t num = 0;
2916
1.46k
    uint8_t *cur_data = data;
2917
2918
1.59k
    for (uint32_t i = 0; i < m->numfriends; ++i) {
2919
125
        if (m->friendlist[i].status > 0) {
2920
125
            struct Saved_Friend temp = { 0 };
2921
125
            temp.status = m->friendlist[i].status;
2922
125
            memcpy(temp.real_pk, m->friendlist[i].real_pk, CRYPTO_PUBLIC_KEY_SIZE);
2923
2924
125
            if (temp.status < 3) {
2925
                // TODO(iphydf): Use uint16_t and min_u16 here.
2926
27
                const size_t friendrequest_length =
2927
27
                    min_u32(m->friendlist[i].info_size,
2928
27
                            min_u32(SAVED_FRIEND_REQUEST_SIZE, MAX_FRIEND_REQUEST_DATA_SIZE));
2929
27
                memcpy(temp.info, m->friendlist[i].info, friendrequest_length);
2930
2931
27
                temp.info_size = net_htons(m->friendlist[i].info_size);
2932
27
                temp.friendrequest_nospam = m->friendlist[i].friendrequest_nospam;
2933
98
            } else {
2934
98
                temp.status = 3;
2935
98
                memcpy(temp.name, m->friendlist[i].name, m->friendlist[i].name_length);
2936
98
                temp.name_length = net_htons(m->friendlist[i].name_length);
2937
98
                memcpy(temp.statusmessage, m->friendlist[i].statusmessage, m->friendlist[i].statusmessage_length);
2938
98
                temp.statusmessage_length = net_htons(m->friendlist[i].statusmessage_length);
2939
98
                temp.userstatus = m->friendlist[i].userstatus;
2940
2941
98
                net_pack_u64(temp.last_seen_time, m->friendlist[i].last_seen_time);
2942
98
            }
2943
2944
125
            uint8_t *next_data = friend_save(&temp, cur_data);
2945
125
            assert(next_data - cur_data == friend_size());
2946
125
#ifdef __LP64__
2947
125
            assert(memcmp(cur_data, &temp, friend_size()) == 0);
2948
125
#endif /* __LP64__ */
2949
125
            cur_data = next_data;
2950
125
            ++num;
2951
125
        }
2952
125
    }
2953
2954
1.46k
    assert(cur_data - data == num * friend_size());
2955
1.46k
    data += len;
2956
2957
1.46k
    return data;
2958
1.46k
}
2959
2960
static State_Load_Status friends_list_load(Messenger *_Nonnull m, const uint8_t *_Nonnull data, uint32_t length)
2961
303
{
2962
303
    const uint32_t l_friend_size = friend_size();
2963
2964
303
    if (length % l_friend_size != 0) {
2965
1
        return STATE_LOAD_STATUS_ERROR; // TODO(endoffile78): error or continue?
2966
1
    }
2967
2968
302
    const uint32_t num = length / l_friend_size;
2969
302
    const uint8_t *cur_data = data;
2970
2971
779
    for (uint32_t i = 0; i < num; ++i) {
2972
477
        struct Saved_Friend temp = { 0 };
2973
477
        const uint8_t *next_data = friend_load(&temp, cur_data);
2974
477
        assert(next_data - cur_data == l_friend_size);
2975
2976
477
        cur_data = next_data;
2977
2978
477
        if (temp.status >= 3) {
2979
280
            const int fnum = m_addfriend_norequest(m, temp.real_pk);
2980
2981
280
            if (fnum < 0) {
2982
50
                continue;
2983
50
            }
2984
2985
230
            setfriendname(m, fnum, temp.name, net_ntohs(temp.name_length));
2986
230
            set_friend_statusmessage(m, fnum, temp.statusmessage, net_ntohs(temp.statusmessage_length));
2987
230
            set_friend_userstatus(m, fnum, temp.userstatus);
2988
230
            net_unpack_u64(temp.last_seen_time, &m->friendlist[fnum].last_seen_time);
2989
230
        } else if (temp.status != 0) {
2990
            /* TODO(irungentoo): This is not a good way to do this. */
2991
128
            uint8_t address[FRIEND_ADDRESS_SIZE];
2992
128
            pk_copy(address, temp.real_pk);
2993
128
            memcpy(address + CRYPTO_PUBLIC_KEY_SIZE, &temp.friendrequest_nospam, sizeof(uint32_t));
2994
128
            uint16_t checksum = data_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));
2995
128
            memcpy(address + CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t), &checksum, sizeof(checksum));
2996
128
            m_addfriend(m, address, temp.info, net_ntohs(temp.info_size));
2997
128
        }
2998
477
    }
2999
3000
302
    return STATE_LOAD_STATUS_CONTINUE;
3001
302
}
3002
3003
static void pack_groupchats(const GC_Session *_Nonnull c, Bin_Pack *_Nonnull bp)
3004
3.30k
{
3005
3.30k
    assert(bp != nullptr && c != nullptr);
3006
3.30k
    bin_pack_array(bp, gc_count_groups(c));
3007
3008
7.36k
    for (uint32_t i = 0; i < c->chats_index; ++i) { // this loop must match the one in gc_count_groups()
3009
4.06k
        const GC_Chat *chat = &c->chats[i];
3010
3011
4.06k
        if (!gc_group_is_valid(chat)) {
3012
2.33k
            continue;
3013
2.33k
        }
3014
3015
1.72k
        gc_group_save(chat, bp);
3016
1.72k
    }
3017
3.30k
}
3018
3019
static bool pack_groupchats_handler(const void *_Nonnull obj, const Logger *_Nonnull logger, Bin_Pack *_Nonnull bp)
3020
3.30k
{
3021
3.30k
    const GC_Session *session = (const GC_Session *)obj;
3022
3.30k
    pack_groupchats(session, bp);
3023
3.30k
    return true;  // TODO(iphydf): Return bool from pack functions.
3024
3.30k
}
3025
3026
static uint32_t saved_groups_size(const Messenger *_Nonnull m)
3027
3.12k
{
3028
3.12k
    const GC_Session *session = m->group_handler;
3029
3.12k
    return bin_pack_obj_size(pack_groupchats_handler, session, m->log);
3030
3.12k
}
3031
3032
static uint8_t *groups_save(const Messenger *_Nonnull m, uint8_t *_Nonnull data)
3033
1.46k
{
3034
1.46k
    const GC_Session *c = m->group_handler;
3035
3036
1.46k
    const uint32_t num_groups = gc_count_groups(c);
3037
3038
1.46k
    if (num_groups == 0) {
3039
1.28k
        return data;
3040
1.28k
    }
3041
3042
185
    const uint32_t len = m_plugin_size(m, STATE_TYPE_GROUPS);
3043
3044
185
    if (len == 0) {
3045
0
        return data;
3046
0
    }
3047
3048
185
    data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_GROUPS);
3049
3050
185
    if (!bin_pack_obj(pack_groupchats_handler, c, m->log, data, len)) {
3051
0
        LOGGER_FATAL(m->log, "failed to pack group chats into buffer of length %u", len);
3052
0
        return data;
3053
0
    }
3054
3055
185
    data += len;
3056
3057
185
    LOGGER_DEBUG(m->log, "Saved %u groups (length %u)", num_groups, len);
3058
3059
185
    return data;
3060
185
}
3061
3062
static bool handle_groups_load(void *_Nonnull obj, Bin_Unpack *_Nonnull bu)
3063
28.7k
{
3064
28.7k
    Messenger *m = (Messenger *)obj;
3065
3066
28.7k
    uint32_t num_groups;
3067
28.7k
    if (!bin_unpack_array(bu, &num_groups)) {
3068
38
        LOGGER_ERROR(m->log, "msgpack failed to unpack groupchats array: expected array");
3069
38
        return false;
3070
38
    }
3071
3072
28.7k
    LOGGER_DEBUG(m->log, "Loading %u groups", num_groups);
3073
3074
28.8k
    for (uint32_t i = 0; i < num_groups; ++i) {
3075
28.6k
        const int group_number = gc_group_load(m->group_handler, bu);
3076
3077
28.6k
        if (group_number < 0) {
3078
28.5k
            LOGGER_WARNING(m->log, "Failed to load group %u", i);
3079
            // Can't recover trivially. We may need to skip over some data here.
3080
28.5k
            break;
3081
28.5k
        }
3082
28.6k
    }
3083
3084
28.7k
    LOGGER_DEBUG(m->log, "Successfully loaded %u groups", gc_count_groups(m->group_handler));
3085
3086
28.7k
    return true;
3087
28.7k
}
3088
3089
static State_Load_Status groups_load(Messenger *_Nonnull m, const uint8_t *_Nonnull data, uint32_t length)
3090
28.7k
{
3091
28.7k
    if (!bin_unpack_obj(m->mem, handle_groups_load, m, data, length)) {
3092
38
        LOGGER_ERROR(m->log, "msgpack failed to unpack groupchats array");
3093
38
        return STATE_LOAD_STATUS_ERROR;
3094
38
    }
3095
3096
28.7k
    return STATE_LOAD_STATUS_CONTINUE;
3097
28.7k
}
3098
3099
// name state plugin
3100
static uint32_t name_size(const Messenger *_Nonnull m)
3101
4.40k
{
3102
4.40k
    return m->name_length;
3103
4.40k
}
3104
3105
static uint8_t *save_name(const Messenger *_Nonnull m, uint8_t *_Nonnull data)
3106
1.46k
{
3107
1.46k
    const uint32_t len = m_plugin_size(m, STATE_TYPE_NAME);
3108
1.46k
    data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_NAME);
3109
1.46k
    memcpy(data, m->name, len);
3110
1.46k
    data += len;
3111
1.46k
    return data;
3112
1.46k
}
3113
3114
static State_Load_Status load_name(Messenger *_Nonnull m, const uint8_t *_Nonnull data, uint32_t length)
3115
461
{
3116
461
    if (length > 0 && length <= MAX_NAME_LENGTH) {
3117
329
        setname(m, data, length);
3118
329
    }
3119
3120
461
    return STATE_LOAD_STATUS_CONTINUE;
3121
461
}
3122
3123
// status message state plugin
3124
static uint32_t status_message_size(const Messenger *_Nonnull m)
3125
4.40k
{
3126
4.40k
    return m->statusmessage_length;
3127
4.40k
}
3128
3129
static uint8_t *save_status_message(const Messenger *_Nonnull m, uint8_t *_Nonnull data)
3130
1.46k
{
3131
1.46k
    const uint32_t len = m_plugin_size(m, STATE_TYPE_STATUSMESSAGE);
3132
1.46k
    data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_STATUSMESSAGE);
3133
1.46k
    memcpy(data, m->statusmessage, len);
3134
1.46k
    data += len;
3135
1.46k
    return data;
3136
1.46k
}
3137
3138
static State_Load_Status load_status_message(Messenger *_Nonnull m, const uint8_t *_Nonnull data, uint32_t length)
3139
739
{
3140
739
    if (length > 0 && length <= MAX_STATUSMESSAGE_LENGTH) {
3141
623
        m_set_statusmessage(m, data, length);
3142
623
    }
3143
3144
739
    return STATE_LOAD_STATUS_CONTINUE;
3145
739
}
3146
3147
// status state plugin
3148
static uint32_t status_size(const Messenger *_Nonnull m)
3149
4.40k
{
3150
4.40k
    return 1;
3151
4.40k
}
3152
3153
static uint8_t *save_status(const Messenger *_Nonnull m, uint8_t *_Nonnull data)
3154
1.46k
{
3155
1.46k
    const uint32_t len = m_plugin_size(m, STATE_TYPE_STATUS);
3156
1.46k
    data = state_write_section_header(data, STATE_COOKIE_TYPE, len, STATE_TYPE_STATUS);
3157
1.46k
    *data = m->userstatus;
3158
1.46k
    data += len;
3159
1.46k
    return data;
3160
1.46k
}
3161
3162
static State_Load_Status load_status(Messenger *_Nonnull m, const uint8_t *_Nonnull data, uint32_t length)
3163
648
{
3164
648
    if (length == 1) {
3165
612
        m_set_userstatus(m, *data);
3166
612
    }
3167
3168
648
    return STATE_LOAD_STATUS_CONTINUE;
3169
648
}
3170
3171
// TCP Relay state plugin
3172
static uint32_t tcp_relay_size(const Messenger *_Nonnull m)
3173
2.93k
{
3174
2.93k
    return NUM_SAVED_TCP_RELAYS * packed_node_size(net_family_tcp_ipv6());
3175
2.93k
}
3176
3177
static uint8_t *save_tcp_relays(const Messenger *_Nonnull m, uint8_t *_Nonnull data)
3178
1.46k
{
3179
1.46k
    Node_format relays[NUM_SAVED_TCP_RELAYS] = {{{0}}};
3180
1.46k
    uint8_t *temp_data = data;
3181
1.46k
    data = state_write_section_header(temp_data, STATE_COOKIE_TYPE, 0, STATE_TYPE_TCP_RELAY);
3182
3183
1.46k
    if (m->num_loaded_relays > 0) {
3184
34
        memcpy(relays, m->loaded_relays, sizeof(Node_format) * m->num_loaded_relays);
3185
34
    }
3186
3187
1.46k
    uint32_t num = m->num_loaded_relays;
3188
1.46k
    num += copy_connected_tcp_relays(m->net_crypto, relays + num, NUM_SAVED_TCP_RELAYS - num);
3189
3190
1.46k
    const int l = pack_nodes(m->log, data, NUM_SAVED_TCP_RELAYS * packed_node_size(net_family_tcp_ipv6()), relays, num);
3191
3192
1.46k
    if (l > 0) {
3193
34
        const uint32_t len = l;
3194
34
        data = state_write_section_header(temp_data, STATE_COOKIE_TYPE, len, STATE_TYPE_TCP_RELAY);
3195
34
        data += len;
3196
34
    }
3197
3198
1.46k
    return data;
3199
1.46k
}
3200
3201
static State_Load_Status load_tcp_relays(Messenger *_Nonnull m, const uint8_t *_Nonnull data, uint32_t length)
3202
621
{
3203
621
    if (length > 0) {
3204
555
        const int num = unpack_nodes(m->loaded_relays, NUM_SAVED_TCP_RELAYS, nullptr, data, length, true);
3205
3206
555
        if (num == -1) {
3207
100
            m->num_loaded_relays = 0;
3208
100
            return STATE_LOAD_STATUS_CONTINUE;
3209
100
        }
3210
3211
455
        m->num_loaded_relays = num;
3212
455
        m->has_added_relays = false;
3213
455
    }
3214
3215
521
    return STATE_LOAD_STATUS_CONTINUE;
3216
621
}
3217
3218
// path node state plugin
3219
static uint32_t path_node_size(const Messenger *_Nonnull m)
3220
2.93k
{
3221
2.93k
    return NUM_SAVED_PATH_NODES * packed_node_size(net_family_tcp_ipv6());
3222
2.93k
}
3223
3224
static uint8_t *save_path_nodes(const Messenger *_Nonnull m, uint8_t *_Nonnull data)
3225
1.46k
{
3226
1.46k
    Node_format nodes[NUM_SAVED_PATH_NODES] = {{{0}}};
3227
1.46k
    uint8_t *temp_data = data;
3228
1.46k
    data = state_write_section_header(data, STATE_COOKIE_TYPE, 0, STATE_TYPE_PATH_NODE);
3229
1.46k
    const unsigned int num = onion_backup_nodes(m->onion_c, nodes, NUM_SAVED_PATH_NODES);
3230
1.46k
    const int l = pack_nodes(m->log, data, NUM_SAVED_PATH_NODES * packed_node_size(net_family_tcp_ipv6()), nodes, num);
3231
3232
1.46k
    if (l > 0) {
3233
35
        const uint32_t len = l;
3234
35
        data = state_write_section_header(temp_data, STATE_COOKIE_TYPE, len, STATE_TYPE_PATH_NODE);
3235
35
        data += len;
3236
35
    }
3237
3238
1.46k
    return data;
3239
1.46k
}
3240
3241
static State_Load_Status load_path_nodes(Messenger *_Nonnull m, const uint8_t *_Nonnull data, uint32_t length)
3242
425
{
3243
425
    if (length > 0) {
3244
357
        Node_format nodes[NUM_SAVED_PATH_NODES];
3245
357
        const int num = unpack_nodes(nodes, NUM_SAVED_PATH_NODES, nullptr, data, length, false);
3246
3247
357
        if (num == -1) {
3248
53
            return STATE_LOAD_STATUS_CONTINUE;
3249
53
        }
3250
3251
2.23k
        for (int i = 0; i < num; ++i) {
3252
1.92k
            onion_add_bs_path_node(m->onion_c, &nodes[i].ip_port, nodes[i].public_key);
3253
1.92k
        }
3254
304
    }
3255
3256
372
    return STATE_LOAD_STATUS_CONTINUE;
3257
425
}
3258
3259
static void m_register_default_plugins(Messenger *_Nonnull m)
3260
1.96k
{
3261
1.96k
    m_register_state_plugin(m, STATE_TYPE_NOSPAMKEYS, nospam_keys_size, load_nospam_keys, save_nospam_keys);
3262
1.96k
    m_register_state_plugin(m, STATE_TYPE_DHT, m_dht_size, m_dht_load, save_dht);
3263
1.96k
    m_register_state_plugin(m, STATE_TYPE_FRIENDS, saved_friendslist_size, friends_list_load, friends_list_save);
3264
1.96k
    m_register_state_plugin(m, STATE_TYPE_NAME, name_size, load_name, save_name);
3265
1.96k
    m_register_state_plugin(m, STATE_TYPE_STATUSMESSAGE, status_message_size, load_status_message,
3266
1.96k
                            save_status_message);
3267
1.96k
    m_register_state_plugin(m, STATE_TYPE_STATUS, status_size, load_status, save_status);
3268
1.96k
    if (m->options.groups_persistence_enabled) {
3269
1.96k
        m_register_state_plugin(m, STATE_TYPE_GROUPS, saved_groups_size, groups_load, groups_save);
3270
1.96k
    }
3271
1.96k
    m_register_state_plugin(m, STATE_TYPE_TCP_RELAY, tcp_relay_size, load_tcp_relays, save_tcp_relays);
3272
1.96k
    m_register_state_plugin(m, STATE_TYPE_PATH_NODE, path_node_size, load_path_nodes, save_path_nodes);
3273
1.96k
}
3274
3275
bool messenger_load_state_section(Messenger *m, const uint8_t *data, uint32_t length, uint16_t type,
3276
                                  State_Load_Status *status)
3277
34.2k
{
3278
231k
    for (uint8_t i = 0; i < m->options.state_plugins_length; ++i) {
3279
230k
        const Messenger_State_Plugin *const plugin = &m->options.state_plugins[i];
3280
3281
230k
        if (plugin->type == type) {
3282
33.3k
            *status = plugin->load(m, data, length);
3283
33.3k
            return true;
3284
33.3k
        }
3285
230k
    }
3286
3287
903
    return false;
3288
34.2k
}
3289
3290
/** @brief Return the number of friends in the instance m.
3291
 *
3292
 * You should use this to determine how much memory to allocate
3293
 * for copy_friendlist.
3294
 */
3295
uint32_t count_friendlist(const Messenger *m)
3296
4.40k
{
3297
4.40k
    uint32_t ret = 0;
3298
3299
4.78k
    for (uint32_t i = 0; i < m->numfriends; ++i) {
3300
375
        if (m->friendlist[i].status > 0) {
3301
375
            ++ret;
3302
375
        }
3303
375
    }
3304
3305
4.40k
    return ret;
3306
4.40k
}
3307
3308
/** @brief Copy a list of valid friend IDs into the array out_list.
3309
 * If out_list is NULL, returns 0.
3310
 * Otherwise, returns the number of elements copied.
3311
 * If the array was too small, the contents
3312
 * of out_list will be truncated to list_size.
3313
 */
3314
uint32_t copy_friendlist(const Messenger *m, uint32_t *out_list, uint32_t list_size)
3315
0
{
3316
0
    if (out_list == nullptr) {
3317
0
        return 0;
3318
0
    }
3319
3320
0
    if (m->numfriends == 0) {
3321
0
        return 0;
3322
0
    }
3323
3324
0
    uint32_t ret = 0;
3325
3326
0
    for (uint32_t i = 0; i < m->numfriends; ++i) {
3327
0
        if (ret >= list_size) {
3328
0
            break; /* Abandon ship */
3329
0
        }
3330
3331
0
        if (m->friendlist[i].status > 0) {
3332
0
            out_list[ret] = i;
3333
0
            ++ret;
3334
0
        }
3335
0
    }
3336
3337
0
    return ret;
3338
0
}
3339
3340
static fr_friend_request_cb m_handle_friend_request;
3341
static void m_handle_friend_request(
3342
    void *_Nonnull object, const uint8_t *_Nonnull public_key, const uint8_t *_Nonnull message, size_t length, void *_Nullable user_data)
3343
0
{
3344
0
    Messenger *m = (Messenger *)object;
3345
0
    assert(m != nullptr);
3346
0
    m->friend_request(m, public_key, message, length, user_data);
3347
0
}
3348
3349
/** @brief Run this at startup.
3350
 *
3351
 * @return allocated instance of Messenger on success.
3352
 * @retval 0 if there are problems.
3353
 *
3354
 * if error is not NULL it will be set to one of the values in the enum above.
3355
 */
3356
Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *rng, const Network *ns,
3357
                         Messenger_Options *options, Messenger_Error *error)
3358
1.98k
{
3359
1.98k
    if (options == nullptr) {
3360
0
        return nullptr;
3361
0
    }
3362
3363
1.98k
    if (error != nullptr) {
3364
1.98k
        *error = MESSENGER_ERROR_OTHER;
3365
1.98k
    }
3366
3367
1.98k
    Messenger *m = (Messenger *)mem_alloc(mem, sizeof(Messenger));
3368
3369
1.98k
    if (m == nullptr) {
3370
1
        return nullptr;
3371
1
    }
3372
3373
1.98k
    m->mono_time = mono_time;
3374
1.98k
    m->mem = mem;
3375
1.98k
    m->rng = rng;
3376
1.98k
    m->ns = ns;
3377
3378
1.98k
    m->fr = friendreq_new(mem);
3379
3380
1.98k
    if (m->fr == nullptr) {
3381
1
        mem_delete(mem, m);
3382
1
        return nullptr;
3383
1
    }
3384
3385
1.98k
    m->log = logger_new(mem);
3386
3387
1.98k
    if (m->log == nullptr) {
3388
1
        friendreq_kill(m->fr);
3389
1
        mem_delete(mem, m);
3390
1
        return nullptr;
3391
1
    }
3392
3393
1.98k
    logger_callback_log(m->log, options->log_callback, options->log_context, options->log_user_data);
3394
3395
1.98k
    unsigned int net_err = 0;
3396
3397
1.98k
    if (!options->udp_disabled && options->proxy_info.proxy_type != TCP_PROXY_NONE) {
3398
        // We don't currently support UDP over proxy.
3399
10
        LOGGER_INFO(m->log, "UDP enabled and proxy set: disabling UDP");
3400
10
        options->udp_disabled = true;
3401
10
    }
3402
3403
1.98k
    if (options->udp_disabled) {
3404
10
        m->net = new_networking_no_udp(m->log, m->mem, m->ns);
3405
1.97k
    } else {
3406
1.97k
        IP ip;
3407
1.97k
        ip_init(&ip, options->ipv6enabled);
3408
1.97k
        m->net = new_networking_ex(m->log, m->mem, m->ns, &ip, options->port_range[0], options->port_range[1], &net_err);
3409
1.97k
    }
3410
3411
1.98k
    if (m->net == nullptr) {
3412
3
        friendreq_kill(m->fr);
3413
3414
3
        if (error != nullptr && net_err == 1) {
3415
0
            LOGGER_WARNING(m->log, "network initialisation failed (no ports available)");
3416
0
            *error = MESSENGER_ERROR_PORT;
3417
0
        }
3418
3419
3
        logger_kill(m->log);
3420
3
        mem_delete(mem, m);
3421
3
        return nullptr;
3422
3
    }
3423
3424
1.98k
    m->dht = new_dht(m->log, m->mem, m->rng, m->ns, m->mono_time, m->net, options->hole_punching_enabled, options->local_discovery_enabled);
3425
3426
1.98k
    if (m->dht == nullptr) {
3427
14
        kill_networking(m->net);
3428
14
        friendreq_kill(m->fr);
3429
14
        logger_kill(m->log);
3430
14
        mem_delete(mem, m);
3431
14
        return nullptr;
3432
14
    }
3433
3434
1.96k
    m->tcp_np = netprof_new(m->log, mem);
3435
3436
1.96k
    if (m->tcp_np == nullptr) {
3437
0
        LOGGER_WARNING(m->log, "TCP netprof initialisation failed");
3438
0
        kill_dht(m->dht);
3439
0
        kill_networking(m->net);
3440
0
        friendreq_kill(m->fr);
3441
0
        logger_kill(m->log);
3442
0
        mem_delete(mem, m);
3443
0
        return nullptr;
3444
0
    }
3445
3446
1.96k
    m->net_crypto = new_net_crypto(m->log, m->mem, m->rng, m->ns, m->mono_time, m->dht, &options->proxy_info, m->tcp_np);
3447
3448
1.96k
    if (m->net_crypto == nullptr) {
3449
0
        LOGGER_WARNING(m->log, "net_crypto initialisation failed");
3450
3451
0
        netprof_kill(mem, m->tcp_np);
3452
0
        kill_dht(m->dht);
3453
0
        kill_networking(m->net);
3454
0
        friendreq_kill(m->fr);
3455
0
        logger_kill(m->log);
3456
0
        mem_delete(mem, m);
3457
0
        return nullptr;
3458
0
    }
3459
3460
1.96k
    m->group_announce = new_gca_list(m->mem);
3461
3462
1.96k
    if (m->group_announce == nullptr) {
3463
0
        LOGGER_WARNING(m->log, "DHT group chats initialisation failed");
3464
3465
0
        kill_net_crypto(m->net_crypto);
3466
0
        netprof_kill(mem, m->tcp_np);
3467
0
        kill_dht(m->dht);
3468
0
        kill_networking(m->net);
3469
0
        friendreq_kill(m->fr);
3470
0
        logger_kill(m->log);
3471
0
        mem_delete(mem, m);
3472
0
        return nullptr;
3473
0
    }
3474
3475
1.96k
    if (options->dht_announcements_enabled) {
3476
1.96k
        m->forwarding = new_forwarding(m->log, m->mem, m->rng, m->mono_time, m->dht);
3477
1.96k
        if (m->forwarding != nullptr) {
3478
1.96k
            m->announce = new_announcements(m->log, m->mem, m->rng, m->mono_time, m->forwarding);
3479
1.96k
        } else {
3480
0
            m->announce = nullptr;
3481
0
        }
3482
1.96k
    } else {
3483
0
        m->forwarding = nullptr;
3484
0
        m->announce = nullptr;
3485
0
    }
3486
3487
1.96k
    m->onion = new_onion(m->log, m->mem, m->mono_time, m->rng, m->dht);
3488
1.96k
    m->onion_a = new_onion_announce(m->log, m->mem, m->rng, m->mono_time, m->dht);
3489
1.96k
    m->onion_c = new_onion_client(m->log, m->mem, m->rng, m->mono_time, m->net_crypto);
3490
1.96k
    if (m->onion_c != nullptr) {
3491
1.96k
        m->fr_c = new_friend_connections(m->log, m->mem, m->mono_time, m->ns, m->onion_c, options->local_discovery_enabled);
3492
1.96k
    }
3493
3494
1.96k
    if ((options->dht_announcements_enabled && (m->forwarding == nullptr || m->announce == nullptr)) ||
3495
1.96k
            m->onion == nullptr || m->onion_a == nullptr || m->onion_c == nullptr || m->fr_c == nullptr) {
3496
0
        LOGGER_WARNING(m->log, "onion initialisation failed");
3497
3498
0
        kill_onion(m->onion);
3499
0
        kill_onion_announce(m->onion_a);
3500
0
        kill_onion_client(m->onion_c);
3501
0
        kill_gca(m->group_announce);
3502
0
        kill_friend_connections(m->fr_c);
3503
0
        kill_announcements(m->announce);
3504
0
        kill_forwarding(m->forwarding);
3505
0
        kill_net_crypto(m->net_crypto);
3506
0
        netprof_kill(mem, m->tcp_np);
3507
0
        kill_dht(m->dht);
3508
0
        kill_networking(m->net);
3509
0
        friendreq_kill(m->fr);
3510
0
        logger_kill(m->log);
3511
0
        mem_delete(mem, m);
3512
0
        return nullptr;
3513
0
    }
3514
3515
1.96k
    gca_onion_init(m->group_announce, m->onion_a);
3516
3517
1.96k
    m->group_handler = new_dht_groupchats(m);
3518
3519
1.96k
    if (m->group_handler == nullptr) {
3520
0
        LOGGER_WARNING(m->log, "conferences initialisation failed");
3521
3522
0
        kill_onion(m->onion);
3523
0
        kill_onion_announce(m->onion_a);
3524
0
        kill_onion_client(m->onion_c);
3525
0
        kill_gca(m->group_announce);
3526
0
        kill_friend_connections(m->fr_c);
3527
0
        kill_announcements(m->announce);
3528
0
        kill_forwarding(m->forwarding);
3529
0
        kill_net_crypto(m->net_crypto);
3530
0
        netprof_kill(mem, m->tcp_np);
3531
0
        kill_dht(m->dht);
3532
0
        kill_networking(m->net);
3533
0
        friendreq_kill(m->fr);
3534
0
        logger_kill(m->log);
3535
0
        mem_delete(mem, m);
3536
0
        return nullptr;
3537
0
    }
3538
3539
1.96k
    if (options->tcp_server_port != 0) {
3540
0
        m->tcp_server = new_tcp_server(m->log, m->mem, m->rng, m->ns, options->ipv6enabled, 1,
3541
0
                                       &options->tcp_server_port, dht_get_self_secret_key(m->dht),
3542
0
                                       m->onion, m->forwarding);
3543
3544
0
        if (m->tcp_server == nullptr) {
3545
0
            LOGGER_WARNING(m->log, "TCP server initialisation failed");
3546
3547
0
            kill_onion(m->onion);
3548
0
            kill_onion_announce(m->onion_a);
3549
0
            kill_dht_groupchats(m->group_handler);
3550
0
            kill_friend_connections(m->fr_c);
3551
0
            kill_onion_client(m->onion_c);
3552
0
            kill_gca(m->group_announce);
3553
0
            kill_announcements(m->announce);
3554
0
            kill_forwarding(m->forwarding);
3555
0
            kill_net_crypto(m->net_crypto);
3556
0
            netprof_kill(mem, m->tcp_np);
3557
0
            kill_dht(m->dht);
3558
0
            kill_networking(m->net);
3559
0
            friendreq_kill(m->fr);
3560
0
            logger_kill(m->log);
3561
0
            mem_delete(mem, m);
3562
3563
0
            if (error != nullptr) {
3564
0
                *error = MESSENGER_ERROR_TCP_SERVER;
3565
0
            }
3566
3567
0
            return nullptr;
3568
0
        }
3569
0
    }
3570
3571
1.96k
    m->options = *options;
3572
1.96k
    friendreq_init(m->fr, m->fr_c);
3573
1.96k
    set_nospam(m->fr, random_u32(m->rng));
3574
1.96k
    set_filter_function(m->fr, &friend_already_added, m);
3575
3576
1.96k
    m->lastdump = 0;
3577
1.96k
    m->is_receiving_file = 0;
3578
3579
1.96k
    m_register_default_plugins(m);
3580
1.96k
    callback_friendrequest(m->fr, m_handle_friend_request, m);
3581
3582
1.96k
    if (error != nullptr) {
3583
1.96k
        *error = MESSENGER_ERROR_NONE;
3584
1.96k
    }
3585
3586
1.96k
    return m;
3587
1.96k
}
3588
3589
/** @brief Run this before closing shop.
3590
 *
3591
 * Free all datastructures.
3592
 */
3593
void kill_messenger(Messenger *m)
3594
1.96k
{
3595
1.96k
    if (m == nullptr) {
3596
0
        return;
3597
0
    }
3598
3599
1.96k
    if (m->tcp_server != nullptr) {
3600
0
        kill_tcp_server(m->tcp_server);
3601
0
    }
3602
3603
1.96k
    kill_onion(m->onion);
3604
1.96k
    kill_onion_announce(m->onion_a);
3605
1.96k
    kill_dht_groupchats(m->group_handler);
3606
1.96k
    kill_friend_connections(m->fr_c);
3607
1.96k
    kill_onion_client(m->onion_c);
3608
1.96k
    kill_gca(m->group_announce);
3609
1.96k
    kill_announcements(m->announce);
3610
1.96k
    kill_forwarding(m->forwarding);
3611
1.96k
    kill_net_crypto(m->net_crypto);
3612
1.96k
    netprof_kill(m->mem, m->tcp_np);
3613
1.96k
    kill_dht(m->dht);
3614
1.96k
    kill_networking(m->net);
3615
3616
2.24k
    for (uint32_t i = 0; i < m->numfriends; ++i) {
3617
272
        clear_receipts(m, i);
3618
272
    }
3619
3620
1.96k
    mem_delete(m->mem, m->friendlist);
3621
1.96k
    friendreq_kill(m->fr);
3622
3623
1.96k
    mem_delete(m->mem, m->options.state_plugins);
3624
1.96k
    logger_kill(m->log);
3625
1.96k
    mem_delete(m->mem, m);
3626
1.96k
}
3627
3628
bool m_is_receiving_file(Messenger *m)
3629
0
{
3630
    // Only run the expensive loop below once every 64 tox_iterate calls.
3631
0
    const uint8_t skip_count = 64;
3632
3633
0
    if (m->is_receiving_file != 0) {
3634
0
        --m->is_receiving_file;
3635
0
        return true;
3636
0
    }
3637
3638
    // TODO(iphydf): This is a very expensive loop. Consider keeping track of
3639
    // the number of live file transfers.
3640
0
    for (size_t friend_number = 0; friend_number < m->numfriends; ++friend_number) {
3641
0
        for (size_t i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {
3642
0
            if (m->friendlist[friend_number].file_receiving[i].status == FILESTATUS_TRANSFERRING) {
3643
0
                m->is_receiving_file = skip_count;
3644
0
                return true;
3645
0
            }
3646
0
        }
3647
0
    }
3648
3649
0
    return false;
3650
0
}