summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzugz (tox) <mbays+tox@sdf.org>2019-04-28 00:00:02 +0000
committerzugz (tox) <mbays+tox@sdf.org>2020-03-15 00:00:27 +0000
commit52655b0c1b8b32ce373498391df868d39a1e2834 (patch)
tree09721aadda1bd225fccf3049a07a849881d8147f
parent8795c5f987e2bd716d59a96418f1c7f6f9e83839 (diff)
clean groups code
* make static functions return bool rather than int to indicate success * add peer_in_list() to factor out uniformity over peer and frozen lists * reduce repetition in send_lossy_all_close * rename 'close' to 'connections' * use uint32_t for peernumber (in accord with tox.c) * explain persistence in tox_conference_get_chatlist documentation * clarify "connectedness" in group API documentation * clarify that tox_conference_peer_count counts only online peers * refactor variously
-rw-r--r--toxav/groupav.h2
-rw-r--r--toxcore/group.c842
-rw-r--r--toxcore/group.h54
-rw-r--r--toxcore/onion_client.h2
-rw-r--r--toxcore/tox.api.h35
-rw-r--r--toxcore/tox.h35
6 files changed, 456 insertions, 514 deletions
diff --git a/toxav/groupav.h b/toxav/groupav.h
index 42c230a8..32304a2b 100644
--- a/toxav/groupav.h
+++ b/toxav/groupav.h
@@ -19,7 +19,7 @@
19typedef void audio_data_cb(void *tox, uint32_t groupnumber, uint32_t peernumber, const int16_t *pcm, 19typedef void audio_data_cb(void *tox, uint32_t groupnumber, uint32_t peernumber, const int16_t *pcm,
20 uint32_t samples, uint8_t channels, uint32_t sample_rate, void *userdata); 20 uint32_t samples, uint8_t channels, uint32_t sample_rate, void *userdata);
21 21
22/* Create a new toxav group. 22/* Create and connect to a new toxav group.
23 * 23 *
24 * return group number on success. 24 * return group number on success.
25 * return -1 on failure. 25 * return -1 on failure.
diff --git a/toxcore/group.c b/toxcore/group.c
index aebf3092..50f6f2fe 100644
--- a/toxcore/group.c
+++ b/toxcore/group.c
@@ -61,19 +61,9 @@ typedef enum Peer_Id {
61 */ 61 */
62static bool is_groupnumber_valid(const Group_Chats *g_c, uint32_t groupnumber) 62static bool is_groupnumber_valid(const Group_Chats *g_c, uint32_t groupnumber)
63{ 63{
64 if (groupnumber >= g_c->num_chats) { 64 return groupnumber < g_c->num_chats
65 return false; 65 && g_c->chats != nullptr
66 } 66 && g_c->chats[groupnumber].status != GROUPCHAT_STATUS_NONE;
67
68 if (g_c->chats == nullptr) {
69 return false;
70 }
71
72 if (g_c->chats[groupnumber].status == GROUPCHAT_STATUS_NONE) {
73 return false;
74 }
75
76 return true;
77} 67}
78 68
79 69
@@ -120,27 +110,25 @@ static int32_t create_group_chat(Group_Chats *g_c)
120 } 110 }
121 } 111 }
122 112
123 int32_t id = -1;
124
125 if (realloc_conferences(g_c, g_c->num_chats + 1)) { 113 if (realloc_conferences(g_c, g_c->num_chats + 1)) {
126 id = g_c->num_chats; 114 uint16_t id = g_c->num_chats;
127 ++g_c->num_chats; 115 ++g_c->num_chats;
128 setup_conference(&g_c->chats[id]); 116 setup_conference(&g_c->chats[id]);
117 return id;
129 } 118 }
130 119
131 return id; 120 return -1;
132} 121}
133 122
134 123
135/* Wipe a groupchat. 124/* Wipe a groupchat.
136 * 125 *
137 * return -1 on failure. 126 * return true on success.
138 * return 0 on success.
139 */ 127 */
140static int wipe_group_chat(Group_Chats *g_c, uint32_t groupnumber) 128static bool wipe_group_chat(Group_Chats *g_c, uint32_t groupnumber)
141{ 129{
142 if (!is_groupnumber_valid(g_c, groupnumber)) { 130 if (!is_groupnumber_valid(g_c, groupnumber)) {
143 return -1; 131 return false;
144 } 132 }
145 133
146 uint16_t i; 134 uint16_t i;
@@ -157,7 +145,7 @@ static int wipe_group_chat(Group_Chats *g_c, uint32_t groupnumber)
157 realloc_conferences(g_c, g_c->num_chats); 145 realloc_conferences(g_c, g_c->num_chats);
158 } 146 }
159 147
160 return 0; 148 return true;
161} 149}
162 150
163static Group_c *get_group_c(const Group_Chats *g_c, uint32_t groupnumber) 151static Group_c *get_group_c(const Group_Chats *g_c, uint32_t groupnumber)
@@ -172,16 +160,16 @@ static Group_c *get_group_c(const Group_Chats *g_c, uint32_t groupnumber)
172/* 160/*
173 * check if peer with real_pk is in peer array. 161 * check if peer with real_pk is in peer array.
174 * 162 *
175 * return peer index if peer is in chat. 163 * return peer index if peer is in group.
176 * return -1 if peer is not in chat. 164 * return -1 if peer is not in group.
177 * 165 *
178 * TODO(irungentoo): make this more efficient. 166 * TODO(irungentoo): make this more efficient.
179 */ 167 */
180 168
181static int peer_in_chat(const Group_c *chat, const uint8_t *real_pk) 169static int peer_in_group(const Group_c *g, const uint8_t *real_pk)
182{ 170{
183 for (uint32_t i = 0; i < chat->numpeers; ++i) { 171 for (uint32_t i = 0; i < g->numpeers; ++i) {
184 if (id_equal(chat->group[i].real_pk, real_pk)) { 172 if (id_equal(g->group[i].real_pk, real_pk)) {
185 return i; 173 return i;
186 } 174 }
187 } 175 }
@@ -189,10 +177,10 @@ static int peer_in_chat(const Group_c *chat, const uint8_t *real_pk)
189 return -1; 177 return -1;
190} 178}
191 179
192static int frozen_in_chat(const Group_c *chat, const uint8_t *real_pk) 180static int frozen_in_group(const Group_c *g, const uint8_t *real_pk)
193{ 181{
194 for (uint32_t i = 0; i < chat->numfrozen; ++i) { 182 for (uint32_t i = 0; i < g->numfrozen; ++i) {
195 if (id_equal(chat->frozen[i].real_pk, real_pk)) { 183 if (id_equal(g->frozen[i].real_pk, real_pk)) {
196 return i; 184 return i;
197 } 185 }
198 } 186 }
@@ -262,47 +250,39 @@ static uint64_t calculate_comp_value(const uint8_t *pk1, const uint8_t *pk2)
262 return cmp1 - cmp2; 250 return cmp1 - cmp2;
263} 251}
264 252
265typedef enum Groupchat_Closest { 253typedef enum Groupchat_Closest_Change {
266 GROUPCHAT_CLOSEST_NONE, 254 GROUPCHAT_CLOSEST_CHANGE_NONE,
267 GROUPCHAT_CLOSEST_ADDED, 255 GROUPCHAT_CLOSEST_CHANGE_ADDED,
268 GROUPCHAT_CLOSEST_REMOVED, 256 GROUPCHAT_CLOSEST_CHANGE_REMOVED,
269} Groupchat_Closest; 257} Groupchat_Closest_Change;
270 258
271static int add_to_closest(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk, const uint8_t *temp_pk) 259static bool add_to_closest(Group_c *g, const uint8_t *real_pk, const uint8_t *temp_pk)
272{ 260{
273 Group_c *g = get_group_c(g_c, groupnumber);
274
275 if (!g) {
276 return -1;
277 }
278
279 if (public_key_cmp(g->real_pk, real_pk) == 0) { 261 if (public_key_cmp(g->real_pk, real_pk) == 0) {
280 return -1; 262 return false;
281 } 263 }
282 264
283 unsigned int i; 265 unsigned int index = DESIRED_CLOSEST;
284 unsigned int index = DESIRED_CLOSE_CONNECTIONS;
285 266
286 for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { 267 for (unsigned int i = 0; i < DESIRED_CLOSEST; ++i) {
287 if (g->closest_peers[i].entry && public_key_cmp(real_pk, g->closest_peers[i].real_pk) == 0) { 268 if (g->closest_peers[i].entry && public_key_cmp(real_pk, g->closest_peers[i].real_pk) == 0) {
288 return 0; 269 return true;
289 } 270 }
290 } 271 }
291 272
292 for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { 273 for (unsigned int i = 0; i < DESIRED_CLOSEST; ++i) {
293 if (g->closest_peers[i].entry == 0) { 274 if (g->closest_peers[i].entry == 0) {
294 index = i; 275 index = i;
295 break; 276 break;
296 } 277 }
297 } 278 }
298 279
299 if (index == DESIRED_CLOSE_CONNECTIONS) { 280 if (index == DESIRED_CLOSEST) {
300 uint64_t comp_val = calculate_comp_value(g->real_pk, real_pk); 281 uint64_t comp_val = calculate_comp_value(g->real_pk, real_pk);
301 uint64_t comp_d = 0; 282 uint64_t comp_d = 0;
302 283
303 for (i = 0; i < (DESIRED_CLOSE_CONNECTIONS / 2); ++i) { 284 for (unsigned int i = 0; i < (DESIRED_CLOSEST / 2); ++i) {
304 uint64_t comp; 285 uint64_t comp = calculate_comp_value(g->real_pk, g->closest_peers[i].real_pk);
305 comp = calculate_comp_value(g->real_pk, g->closest_peers[i].real_pk);
306 286
307 if (comp > comp_val && comp > comp_d) { 287 if (comp > comp_val && comp > comp_d) {
308 index = i; 288 index = i;
@@ -312,7 +292,7 @@ static int add_to_closest(Group_Chats *g_c, uint32_t groupnumber, const uint8_t
312 292
313 comp_val = calculate_comp_value(real_pk, g->real_pk); 293 comp_val = calculate_comp_value(real_pk, g->real_pk);
314 294
315 for (i = (DESIRED_CLOSE_CONNECTIONS / 2); i < DESIRED_CLOSE_CONNECTIONS; ++i) { 295 for (unsigned int i = (DESIRED_CLOSEST / 2); i < DESIRED_CLOSEST; ++i) {
316 uint64_t comp = calculate_comp_value(g->closest_peers[i].real_pk, g->real_pk); 296 uint64_t comp = calculate_comp_value(g->closest_peers[i].real_pk, g->real_pk);
317 297
318 if (comp > comp_val && comp > comp_d) { 298 if (comp > comp_val && comp > comp_d) {
@@ -322,8 +302,8 @@ static int add_to_closest(Group_Chats *g_c, uint32_t groupnumber, const uint8_t
322 } 302 }
323 } 303 }
324 304
325 if (index == DESIRED_CLOSE_CONNECTIONS) { 305 if (index == DESIRED_CLOSEST) {
326 return -1; 306 return false;
327 } 307 }
328 308
329 uint8_t old_real_pk[CRYPTO_PUBLIC_KEY_SIZE]; 309 uint8_t old_real_pk[CRYPTO_PUBLIC_KEY_SIZE];
@@ -341,34 +321,32 @@ static int add_to_closest(Group_Chats *g_c, uint32_t groupnumber, const uint8_t
341 memcpy(g->closest_peers[index].temp_pk, temp_pk, CRYPTO_PUBLIC_KEY_SIZE); 321 memcpy(g->closest_peers[index].temp_pk, temp_pk, CRYPTO_PUBLIC_KEY_SIZE);
342 322
343 if (old) { 323 if (old) {
344 add_to_closest(g_c, groupnumber, old_real_pk, old_temp_pk); 324 add_to_closest(g, old_real_pk, old_temp_pk);
345 } 325 }
346 326
347 if (!g->changed) { 327 if (!g->changed) {
348 g->changed = GROUPCHAT_CLOSEST_ADDED; 328 g->changed = GROUPCHAT_CLOSEST_CHANGE_ADDED;
349 } 329 }
350 330
351 return 0; 331 return true;
352} 332}
353 333
354static unsigned int pk_in_closest_peers(const Group_c *g, uint8_t *real_pk) 334static bool pk_in_closest_peers(const Group_c *g, uint8_t *real_pk)
355{ 335{
356 unsigned int i; 336 for (unsigned int i = 0; i < DESIRED_CLOSEST; ++i) {
357
358 for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) {
359 if (!g->closest_peers[i].entry) { 337 if (!g->closest_peers[i].entry) {
360 continue; 338 continue;
361 } 339 }
362 340
363 if (public_key_cmp(g->closest_peers[i].real_pk, real_pk) == 0) { 341 if (public_key_cmp(g->closest_peers[i].real_pk, real_pk) == 0) {
364 return 1; 342 return true;
365 } 343 }
366 } 344 }
367 345
368 return 0; 346 return false;
369} 347}
370 348
371static void remove_conn_reason(Group_Chats *g_c, uint32_t groupnumber, uint16_t i, uint8_t reason); 349static void remove_connection_reason(Group_Chats *g_c, Group_c *g, uint16_t i, uint8_t reason);
372 350
373static void purge_closest(Group_Chats *g_c, uint32_t groupnumber) 351static void purge_closest(Group_Chats *g_c, uint32_t groupnumber)
374{ 352{
@@ -379,19 +357,19 @@ static void purge_closest(Group_Chats *g_c, uint32_t groupnumber)
379 } 357 }
380 358
381 for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { 359 for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
382 if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { 360 if (g->connections[i].type == GROUPCHAT_CONNECTION_NONE) {
383 continue; 361 continue;
384 } 362 }
385 363
386 if (!(g->close[i].reasons & GROUPCHAT_CLOSE_REASON_CLOSEST)) { 364 if (!(g->connections[i].reasons & GROUPCHAT_CONNECTION_REASON_CLOSEST)) {
387 continue; 365 continue;
388 } 366 }
389 367
390 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; 368 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE];
391 get_friendcon_public_keys(real_pk, nullptr, g_c->fr_c, g->close[i].number); 369 get_friendcon_public_keys(real_pk, nullptr, g_c->fr_c, g->connections[i].number);
392 370
393 if (!pk_in_closest_peers(g, real_pk)) { 371 if (!pk_in_closest_peers(g, real_pk)) {
394 remove_conn_reason(g_c, groupnumber, i, GROUPCHAT_CLOSE_REASON_CLOSEST); 372 remove_connection_reason(g_c, g, i, GROUPCHAT_CONNECTION_REASON_CLOSEST);
395 } 373 }
396 } 374 }
397} 375}
@@ -399,7 +377,7 @@ static void purge_closest(Group_Chats *g_c, uint32_t groupnumber)
399static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t type, 377static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t type,
400 const uint8_t *id); 378 const uint8_t *id);
401 379
402static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, uint32_t groupnumber, uint8_t reason, 380static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, Group_c *g, uint8_t reason,
403 uint8_t lock); 381 uint8_t lock);
404 382
405static void add_closest_connections(Group_Chats *g_c, uint32_t groupnumber, void *userdata) 383static void add_closest_connections(Group_Chats *g_c, uint32_t groupnumber, void *userdata)
@@ -410,7 +388,7 @@ static void add_closest_connections(Group_Chats *g_c, uint32_t groupnumber, void
410 return; 388 return;
411 } 389 }
412 390
413 for (uint32_t i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { 391 for (uint32_t i = 0; i < DESIRED_CLOSEST; ++i) {
414 if (!g->closest_peers[i].entry) { 392 if (!g->closest_peers[i].entry) {
415 continue; 393 continue;
416 } 394 }
@@ -430,9 +408,10 @@ static void add_closest_connections(Group_Chats *g_c, uint32_t groupnumber, void
430 set_dht_temp_pk(g_c->fr_c, friendcon_id, g->closest_peers[i].temp_pk, userdata); 408 set_dht_temp_pk(g_c->fr_c, friendcon_id, g->closest_peers[i].temp_pk, userdata);
431 } 409 }
432 410
433 const int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnumber, GROUPCHAT_CLOSE_REASON_CLOSEST, !fresh); 411 const int connection_index = add_conn_to_groupchat(g_c, friendcon_id, g,
412 GROUPCHAT_CONNECTION_REASON_CLOSEST, !fresh);
434 413
435 if (close_index == -1) { 414 if (connection_index == -1) {
436 if (fresh) { 415 if (fresh) {
437 kill_friend_connection(g_c->fr_c, friendcon_id); 416 kill_friend_connection(g_c->fr_c, friendcon_id);
438 } 417 }
@@ -441,27 +420,27 @@ static void add_closest_connections(Group_Chats *g_c, uint32_t groupnumber, void
441 } 420 }
442 421
443 if (friend_con_connected(g_c->fr_c, friendcon_id) == FRIENDCONN_STATUS_CONNECTED 422 if (friend_con_connected(g_c->fr_c, friendcon_id) == FRIENDCONN_STATUS_CONNECTED
444 && g->close[close_index].type == GROUPCHAT_CLOSE_CONNECTION) { 423 && g->connections[connection_index].type == GROUPCHAT_CONNECTION_CONNECTING) {
445 send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->type, g->id); 424 send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->type, g->id);
446 } 425 }
447 } 426 }
448} 427}
449 428
450static int connect_to_closest(Group_Chats *g_c, uint32_t groupnumber, void *userdata) 429static bool connect_to_closest(Group_Chats *g_c, uint32_t groupnumber, void *userdata)
451{ 430{
452 Group_c *g = get_group_c(g_c, groupnumber); 431 Group_c *g = get_group_c(g_c, groupnumber);
453 432
454 if (!g) { 433 if (!g) {
455 return -1; 434 return false;
456 } 435 }
457 436
458 if (!g->changed) { 437 if (!g->changed) {
459 return 0; 438 return true;
460 } 439 }
461 440
462 if (g->changed == GROUPCHAT_CLOSEST_REMOVED) { 441 if (g->changed == GROUPCHAT_CLOSEST_CHANGE_REMOVED) {
463 for (uint32_t i = 0; i < g->numpeers; ++i) { 442 for (uint32_t i = 0; i < g->numpeers; ++i) {
464 add_to_closest(g_c, groupnumber, g->group[i].real_pk, g->group[i].temp_pk); 443 add_to_closest(g, g->group[i].real_pk, g->group[i].temp_pk);
465 } 444 }
466 } 445 }
467 446
@@ -469,9 +448,9 @@ static int connect_to_closest(Group_Chats *g_c, uint32_t groupnumber, void *user
469 448
470 add_closest_connections(g_c, groupnumber, userdata); 449 add_closest_connections(g_c, groupnumber, userdata);
471 450
472 g->changed = GROUPCHAT_CLOSEST_NONE; 451 g->changed = GROUPCHAT_CLOSEST_CHANGE_NONE;
473 452
474 return 0; 453 return true;
475} 454}
476 455
477static int get_frozen_index(const Group_c *g, uint16_t peer_number) 456static int get_frozen_index(const Group_c *g, uint16_t peer_number)
@@ -547,12 +526,14 @@ static int note_peer_active(Group_Chats *g_c, uint32_t groupnumber, uint16_t pee
547 return -1; 526 return -1;
548 } 527 }
549 528
529 const uint32_t thawed_index = g->numpeers;
530
550 g->group = temp; 531 g->group = temp;
551 g->group[g->numpeers] = g->frozen[frozen_index]; 532 g->group[thawed_index] = g->frozen[frozen_index];
552 g->group[g->numpeers].temp_pk_updated = false; 533 g->group[thawed_index].temp_pk_updated = false;
553 g->group[g->numpeers].last_active = mono_time_get(g_c->mono_time); 534 g->group[thawed_index].last_active = mono_time_get(g_c->mono_time);
554 535
555 add_to_closest(g_c, groupnumber, g->group[g->numpeers].real_pk, g->group[g->numpeers].temp_pk); 536 add_to_closest(g, g->group[thawed_index].real_pk, g->group[thawed_index].temp_pk);
556 537
557 ++g->numpeers; 538 ++g->numpeers;
558 539
@@ -563,15 +544,15 @@ static int note_peer_active(Group_Chats *g_c, uint32_t groupnumber, uint16_t pee
563 } 544 }
564 545
565 if (g->peer_on_join) { 546 if (g->peer_on_join) {
566 g->peer_on_join(g->object, groupnumber, g->numpeers - 1); 547 g->peer_on_join(g->object, groupnumber, thawed_index);
567 } 548 }
568 549
569 g->need_send_name = true; 550 g->need_send_name = true;
570 551
571 return g->numpeers - 1; 552 return thawed_index;
572} 553}
573 554
574static int delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void *userdata); 555static bool delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void *userdata);
575 556
576static void delete_any_peer_with_pk(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk, void *userdata) 557static void delete_any_peer_with_pk(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk, void *userdata)
577{ 558{
@@ -581,16 +562,16 @@ static void delete_any_peer_with_pk(Group_Chats *g_c, uint32_t groupnumber, cons
581 return; 562 return;
582 } 563 }
583 564
584 const int prev_peer_index = peer_in_chat(g, real_pk); 565 const int peer_index = peer_in_group(g, real_pk);
585 566
586 if (prev_peer_index >= 0) { 567 if (peer_index >= 0) {
587 delpeer(g_c, groupnumber, prev_peer_index, userdata); 568 delpeer(g_c, groupnumber, peer_index, userdata);
588 } 569 }
589 570
590 const int prev_frozen_index = frozen_in_chat(g, real_pk); 571 const int frozen_index = frozen_in_group(g, real_pk);
591 572
592 if (prev_frozen_index >= 0) { 573 if (frozen_index >= 0) {
593 delete_frozen(g, prev_frozen_index); 574 delete_frozen(g, frozen_index);
594 } 575 }
595} 576}
596 577
@@ -657,63 +638,58 @@ static int addpeer(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_p
657 memset(&temp[g->numpeers], 0, sizeof(Group_Peer)); 638 memset(&temp[g->numpeers], 0, sizeof(Group_Peer));
658 g->group = temp; 639 g->group = temp;
659 640
660 id_copy(g->group[g->numpeers].real_pk, real_pk); 641 const uint32_t new_index = g->numpeers;
661 id_copy(g->group[g->numpeers].temp_pk, temp_pk); 642
662 g->group[g->numpeers].temp_pk_updated = true; 643 id_copy(g->group[new_index].real_pk, real_pk);
663 g->group[g->numpeers].peer_number = peer_number; 644 id_copy(g->group[new_index].temp_pk, temp_pk);
664 g->group[g->numpeers].last_active = mono_time_get(g_c->mono_time); 645 g->group[new_index].temp_pk_updated = true;
665 g->group[g->numpeers].is_friend = (getfriend_id(g_c->m, real_pk) != -1); 646 g->group[new_index].peer_number = peer_number;
647 g->group[new_index].last_active = mono_time_get(g_c->mono_time);
648 g->group[new_index].is_friend = (getfriend_id(g_c->m, real_pk) != -1);
666 ++g->numpeers; 649 ++g->numpeers;
667 650
668 add_to_closest(g_c, groupnumber, real_pk, temp_pk); 651 add_to_closest(g, real_pk, temp_pk);
669 652
670 if (do_gc_callback && g_c->peer_list_changed_callback) { 653 if (do_gc_callback && g_c->peer_list_changed_callback) {
671 g_c->peer_list_changed_callback(g_c->m, groupnumber, userdata); 654 g_c->peer_list_changed_callback(g_c->m, groupnumber, userdata);
672 } 655 }
673 656
674 if (g->peer_on_join) { 657 if (g->peer_on_join) {
675 g->peer_on_join(g->object, groupnumber, g->numpeers - 1); 658 g->peer_on_join(g->object, groupnumber, new_index);
676 } 659 }
677 660
678 return g->numpeers - 1; 661 return new_index;
679} 662}
680 663
681static int remove_close_conn(Group_Chats *g_c, uint32_t groupnumber, int friendcon_id) 664static bool remove_connection(Group_Chats *g_c, Group_c *g, int friendcon_id)
682{ 665{
683 Group_c *g = get_group_c(g_c, groupnumber); 666 for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
684 667 if (g->connections[i].type == GROUPCHAT_CONNECTION_NONE) {
685 if (!g) {
686 return -1;
687 }
688
689 uint32_t i;
690
691 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
692 if (g->close[i].type == GROUPCHAT_CLOSE_NONE) {
693 continue; 668 continue;
694 } 669 }
695 670
696 if (g->close[i].number == (unsigned int)friendcon_id) { 671 if (g->connections[i].number == (unsigned int)friendcon_id) {
697 if (g->close[i].reasons & GROUPCHAT_CLOSE_REASON_INTRODUCER) { 672 if (g->connections[i].reasons & GROUPCHAT_CONNECTION_REASON_INTRODUCER) {
698 --g->num_introducer_connections; 673 --g->num_introducer_connections;
699 } 674 }
700 675
701 g->close[i].type = GROUPCHAT_CLOSE_NONE; 676 g->connections[i].type = GROUPCHAT_CONNECTION_NONE;
702 kill_friend_connection(g_c->fr_c, friendcon_id); 677 kill_friend_connection(g_c->fr_c, friendcon_id);
703 return 0; 678 return true;
704 } 679 }
705 } 680 }
706 681
707 return -1; 682 return false;
708} 683}
709 684
710 685
711static void remove_from_closest(Group_c *g, int peer_index) 686static void remove_from_closest(Group_c *g, int peer_index)
712{ 687{
713 for (uint32_t i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { 688 for (uint32_t i = 0; i < DESIRED_CLOSEST; ++i) {
714 if (g->closest_peers[i].entry && id_equal(g->closest_peers[i].real_pk, g->group[peer_index].real_pk)) { 689 if (g->closest_peers[i].entry
690 && id_equal(g->closest_peers[i].real_pk, g->group[peer_index].real_pk)) {
715 g->closest_peers[i].entry = 0; 691 g->closest_peers[i].entry = 0;
716 g->changed = GROUPCHAT_CLOSEST_REMOVED; 692 g->changed = GROUPCHAT_CLOSEST_CHANGE_REMOVED;
717 break; 693 break;
718 } 694 }
719 } 695 }
@@ -722,15 +698,14 @@ static void remove_from_closest(Group_c *g, int peer_index)
722/* 698/*
723 * Delete a peer from the group chat. 699 * Delete a peer from the group chat.
724 * 700 *
725 * return 0 if success 701 * return true on success
726 * return -1 if error.
727 */ 702 */
728static int delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void *userdata) 703static bool delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void *userdata)
729{ 704{
730 Group_c *g = get_group_c(g_c, groupnumber); 705 Group_c *g = get_group_c(g_c, groupnumber);
731 706
732 if (!g) { 707 if (!g) {
733 return -1; 708 return false;
734 } 709 }
735 710
736 remove_from_closest(g, peer_index); 711 remove_from_closest(g, peer_index);
@@ -738,7 +713,7 @@ static int delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void
738 const int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, g->group[peer_index].real_pk); 713 const int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, g->group[peer_index].real_pk);
739 714
740 if (friendcon_id != -1) { 715 if (friendcon_id != -1) {
741 remove_close_conn(g_c, groupnumber, friendcon_id); 716 remove_connection(g_c, g, friendcon_id);
742 } 717 }
743 718
744 --g->numpeers; 719 --g->numpeers;
@@ -756,7 +731,7 @@ static int delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void
756 Group_Peer *temp = (Group_Peer *)realloc(g->group, sizeof(Group_Peer) * (g->numpeers)); 731 Group_Peer *temp = (Group_Peer *)realloc(g->group, sizeof(Group_Peer) * (g->numpeers));
757 732
758 if (temp == nullptr) { 733 if (temp == nullptr) {
759 return -1; 734 return false;
760 } 735 }
761 736
762 g->group = temp; 737 g->group = temp;
@@ -770,7 +745,7 @@ static int delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void
770 g->peer_on_leave(g->object, groupnumber, peer_object); 745 g->peer_on_leave(g->object, groupnumber, peer_object);
771 } 746 }
772 747
773 return 0; 748 return true;
774} 749}
775 750
776static int cmp_u64(uint64_t a, uint64_t b) 751static int cmp_u64(uint64_t a, uint64_t b)
@@ -823,37 +798,37 @@ static bool delete_old_frozen(Group_c *g)
823 return true; 798 return true;
824} 799}
825 800
826static bool try_send_rejoin(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk); 801static bool try_send_rejoin(Group_Chats *g_c, Group_c *g, const uint8_t *real_pk);
827 802
828static int freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void *userdata) 803static bool freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void *userdata)
829{ 804{
830 Group_c *g = get_group_c(g_c, groupnumber); 805 Group_c *g = get_group_c(g_c, groupnumber);
831 806
832 if (!g) { 807 if (!g) {
833 return -1; 808 return false;
834 } 809 }
835 810
836 Group_Peer *temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * (g->numfrozen + 1)); 811 Group_Peer *temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * (g->numfrozen + 1));
837 812
838 if (temp == nullptr) { 813 if (temp == nullptr) {
839 return -1; 814 return false;
840 } 815 }
841 816
842 g->frozen = temp; 817 g->frozen = temp;
843 g->frozen[g->numfrozen] = g->group[peer_index]; 818 g->frozen[g->numfrozen] = g->group[peer_index];
844 g->frozen[g->numfrozen].object = nullptr; 819 g->frozen[g->numfrozen].object = nullptr;
845 820
846 if (delpeer(g_c, groupnumber, peer_index, userdata) != 0) { 821 if (!delpeer(g_c, groupnumber, peer_index, userdata)) {
847 return -1; 822 return false;
848 } 823 }
849 824
850 try_send_rejoin(g_c, groupnumber, g->frozen[g->numfrozen].real_pk); 825 try_send_rejoin(g_c, g, g->frozen[g->numfrozen].real_pk);
851 826
852 ++g->numfrozen; 827 ++g->numfrozen;
853 828
854 delete_old_frozen(g); 829 delete_old_frozen(g);
855 830
856 return 0; 831 return true;
857} 832}
858 833
859 834
@@ -863,29 +838,27 @@ static int freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, v
863 * via the public API. This should be set to false if this function is called 838 * via the public API. This should be set to false if this function is called
864 * from outside of the tox_iterate() loop. 839 * from outside of the tox_iterate() loop.
865 * 840 *
866 * return 0 on success. 841 * return true on success.
867 * return -1 if error.
868 */ 842 */
869static int setnick(Group_Chats *g_c, uint32_t groupnumber, int peer_index, const uint8_t *nick, uint16_t nick_len, 843static bool setnick(Group_Chats *g_c, uint32_t groupnumber, int peer_index, const uint8_t *nick, uint16_t nick_len,
870 void *userdata, bool do_gc_callback) 844 void *userdata, bool do_gc_callback)
871{ 845{
872 if (nick_len > MAX_NAME_LENGTH) { 846 if (nick_len > MAX_NAME_LENGTH) {
873 return -1; 847 return false;
874 } 848 }
875 849
876 Group_c *g = get_group_c(g_c, groupnumber); 850 Group_c *g = get_group_c(g_c, groupnumber);
877 851
878 if (!g) { 852 if (!g) {
879 return -1; 853 return false;
880 } 854 }
881 855
882 g->group[peer_index].nick_updated = true; 856 g->group[peer_index].nick_updated = true;
883 857
884 /* same name as already stored? */ 858 if (g->group[peer_index].nick_len == nick_len
885 if (g->group[peer_index].nick_len == nick_len) { 859 && (nick_len == 0 || !memcmp(g->group[peer_index].nick, nick, nick_len))) {
886 if (nick_len == 0 || !memcmp(g->group[peer_index].nick, nick, nick_len)) { 860 /* same name as already stored */
887 return 0; 861 return true;
888 }
889 } 862 }
890 863
891 if (nick_len) { 864 if (nick_len) {
@@ -898,25 +871,29 @@ static int setnick(Group_Chats *g_c, uint32_t groupnumber, int peer_index, const
898 g_c->peer_name_callback(g_c->m, groupnumber, peer_index, nick, nick_len, userdata); 871 g_c->peer_name_callback(g_c->m, groupnumber, peer_index, nick, nick_len, userdata);
899 } 872 }
900 873
901 return 0; 874 return true;
902} 875}
903 876
904static int settitle(Group_Chats *g_c, uint32_t groupnumber, int peer_index, const uint8_t *title, uint8_t title_len, 877/* Set the title for a group.
905 void *userdata) 878 *
879 * return true on success.
880 */
881static bool settitle(Group_Chats *g_c, uint32_t groupnumber, int peer_index, const uint8_t *title, uint8_t title_len,
882 void *userdata)
906{ 883{
907 if (title_len > MAX_NAME_LENGTH || title_len == 0) { 884 if (title_len > MAX_NAME_LENGTH || title_len == 0) {
908 return -1; 885 return false;
909 } 886 }
910 887
911 Group_c *g = get_group_c(g_c, groupnumber); 888 Group_c *g = get_group_c(g_c, groupnumber);
912 889
913 if (!g) { 890 if (!g) {
914 return -1; 891 return false;
915 } 892 }
916 893
917 /* same as already set? */
918 if (g->title_len == title_len && !memcmp(g->title, title, title_len)) { 894 if (g->title_len == title_len && !memcmp(g->title, title, title_len)) {
919 return 0; 895 /* same title as already set */
896 return true;
920 } 897 }
921 898
922 memcpy(g->title, title, title_len); 899 memcpy(g->title, title, title_len);
@@ -928,7 +905,7 @@ static int settitle(Group_Chats *g_c, uint32_t groupnumber, int peer_index, cons
928 g_c->title_callback(g_c->m, groupnumber, peer_index, title, title_len, userdata); 905 g_c->title_callback(g_c->m, groupnumber, peer_index, title, title_len, userdata);
929 } 906 }
930 907
931 return 0; 908 return true;
932} 909}
933 910
934/* Check if the group has no online connection, and freeze all peers if so */ 911/* Check if the group has no online connection, and freeze all peers if so */
@@ -941,7 +918,7 @@ static void check_disconnected(Group_Chats *g_c, uint32_t groupnumber, void *use
941 } 918 }
942 919
943 for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { 920 for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
944 if (g->close[i].type == GROUPCHAT_CLOSE_ONLINE) { 921 if (g->connections[i].type == GROUPCHAT_CONNECTION_ONLINE) {
945 return; 922 return;
946 } 923 }
947 } 924 }
@@ -953,7 +930,8 @@ static void check_disconnected(Group_Chats *g_c, uint32_t groupnumber, void *use
953 } 930 }
954} 931}
955 932
956static void set_conns_type_close(Group_Chats *g_c, uint32_t groupnumber, int friendcon_id, uint8_t type, void *userdata) 933static void set_conns_type_connections(Group_Chats *g_c, uint32_t groupnumber, int friendcon_id, uint8_t type,
934 void *userdata)
957{ 935{
958 Group_c *g = get_group_c(g_c, groupnumber); 936 Group_c *g = get_group_c(g_c, groupnumber);
959 937
@@ -961,30 +939,29 @@ static void set_conns_type_close(Group_Chats *g_c, uint32_t groupnumber, int fri
961 return; 939 return;
962 } 940 }
963 941
964 uint32_t i; 942 for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
965 943 if (g->connections[i].type == GROUPCHAT_CONNECTION_NONE) {
966 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
967 if (g->close[i].type == GROUPCHAT_CLOSE_NONE) {
968 continue; 944 continue;
969 } 945 }
970 946
971 if (g->close[i].number != (unsigned int)friendcon_id) { 947 if (g->connections[i].number != (unsigned int)friendcon_id) {
972 continue; 948 continue;
973 } 949 }
974 950
975 if (type == GROUPCHAT_CLOSE_ONLINE) { 951 if (type == GROUPCHAT_CONNECTION_ONLINE) {
976 send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->type, g->id); 952 send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->type, g->id);
977 } else { 953 } else {
978 g->close[i].type = type; 954 g->connections[i].type = type;
979 check_disconnected(g_c, groupnumber, userdata); 955 check_disconnected(g_c, groupnumber, userdata);
980 } 956 }
981 } 957 }
982} 958}
983/* Set the type for all close connections with friendcon_id */ 959
960/* Set the type for all connections with friendcon_id */
984static void set_conns_status_groups(Group_Chats *g_c, int friendcon_id, uint8_t type, void *userdata) 961static void set_conns_status_groups(Group_Chats *g_c, int friendcon_id, uint8_t type, void *userdata)
985{ 962{
986 for (uint16_t i = 0; i < g_c->num_chats; ++i) { 963 for (uint16_t i = 0; i < g_c->num_chats; ++i) {
987 set_conns_type_close(g_c, i, friendcon_id, type, userdata); 964 set_conns_type_connections(g_c, i, friendcon_id, type, userdata);
988 } 965 }
989} 966}
990 967
@@ -1002,7 +979,7 @@ static void rejoin_frozen_friend(Group_Chats *g_c, int friendcon_id)
1002 979
1003 for (uint32_t j = 0; j < g->numfrozen; ++j) { 980 for (uint32_t j = 0; j < g->numfrozen; ++j) {
1004 if (id_equal(g->frozen[j].real_pk, real_pk)) { 981 if (id_equal(g->frozen[j].real_pk, real_pk)) {
1005 try_send_rejoin(g_c, i, real_pk); 982 try_send_rejoin(g_c, g, real_pk);
1006 break; 983 break;
1007 } 984 }
1008 } 985 }
@@ -1025,9 +1002,9 @@ static int g_handle_status(void *object, int friendcon_id, uint8_t status, void
1025 Group_Chats *g_c = (Group_Chats *)object; 1002 Group_Chats *g_c = (Group_Chats *)object;
1026 1003
1027 if (status) { /* Went online */ 1004 if (status) { /* Went online */
1028 set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_ONLINE, userdata); 1005 set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CONNECTION_ONLINE, userdata);
1029 } else { /* Went offline */ 1006 } else { /* Went offline */
1030 set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_CONNECTION, userdata); 1007 set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CONNECTION_CONNECTING, userdata);
1031 // TODO(irungentoo): remove timedout connections? 1008 // TODO(irungentoo): remove timedout connections?
1032 } 1009 }
1033 1010
@@ -1039,55 +1016,49 @@ static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uin
1039 1016
1040/* Add friend to group chat. 1017/* Add friend to group chat.
1041 * 1018 *
1042 * return close index on success 1019 * return connections index on success
1043 * return -1 on failure. 1020 * return -1 on failure.
1044 */ 1021 */
1045static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, uint32_t groupnumber, uint8_t reason, 1022static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, Group_c *g, uint8_t reason,
1046 uint8_t lock) 1023 uint8_t lock)
1047{ 1024{
1048 Group_c *g = get_group_c(g_c, groupnumber);
1049
1050 if (!g) {
1051 return -1;
1052 }
1053
1054 uint16_t empty = MAX_GROUP_CONNECTIONS; 1025 uint16_t empty = MAX_GROUP_CONNECTIONS;
1055 uint16_t ind = MAX_GROUP_CONNECTIONS; 1026 uint16_t ind = MAX_GROUP_CONNECTIONS;
1056 1027
1057 for (uint16_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { 1028 for (uint16_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
1058 if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { 1029 if (g->connections[i].type == GROUPCHAT_CONNECTION_NONE) {
1059 empty = i; 1030 empty = i;
1060 continue; 1031 continue;
1061 } 1032 }
1062 1033
1063 if (g->close[i].number == (uint32_t)friendcon_id) { 1034 if (g->connections[i].number == (uint32_t)friendcon_id) {
1064 ind = i; /* Already in list. */ 1035 ind = i; /* Already in list. */
1065 break; 1036 break;
1066 } 1037 }
1067 } 1038 }
1068 1039
1069 if (ind == MAX_GROUP_CONNECTIONS && empty != MAX_GROUP_CONNECTIONS) { 1040 if (ind == MAX_GROUP_CONNECTIONS) {
1041 if (empty == MAX_GROUP_CONNECTIONS) {
1042 return -1;
1043 }
1044
1070 if (lock) { 1045 if (lock) {
1071 friend_connection_lock(g_c->fr_c, friendcon_id); 1046 friend_connection_lock(g_c->fr_c, friendcon_id);
1072 } 1047 }
1073 1048
1074 g->close[empty].type = GROUPCHAT_CLOSE_CONNECTION; 1049 g->connections[empty].type = GROUPCHAT_CONNECTION_CONNECTING;
1075 g->close[empty].number = friendcon_id; 1050 g->connections[empty].number = friendcon_id;
1076 g->close[empty].reasons = 0; 1051 g->connections[empty].reasons = 0;
1077 // TODO(irungentoo): 1052 // TODO(irungentoo):
1078 friend_connection_callbacks(g_c->m->fr_c, friendcon_id, GROUPCHAT_CALLBACK_INDEX, &g_handle_status, &g_handle_packet, 1053 friend_connection_callbacks(g_c->m->fr_c, friendcon_id, GROUPCHAT_CALLBACK_INDEX, &g_handle_status, &g_handle_packet,
1079 &handle_lossy, g_c, friendcon_id); 1054 &handle_lossy, g_c, friendcon_id);
1080 ind = empty; 1055 ind = empty;
1081 } 1056 }
1082 1057
1083 if (ind == MAX_GROUP_CONNECTIONS) { 1058 if (!(g->connections[ind].reasons & reason)) {
1084 return -1; 1059 g->connections[ind].reasons |= reason;
1085 }
1086 1060
1087 if (!(g->close[ind].reasons & reason)) { 1061 if (reason == GROUPCHAT_CONNECTION_REASON_INTRODUCER) {
1088 g->close[ind].reasons |= reason;
1089
1090 if (reason == GROUPCHAT_CLOSE_REASON_INTRODUCER) {
1091 ++g->num_introducer_connections; 1062 ++g->num_introducer_connections;
1092 } 1063 }
1093 } 1064 }
@@ -1101,31 +1072,25 @@ static unsigned int send_peer_introduced(Group_Chats *g_c, int friendcon_id, uin
1101 * 1072 *
1102 * Kills connection if this was the last reason. 1073 * Kills connection if this was the last reason.
1103 */ 1074 */
1104static void remove_conn_reason(Group_Chats *g_c, uint32_t groupnumber, uint16_t i, uint8_t reason) 1075static void remove_connection_reason(Group_Chats *g_c, Group_c *g, uint16_t i, uint8_t reason)
1105{ 1076{
1106 Group_c *g = get_group_c(g_c, groupnumber); 1077 if (!(g->connections[i].reasons & reason)) {
1107
1108 if (!g) {
1109 return;
1110 }
1111
1112 if (!(g->close[i].reasons & reason)) {
1113 return; 1078 return;
1114 } 1079 }
1115 1080
1116 g->close[i].reasons &= ~reason; 1081 g->connections[i].reasons &= ~reason;
1117 1082
1118 if (reason == GROUPCHAT_CLOSE_REASON_INTRODUCER) { 1083 if (reason == GROUPCHAT_CONNECTION_REASON_INTRODUCER) {
1119 --g->num_introducer_connections; 1084 --g->num_introducer_connections;
1120 1085
1121 if (g->close[i].type == GROUPCHAT_CLOSE_ONLINE) { 1086 if (g->connections[i].type == GROUPCHAT_CONNECTION_ONLINE) {
1122 send_peer_introduced(g_c, g->close[i].number, g->close[i].group_number); 1087 send_peer_introduced(g_c, g->connections[i].number, g->connections[i].group_number);
1123 } 1088 }
1124 } 1089 }
1125 1090
1126 if (g->close[i].reasons == 0) { 1091 if (g->connections[i].reasons == 0) {
1127 kill_friend_connection(g_c->fr_c, g->close[i].number); 1092 kill_friend_connection(g_c->fr_c, g->connections[i].number);
1128 g->close[i].type = GROUPCHAT_CLOSE_NONE; 1093 g->connections[i].type = GROUPCHAT_CONNECTION_NONE;
1129 } 1094 }
1130} 1095}
1131 1096
@@ -1182,12 +1147,12 @@ int del_groupchat(Group_Chats *g_c, uint32_t groupnumber, bool leave_permanently
1182 group_leave(g_c, groupnumber, leave_permanently); 1147 group_leave(g_c, groupnumber, leave_permanently);
1183 1148
1184 for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { 1149 for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
1185 if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { 1150 if (g->connections[i].type == GROUPCHAT_CONNECTION_NONE) {
1186 continue; 1151 continue;
1187 } 1152 }
1188 1153
1189 g->close[i].type = GROUPCHAT_CLOSE_NONE; 1154 g->connections[i].type = GROUPCHAT_CONNECTION_NONE;
1190 kill_friend_connection(g_c->fr_c, g->close[i].number); 1155 kill_friend_connection(g_c->fr_c, g->connections[i].number);
1191 } 1156 }
1192 1157
1193 for (uint32_t i = 0; i < g->numpeers; ++i) { 1158 for (uint32_t i = 0; i < g->numpeers; ++i) {
@@ -1206,6 +1171,19 @@ int del_groupchat(Group_Chats *g_c, uint32_t groupnumber, bool leave_permanently
1206 return wipe_group_chat(g_c, groupnumber); 1171 return wipe_group_chat(g_c, groupnumber);
1207} 1172}
1208 1173
1174static const Group_Peer *peer_in_list(const Group_c *g, uint32_t peernumber, bool frozen)
1175{
1176 const Group_Peer *list = frozen ? g->frozen : g->group;
1177 const uint32_t num = frozen ? g->numfrozen : g->numpeers;
1178
1179 if (peernumber >= num) {
1180 return nullptr;
1181 }
1182
1183 return &list[peernumber];
1184}
1185
1186
1209/* Copy the public key of (frozen, if frozen is true) peernumber who is in 1187/* Copy the public key of (frozen, if frozen is true) peernumber who is in
1210 * groupnumber to pk. pk must be CRYPTO_PUBLIC_KEY_SIZE long. 1188 * groupnumber to pk. pk must be CRYPTO_PUBLIC_KEY_SIZE long.
1211 * 1189 *
@@ -1213,7 +1191,7 @@ int del_groupchat(Group_Chats *g_c, uint32_t groupnumber, bool leave_permanently
1213 * return -1 if groupnumber is invalid. 1191 * return -1 if groupnumber is invalid.
1214 * return -2 if peernumber is invalid. 1192 * return -2 if peernumber is invalid.
1215 */ 1193 */
1216int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *pk, bool frozen) 1194int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, uint8_t *pk, bool frozen)
1217{ 1195{
1218 const Group_c *g = get_group_c(g_c, groupnumber); 1196 const Group_c *g = get_group_c(g_c, groupnumber);
1219 1197
@@ -1221,14 +1199,13 @@ int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, int peernumb
1221 return -1; 1199 return -1;
1222 } 1200 }
1223 1201
1224 const Group_Peer *list = frozen ? g->frozen : g->group; 1202 const Group_Peer *peer = peer_in_list(g, peernumber, frozen);
1225 const uint32_t num = frozen ? g->numfrozen : g->numpeers;
1226 1203
1227 if ((uint32_t)peernumber >= num) { 1204 if (peer == nullptr) {
1228 return -2; 1205 return -2;
1229 } 1206 }
1230 1207
1231 memcpy(pk, list[peernumber].real_pk, CRYPTO_PUBLIC_KEY_SIZE); 1208 memcpy(pk, peer->real_pk, CRYPTO_PUBLIC_KEY_SIZE);
1232 return 0; 1209 return 0;
1233} 1210}
1234 1211
@@ -1238,7 +1215,7 @@ int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, int peernumb
1238 * return -1 if groupnumber is invalid. 1215 * return -1 if groupnumber is invalid.
1239 * return -2 if peernumber is invalid. 1216 * return -2 if peernumber is invalid.
1240 */ 1217 */
1241int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, bool frozen) 1218int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, bool frozen)
1242{ 1219{
1243 const Group_c *g = get_group_c(g_c, groupnumber); 1220 const Group_c *g = get_group_c(g_c, groupnumber);
1244 1221
@@ -1246,18 +1223,13 @@ int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, int peernu
1246 return -1; 1223 return -1;
1247 } 1224 }
1248 1225
1249 const Group_Peer *list = frozen ? g->frozen : g->group; 1226 const Group_Peer *peer = peer_in_list(g, peernumber, frozen);
1250 const uint32_t num = frozen ? g->numfrozen : g->numpeers;
1251 1227
1252 if ((uint32_t)peernumber >= num) { 1228 if (peer == nullptr) {
1253 return -2; 1229 return -2;
1254 } 1230 }
1255 1231
1256 if (list[peernumber].nick_len == 0) { 1232 return peer->nick_len;
1257 return 0;
1258 }
1259
1260 return list[peernumber].nick_len;
1261} 1233}
1262 1234
1263/* Copy the name of (frozen, if frozen is true) peernumber who is in 1235/* Copy the name of (frozen, if frozen is true) peernumber who is in
@@ -1267,7 +1239,7 @@ int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, int peernu
1267 * return -1 if groupnumber is invalid. 1239 * return -1 if groupnumber is invalid.
1268 * return -2 if peernumber is invalid. 1240 * return -2 if peernumber is invalid.
1269 */ 1241 */
1270int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *name, bool frozen) 1242int group_peername(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, uint8_t *name, bool frozen)
1271{ 1243{
1272 const Group_c *g = get_group_c(g_c, groupnumber); 1244 const Group_c *g = get_group_c(g_c, groupnumber);
1273 1245
@@ -1275,19 +1247,17 @@ int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber,
1275 return -1; 1247 return -1;
1276 } 1248 }
1277 1249
1278 const Group_Peer *list = frozen ? g->frozen : g->group; 1250 const Group_Peer *peer = peer_in_list(g, peernumber, frozen);
1279 const uint32_t num = frozen ? g->numfrozen : g->numpeers;
1280 1251
1281 if ((uint32_t)peernumber >= num) { 1252 if (peer == nullptr) {
1282 return -2; 1253 return -2;
1283 } 1254 }
1284 1255
1285 if (list[peernumber].nick_len == 0) { 1256 if (peer->nick_len > 0) {
1286 return 0; 1257 memcpy(name, peer->nick, peer->nick_len);
1287 } 1258 }
1288 1259
1289 memcpy(name, list[peernumber].nick, list[peernumber].nick_len); 1260 return peer->nick_len;
1290 return list[peernumber].nick_len;
1291} 1261}
1292 1262
1293/* Copy last active timestamp of frozennumber who is in groupnumber to 1263/* Copy last active timestamp of frozennumber who is in groupnumber to
@@ -1297,7 +1267,7 @@ int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber,
1297 * return -1 if groupnumber is invalid. 1267 * return -1 if groupnumber is invalid.
1298 * return -2 if frozennumber is invalid. 1268 * return -2 if frozennumber is invalid.
1299 */ 1269 */
1300int group_frozen_last_active(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, 1270int group_frozen_last_active(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber,
1301 uint64_t *last_active) 1271 uint64_t *last_active)
1302{ 1272{
1303 const Group_c *g = get_group_c(g_c, groupnumber); 1273 const Group_c *g = get_group_c(g_c, groupnumber);
@@ -1306,7 +1276,7 @@ int group_frozen_last_active(const Group_Chats *g_c, uint32_t groupnumber, int p
1306 return -1; 1276 return -1;
1307 } 1277 }
1308 1278
1309 if ((uint32_t)peernumber >= g->numfrozen) { 1279 if (peernumber >= g->numfrozen) {
1310 return -2; 1280 return -2;
1311 } 1281 }
1312 1282
@@ -1383,7 +1353,7 @@ int group_number_peers(const Group_Chats *g_c, uint32_t groupnumber, bool frozen
1383 * return -2 if peernumber is invalid. 1353 * return -2 if peernumber is invalid.
1384 * return -3 if we are not connected to the group chat. 1354 * return -3 if we are not connected to the group chat.
1385 */ 1355 */
1386int group_peernumber_is_ours(const Group_Chats *g_c, uint32_t groupnumber, int peernumber) 1356int group_peernumber_is_ours(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber)
1387{ 1357{
1388 const Group_c *g = get_group_c(g_c, groupnumber); 1358 const Group_c *g = get_group_c(g_c, groupnumber);
1389 1359
@@ -1391,7 +1361,7 @@ int group_peernumber_is_ours(const Group_Chats *g_c, uint32_t groupnumber, int p
1391 return -1; 1361 return -1;
1392 } 1362 }
1393 1363
1394 if ((uint32_t)peernumber >= g->numpeers) { 1364 if (peernumber >= g->numpeers) {
1395 return -2; 1365 return -2;
1396 } 1366 }
1397 1367
@@ -1517,14 +1487,8 @@ int invite_friend(Group_Chats *g_c, uint32_t friendnumber, uint32_t groupnumber)
1517 * return true if a packet was sent. 1487 * return true if a packet was sent.
1518 * return false otherwise. 1488 * return false otherwise.
1519 */ 1489 */
1520static bool try_send_rejoin(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk) 1490static bool try_send_rejoin(Group_Chats *g_c, Group_c *g, const uint8_t *real_pk)
1521{ 1491{
1522 Group_c *g = get_group_c(g_c, groupnumber);
1523
1524 if (!g) {
1525 return false;
1526 }
1527
1528 const int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, real_pk); 1492 const int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, real_pk);
1529 1493
1530 if (friendcon_id == -1) { 1494 if (friendcon_id == -1) {
@@ -1541,16 +1505,17 @@ static bool try_send_rejoin(Group_Chats *g_c, uint32_t groupnumber, const uint8_
1541 return false; 1505 return false;
1542 } 1506 }
1543 1507
1544 add_conn_to_groupchat(g_c, friendcon_id, groupnumber, GROUPCHAT_CLOSE_REASON_INTRODUCER, 1); 1508 add_conn_to_groupchat(g_c, friendcon_id, g, GROUPCHAT_CONNECTION_REASON_INTRODUCER, 1);
1545 1509
1546 return true; 1510 return true;
1547} 1511}
1548 1512
1549static unsigned int send_peer_query(Group_Chats *g_c, int friendcon_id, uint16_t group_num); 1513static unsigned int send_peer_query(Group_Chats *g_c, int friendcon_id, uint16_t group_num);
1550 1514
1551/* Join a group (you need to have been invited first.) 1515/* Join a group (we need to have been invited first.)
1552 * 1516 *
1553 * expected_type is the groupchat type we expect the chat we are joining is. 1517 * expected_type is the groupchat type we expect the chat we are joining to
1518 * have.
1554 * 1519 *
1555 * return group number on success. 1520 * return group number on success.
1556 * return -1 if data length is invalid. 1521 * return -1 if data length is invalid.
@@ -1603,11 +1568,12 @@ int join_groupchat(Group_Chats *g_c, uint32_t friendnumber, uint8_t expected_typ
1603 other_groupnum = net_ntohs(other_groupnum); 1568 other_groupnum = net_ntohs(other_groupnum);
1604 g->type = data[sizeof(uint16_t)]; 1569 g->type = data[sizeof(uint16_t)];
1605 memcpy(g->id, data + sizeof(uint16_t) + 1, GROUP_ID_LENGTH); 1570 memcpy(g->id, data + sizeof(uint16_t) + 1, GROUP_ID_LENGTH);
1606 const int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnumber, GROUPCHAT_CLOSE_REASON_INTRODUCER, 1); 1571 const int connection_index = add_conn_to_groupchat(g_c, friendcon_id, g,
1572 GROUPCHAT_CONNECTION_REASON_INTRODUCER, 1);
1607 1573
1608 if (close_index != -1) { 1574 if (connection_index != -1) {
1609 g->close[close_index].group_number = other_groupnum; 1575 g->connections[connection_index].group_number = other_groupnum;
1610 g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE; 1576 g->connections[connection_index].type = GROUPCHAT_CONNECTION_ONLINE;
1611 } 1577 }
1612 1578
1613 send_peer_query(g_c, friendcon_id, other_groupnum); 1579 send_peer_query(g_c, friendcon_id, other_groupnum);
@@ -1720,21 +1686,23 @@ int callback_groupchat_delete(Group_Chats *g_c, uint32_t groupnumber, group_on_d
1720static int send_message_group(const Group_Chats *g_c, uint32_t groupnumber, uint8_t message_id, const uint8_t *data, 1686static int send_message_group(const Group_Chats *g_c, uint32_t groupnumber, uint8_t message_id, const uint8_t *data,
1721 uint16_t len); 1687 uint16_t len);
1722 1688
1723static int group_ping_send(const Group_Chats *g_c, uint32_t groupnumber) 1689/* send a ping message
1690 * return true on success
1691 */
1692static bool group_ping_send(const Group_Chats *g_c, uint32_t groupnumber)
1724{ 1693{
1725 if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_PING_ID, nullptr, 0) > 0) { 1694 if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_PING_ID, nullptr, 0) > 0) {
1726 return 0; 1695 return true;
1727 } 1696 }
1728 1697
1729 return -1; 1698 return false;
1730} 1699}
1731 1700
1732/* send a new_peer message 1701/* send a new_peer message
1733 * return 0 on success 1702 * return true on success
1734 * return -1 on failure
1735 */ 1703 */
1736static int group_new_peer_send(const Group_Chats *g_c, uint32_t groupnumber, uint16_t peer_num, const uint8_t *real_pk, 1704static bool group_new_peer_send(const Group_Chats *g_c, uint32_t groupnumber, uint16_t peer_num, const uint8_t *real_pk,
1737 uint8_t *temp_pk) 1705 uint8_t *temp_pk)
1738{ 1706{
1739 uint8_t packet[GROUP_MESSAGE_NEW_PEER_LENGTH]; 1707 uint8_t packet[GROUP_MESSAGE_NEW_PEER_LENGTH];
1740 1708
@@ -1744,10 +1712,10 @@ static int group_new_peer_send(const Group_Chats *g_c, uint32_t groupnumber, uin
1744 memcpy(packet + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE, temp_pk, CRYPTO_PUBLIC_KEY_SIZE); 1712 memcpy(packet + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE, temp_pk, CRYPTO_PUBLIC_KEY_SIZE);
1745 1713
1746 if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_NEW_PEER_ID, packet, sizeof(packet)) > 0) { 1714 if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_NEW_PEER_ID, packet, sizeof(packet)) > 0) {
1747 return 0; 1715 return true;
1748 } 1716 }
1749 1717
1750 return -1; 1718 return false;
1751} 1719}
1752 1720
1753/* send a kill_peer message 1721/* send a kill_peer message
@@ -1785,20 +1753,19 @@ static bool group_freeze_peer_send(const Group_Chats *g_c, uint32_t groupnumber,
1785} 1753}
1786 1754
1787/* send a name message 1755/* send a name message
1788 * return 0 on success 1756 * return true on success
1789 * return -1 on failure
1790 */ 1757 */
1791static int group_name_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *nick, uint16_t nick_len) 1758static bool group_name_send(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *nick, uint16_t nick_len)
1792{ 1759{
1793 if (nick_len > MAX_NAME_LENGTH) { 1760 if (nick_len > MAX_NAME_LENGTH) {
1794 return -1; 1761 return false;
1795 } 1762 }
1796 1763
1797 if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_NAME_ID, nick, nick_len) > 0) { 1764 if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_NAME_ID, nick, nick_len) > 0) {
1798 return 0; 1765 return true;
1799 } 1766 }
1800 1767
1801 return -1; 1768 return false;
1802} 1769}
1803 1770
1804/* send message to announce leaving group 1771/* send message to announce leaving group
@@ -1869,7 +1836,7 @@ int group_title_get_size(const Group_Chats *g_c, uint32_t groupnumber)
1869 return -1; 1836 return -1;
1870 } 1837 }
1871 1838
1872 if (g->title_len == 0 || g->title_len > MAX_NAME_LENGTH) { 1839 if (g->title_len > MAX_NAME_LENGTH || g->title_len == 0) {
1873 return -2; 1840 return -2;
1874 } 1841 }
1875 1842
@@ -1891,7 +1858,7 @@ int group_title_get(const Group_Chats *g_c, uint32_t groupnumber, uint8_t *title
1891 return -1; 1858 return -1;
1892 } 1859 }
1893 1860
1894 if (g->title_len == 0 || g->title_len > MAX_NAME_LENGTH) { 1861 if (g->title_len > MAX_NAME_LENGTH || g->title_len == 0) {
1895 return -2; 1862 return -2;
1896 } 1863 }
1897 1864
@@ -1901,14 +1868,14 @@ int group_title_get(const Group_Chats *g_c, uint32_t groupnumber, uint8_t *title
1901 1868
1902static bool get_peer_number(const Group_c *g, const uint8_t *real_pk, uint16_t *peer_number) 1869static bool get_peer_number(const Group_c *g, const uint8_t *real_pk, uint16_t *peer_number)
1903{ 1870{
1904 const int peer_index = peer_in_chat(g, real_pk); 1871 const int peer_index = peer_in_group(g, real_pk);
1905 1872
1906 if (peer_index >= 0) { 1873 if (peer_index >= 0) {
1907 *peer_number = g->group[peer_index].peer_number; 1874 *peer_number = g->group[peer_index].peer_number;
1908 return true; 1875 return true;
1909 } 1876 }
1910 1877
1911 const int frozen_index = frozen_in_chat(g, real_pk); 1878 const int frozen_index = frozen_in_group(g, real_pk);
1912 1879
1913 if (frozen_index >= 0) { 1880 if (frozen_index >= 0) {
1914 *peer_number = g->frozen[frozen_index].peer_number; 1881 *peer_number = g->frozen[frozen_index].peer_number;
@@ -2001,55 +1968,51 @@ static void handle_friend_invite_packet(Messenger *m, uint32_t friendnumber, con
2001 get_friendcon_public_keys(real_pk, temp_pk, g_c->fr_c, friendcon_id); 1968 get_friendcon_public_keys(real_pk, temp_pk, g_c->fr_c, friendcon_id);
2002 1969
2003 addpeer(g_c, groupnum, real_pk, temp_pk, peer_number, userdata, true, true); 1970 addpeer(g_c, groupnum, real_pk, temp_pk, peer_number, userdata, true, true);
2004 const int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnum, GROUPCHAT_CLOSE_REASON_INTRODUCING, 1); 1971 const int connection_index = add_conn_to_groupchat(g_c, friendcon_id, g,
1972 GROUPCHAT_CONNECTION_REASON_INTRODUCING, 1);
2005 1973
2006 if (close_index != -1) { 1974 if (connection_index != -1) {
2007 g->close[close_index].group_number = other_groupnum; 1975 g->connections[connection_index].group_number = other_groupnum;
2008 g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE; 1976 g->connections[connection_index].type = GROUPCHAT_CONNECTION_ONLINE;
2009 } 1977 }
2010 1978
2011 group_new_peer_send(g_c, groupnum, peer_number, real_pk, temp_pk); 1979 group_new_peer_send(g_c, groupnum, peer_number, real_pk, temp_pk);
2012 break; 1980 break;
2013 } 1981 }
2014 1982
2015
2016 default: 1983 default:
2017 return; 1984 return;
2018 } 1985 }
2019} 1986}
2020 1987
2021/* Find index of friend in the close list. 1988/* Find index of friend in the connections list.
2022 * 1989 *
2023 * returns index on success 1990 * return index on success
2024 * returns -1 on failure. 1991 * return -1 on failure.
2025 */ 1992 */
2026static int friend_in_close(const Group_c *g, int friendcon_id) 1993static int friend_in_connections(const Group_c *g, int friendcon_id)
2027{ 1994{
2028 unsigned int i; 1995 for (unsigned int i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
2029 1996 if (g->connections[i].type == GROUPCHAT_CONNECTION_NONE) {
2030 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
2031 if (g->close[i].type == GROUPCHAT_CLOSE_NONE) {
2032 continue; 1997 continue;
2033 } 1998 }
2034 1999
2035 if (g->close[i].number != (uint32_t)friendcon_id) { 2000 if (g->connections[i].number == (uint32_t)friendcon_id) {
2036 continue; 2001 return i;
2037 } 2002 }
2038
2039 return i;
2040 } 2003 }
2041 2004
2042 return -1; 2005 return -1;
2043} 2006}
2044 2007
2045/* return number of connected close connections. 2008/* return number of connections.
2046 */ 2009 */
2047static unsigned int count_close_connected(const Group_c *g) 2010static unsigned int count_connected(const Group_c *g)
2048{ 2011{
2049 unsigned int i, count = 0; 2012 unsigned int count = 0;
2050 2013
2051 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { 2014 for (unsigned int i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
2052 if (g->close[i].type == GROUPCHAT_CLOSE_ONLINE) { 2015 if (g->connections[i].type == GROUPCHAT_CONNECTION_ONLINE) {
2053 ++count; 2016 ++count;
2054 } 2017 }
2055 } 2018 }
@@ -2070,7 +2033,7 @@ static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16
2070 sizeof(packet), 0) != -1; 2033 sizeof(packet), 0) != -1;
2071} 2034}
2072 2035
2073static int ping_groupchat(Group_Chats *g_c, uint32_t groupnumber); 2036static bool ping_groupchat(Group_Chats *g_c, uint32_t groupnumber);
2074 2037
2075static int handle_packet_online(Group_Chats *g_c, int friendcon_id, const uint8_t *data, uint16_t length) 2038static int handle_packet_online(Group_Chats *g_c, int friendcon_id, const uint8_t *data, uint16_t length)
2076{ 2039{
@@ -2094,29 +2057,29 @@ static int handle_packet_online(Group_Chats *g_c, int friendcon_id, const uint8_
2094 return -1; 2057 return -1;
2095 } 2058 }
2096 2059
2097 const int index = friend_in_close(g, friendcon_id); 2060 const int index = friend_in_connections(g, friendcon_id);
2098 2061
2099 if (index == -1) { 2062 if (index == -1) {
2100 return -1; 2063 return -1;
2101 } 2064 }
2102 2065
2103 if (g->close[index].type == GROUPCHAT_CLOSE_ONLINE) { 2066 if (g->connections[index].type == GROUPCHAT_CONNECTION_ONLINE) {
2104 return -1; 2067 return -1;
2105 } 2068 }
2106 2069
2107 if (count_close_connected(g) == 0 || (g->close[index].reasons & GROUPCHAT_CLOSE_REASON_INTRODUCER)) { 2070 if (count_connected(g) == 0 || (g->connections[index].reasons & GROUPCHAT_CONNECTION_REASON_INTRODUCER)) {
2108 send_peer_query(g_c, friendcon_id, other_groupnum); 2071 send_peer_query(g_c, friendcon_id, other_groupnum);
2109 } 2072 }
2110 2073
2111 g->close[index].group_number = other_groupnum; 2074 g->connections[index].group_number = other_groupnum;
2112 g->close[index].type = GROUPCHAT_CLOSE_ONLINE; 2075 g->connections[index].type = GROUPCHAT_CONNECTION_ONLINE;
2113 send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->type, g->id); 2076 send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->type, g->id);
2114 2077
2115 if (g->close[index].reasons & GROUPCHAT_CLOSE_REASON_INTRODUCING) { 2078 if (g->connections[index].reasons & GROUPCHAT_CONNECTION_REASON_INTRODUCING) {
2116 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE], temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; 2079 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE], temp_pk[CRYPTO_PUBLIC_KEY_SIZE];
2117 get_friendcon_public_keys(real_pk, temp_pk, g_c->fr_c, friendcon_id); 2080 get_friendcon_public_keys(real_pk, temp_pk, g_c->fr_c, friendcon_id);
2118 2081
2119 const int peer_index = peer_in_chat(g, real_pk); 2082 const int peer_index = peer_in_group(g, real_pk);
2120 2083
2121 if (peer_index != -1) { 2084 if (peer_index != -1) {
2122 group_new_peer_send(g_c, groupnumber, g->group[peer_index].peer_number, real_pk, temp_pk); 2085 group_new_peer_send(g_c, groupnumber, g->group[peer_index].peer_number, real_pk, temp_pk);
@@ -2139,7 +2102,7 @@ static int handle_packet_rejoin(Group_Chats *g_c, int friendcon_id, const uint8_
2139 2102
2140 const int32_t groupnum = get_group_num(g_c, *data, data + 1); 2103 const int32_t groupnum = get_group_num(g_c, *data, data + 1);
2141 2104
2142 const Group_c *g = get_group_c(g_c, groupnum); 2105 Group_c *g = get_group_c(g_c, groupnum);
2143 2106
2144 if (!g) { 2107 if (!g) {
2145 return -1; 2108 return -1;
@@ -2155,9 +2118,10 @@ static int handle_packet_rejoin(Group_Chats *g_c, int friendcon_id, const uint8_
2155 } 2118 }
2156 2119
2157 addpeer(g_c, groupnum, real_pk, temp_pk, peer_number, userdata, true, true); 2120 addpeer(g_c, groupnum, real_pk, temp_pk, peer_number, userdata, true, true);
2158 const int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnum, GROUPCHAT_CLOSE_REASON_INTRODUCING, 1); 2121 const int connection_index = add_conn_to_groupchat(g_c, friendcon_id, g,
2122 GROUPCHAT_CONNECTION_REASON_INTRODUCING, 1);
2159 2123
2160 if (close_index != -1) { 2124 if (connection_index != -1) {
2161 send_packet_online(g_c->fr_c, friendcon_id, groupnum, g->type, g->id); 2125 send_packet_online(g_c->fr_c, friendcon_id, groupnum, g->type, g->id);
2162 } 2126 }
2163 2127
@@ -2191,24 +2155,18 @@ static unsigned int send_peer_query(Group_Chats *g_c, int friendcon_id, uint16_t
2191/* return number of peers sent on success. 2155/* return number of peers sent on success.
2192 * return 0 on failure. 2156 * return 0 on failure.
2193 */ 2157 */
2194static unsigned int send_peers(Group_Chats *g_c, uint32_t groupnumber, int friendcon_id, uint16_t group_num) 2158static unsigned int send_peers(Group_Chats *g_c, const Group_c *g, int friendcon_id, uint16_t group_num)
2195{ 2159{
2196 const Group_c *g = get_group_c(g_c, groupnumber);
2197
2198 if (!g) {
2199 return 0;
2200 }
2201
2202 uint8_t response_packet[MAX_CRYPTO_DATA_SIZE - (1 + sizeof(uint16_t))]; 2160 uint8_t response_packet[MAX_CRYPTO_DATA_SIZE - (1 + sizeof(uint16_t))];
2203 response_packet[0] = PEER_RESPONSE_ID; 2161 response_packet[0] = PEER_RESPONSE_ID;
2204 uint8_t *p = response_packet + 1; 2162 uint8_t *p = response_packet + 1;
2205 2163
2206 uint16_t sent = 0; 2164 uint16_t sent = 0;
2207 uint32_t i;
2208 2165
2209 for (i = 0; i < g->numpeers; ++i) { 2166 for (uint32_t i = 0;; ++i) {
2210 if ((p - response_packet) + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE * 2 + 1 + g->group[i].nick_len > sizeof( 2167 if (i == g->numpeers
2211 response_packet)) { 2168 || (p - response_packet) + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE * 2 + 1 + g->group[i].nick_len >
2169 sizeof(response_packet)) {
2212 if (send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_CONFERENCE, group_num, response_packet, 2170 if (send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_CONFERENCE, group_num, response_packet,
2213 (p - response_packet))) { 2171 (p - response_packet))) {
2214 sent = i; 2172 sent = i;
@@ -2216,6 +2174,10 @@ static unsigned int send_peers(Group_Chats *g_c, uint32_t groupnumber, int frien
2216 return sent; 2174 return sent;
2217 } 2175 }
2218 2176
2177 if (i == g->numpeers) {
2178 break;
2179 }
2180
2219 p = response_packet + 1; 2181 p = response_packet + 1;
2220 } 2182 }
2221 2183
@@ -2232,13 +2194,6 @@ static unsigned int send_peers(Group_Chats *g_c, uint32_t groupnumber, int frien
2232 p += g->group[i].nick_len; 2194 p += g->group[i].nick_len;
2233 } 2195 }
2234 2196
2235 if (sent != i) {
2236 if (send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_CONFERENCE, group_num, response_packet,
2237 (p - response_packet))) {
2238 sent = i;
2239 }
2240 }
2241
2242 if (g->title_len) { 2197 if (g->title_len) {
2243 VLA(uint8_t, title_packet, 1 + g->title_len); 2198 VLA(uint8_t, title_packet, 1 + g->title_len);
2244 title_packet[0] = PEER_TITLE_ID; 2199 title_packet[0] = PEER_TITLE_ID;
@@ -2308,37 +2263,31 @@ static int handle_send_peers(Group_Chats *g_c, uint32_t groupnumber, const uint8
2308} 2263}
2309 2264
2310static void handle_direct_packet(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *data, uint16_t length, 2265static void handle_direct_packet(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *data, uint16_t length,
2311 int close_index, void *userdata) 2266 int connection_index, void *userdata)
2312{ 2267{
2313 if (length == 0) { 2268 if (length == 0) {
2314 return; 2269 return;
2315 } 2270 }
2316 2271
2317 switch (data[0]) { 2272 Group_c *g = get_group_c(g_c, groupnumber);
2318 case PEER_INTRODUCED_ID: {
2319 const Group_c *g = get_group_c(g_c, groupnumber);
2320 2273
2321 if (!g) { 2274 if (!g) {
2322 return; 2275 return;
2323 } 2276 }
2324 2277
2325 remove_conn_reason(g_c, groupnumber, close_index, GROUPCHAT_CLOSE_REASON_INTRODUCING); 2278 switch (data[0]) {
2279 case PEER_INTRODUCED_ID: {
2280 remove_connection_reason(g_c, g, connection_index, GROUPCHAT_CONNECTION_REASON_INTRODUCING);
2326 } 2281 }
2327 2282
2328 break; 2283 break;
2329 2284
2330 case PEER_QUERY_ID: { 2285 case PEER_QUERY_ID: {
2331 const Group_c *g = get_group_c(g_c, groupnumber); 2286 if (g->connections[connection_index].type != GROUPCHAT_CONNECTION_ONLINE) {
2332
2333 if (!g) {
2334 return;
2335 }
2336
2337 if (g->close[close_index].type != GROUPCHAT_CLOSE_ONLINE) {
2338 return; 2287 return;
2339 } 2288 }
2340 2289
2341 send_peers(g_c, groupnumber, g->close[close_index].number, g->close[close_index].group_number); 2290 send_peers(g_c, g, g->connections[connection_index].number, g->connections[connection_index].group_number);
2342 } 2291 }
2343 2292
2344 break; 2293 break;
@@ -2350,12 +2299,6 @@ static void handle_direct_packet(Group_Chats *g_c, uint32_t groupnumber, const u
2350 break; 2299 break;
2351 2300
2352 case PEER_TITLE_ID: { 2301 case PEER_TITLE_ID: {
2353 const Group_c *g = get_group_c(g_c, groupnumber);
2354
2355 if (!g) {
2356 break;
2357 }
2358
2359 if (!g->title_fresh) { 2302 if (!g->title_fresh) {
2360 settitle(g_c, groupnumber, -1, data + 1, length - 1, userdata); 2303 settitle(g_c, groupnumber, -1, data + 1, length - 1, userdata);
2361 } 2304 }
@@ -2365,24 +2308,18 @@ static void handle_direct_packet(Group_Chats *g_c, uint32_t groupnumber, const u
2365 } 2308 }
2366} 2309}
2367 2310
2368/* Send message to all close except receiver (if receiver isn't -1) 2311/* Send message to all connections except receiver (if receiver isn't -1)
2369 * NOTE: this function appends the group chat number to the data passed to it. 2312 * NOTE: this function appends the group chat number to the data passed to it.
2370 * 2313 *
2371 * return number of messages sent. 2314 * return number of messages sent.
2372 */ 2315 */
2373static unsigned int send_message_all_close(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *data, 2316static unsigned int send_message_all_connections(const Group_Chats *g_c, const Group_c *g, const uint8_t *data,
2374 uint16_t length, int receiver) 2317 uint16_t length, int receiver)
2375{ 2318{
2376 const Group_c *g = get_group_c(g_c, groupnumber); 2319 uint16_t sent = 0;
2377
2378 if (!g) {
2379 return 0;
2380 }
2381
2382 uint16_t i, sent = 0;
2383 2320
2384 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { 2321 for (uint16_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
2385 if (g->close[i].type != GROUPCHAT_CLOSE_ONLINE) { 2322 if (g->connections[i].type != GROUPCHAT_CONNECTION_ONLINE) {
2386 continue; 2323 continue;
2387 } 2324 }
2388 2325
@@ -2390,8 +2327,8 @@ static unsigned int send_message_all_close(const Group_Chats *g_c, uint32_t grou
2390 continue; 2327 continue;
2391 } 2328 }
2392 2329
2393 if (send_packet_group_peer(g_c->fr_c, g->close[i].number, PACKET_ID_MESSAGE_CONFERENCE, g->close[i].group_number, data, 2330 if (send_packet_group_peer(g_c->fr_c, g->connections[i].number, PACKET_ID_MESSAGE_CONFERENCE,
2394 length)) { 2331 g->connections[i].group_number, data, length)) {
2395 ++sent; 2332 ++sent;
2396 } 2333 }
2397 } 2334 }
@@ -2399,25 +2336,19 @@ static unsigned int send_message_all_close(const Group_Chats *g_c, uint32_t grou
2399 return sent; 2336 return sent;
2400} 2337}
2401 2338
2402/* Send lossy message to all close except receiver (if receiver isn't -1) 2339/* Send lossy message to all connections except receiver (if receiver isn't -1)
2403 * NOTE: this function appends the group chat number to the data passed to it. 2340 * NOTE: this function appends the group chat number to the data passed to it.
2404 * 2341 *
2405 * return number of messages sent. 2342 * return number of messages sent.
2406 */ 2343 */
2407static unsigned int send_lossy_all_close(const Group_Chats *g_c, uint32_t groupnumber, const uint8_t *data, 2344static unsigned int send_lossy_all_connections(const Group_Chats *g_c, const Group_c *g, const uint8_t *data,
2408 uint16_t length, 2345 uint16_t length,
2409 int receiver) 2346 int receiver)
2410{ 2347{
2411 const Group_c *g = get_group_c(g_c, groupnumber); 2348 unsigned int sent = 0, num_connected_closest = 0, connected_closest[DESIRED_CLOSEST];
2412 2349
2413 if (!g) { 2350 for (unsigned int i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
2414 return 0; 2351 if (g->connections[i].type != GROUPCHAT_CONNECTION_ONLINE) {
2415 }
2416
2417 unsigned int i, sent = 0, num_connected_closest = 0, connected_closest[DESIRED_CLOSE_CONNECTIONS];
2418
2419 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
2420 if (g->close[i].type != GROUPCHAT_CLOSE_ONLINE) {
2421 continue; 2352 continue;
2422 } 2353 }
2423 2354
@@ -2425,14 +2356,14 @@ static unsigned int send_lossy_all_close(const Group_Chats *g_c, uint32_t groupn
2425 continue; 2356 continue;
2426 } 2357 }
2427 2358
2428 if (g->close[i].reasons & GROUPCHAT_CLOSE_REASON_CLOSEST) { 2359 if (g->connections[i].reasons & GROUPCHAT_CONNECTION_REASON_CLOSEST) {
2429 connected_closest[num_connected_closest] = i; 2360 connected_closest[num_connected_closest] = i;
2430 ++num_connected_closest; 2361 ++num_connected_closest;
2431 continue; 2362 continue;
2432 } 2363 }
2433 2364
2434 if (send_lossy_group_peer(g_c->fr_c, g->close[i].number, PACKET_ID_LOSSY_CONFERENCE, g->close[i].group_number, data, 2365 if (send_lossy_group_peer(g_c->fr_c, g->connections[i].number, PACKET_ID_LOSSY_CONFERENCE,
2435 length)) { 2366 g->connections[i].group_number, data, length)) {
2436 ++sent; 2367 ++sent;
2437 } 2368 }
2438 } 2369 }
@@ -2441,48 +2372,31 @@ static unsigned int send_lossy_all_close(const Group_Chats *g_c, uint32_t groupn
2441 return sent; 2372 return sent;
2442 } 2373 }
2443 2374
2444 unsigned int to_send = 0; 2375 unsigned int to_send[2] = {0, 0};
2445 uint64_t comp_val_old = -1; 2376 uint64_t comp_val_old[2] = {(uint64_t) -1, (uint64_t) -1};
2446 2377
2447 for (i = 0; i < num_connected_closest; ++i) { 2378 for (unsigned int i = 0; i < num_connected_closest; ++i) {
2448 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE] = {0}; 2379 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE] = {0};
2449 uint8_t dht_temp_pk[CRYPTO_PUBLIC_KEY_SIZE] = {0}; 2380 get_friendcon_public_keys(real_pk, nullptr, g_c->fr_c, g->connections[connected_closest[i]].number);
2450 get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[connected_closest[i]].number);
2451 const uint64_t comp_val = calculate_comp_value(g->real_pk, real_pk); 2381 const uint64_t comp_val = calculate_comp_value(g->real_pk, real_pk);
2452 2382
2453 if (comp_val < comp_val_old) { 2383 for (uint8_t j = 0; j < 2; ++j) {
2454 to_send = connected_closest[i]; 2384 if (j ? (comp_val > comp_val_old[j]) : (comp_val < comp_val_old[j])) {
2455 comp_val_old = comp_val; 2385 to_send[j] = connected_closest[i];
2386 comp_val_old[j] = comp_val;
2387 }
2456 } 2388 }
2457 } 2389 }
2458 2390
2459 if (send_lossy_group_peer(g_c->fr_c, g->close[to_send].number, PACKET_ID_LOSSY_CONFERENCE, 2391 for (uint8_t j = 0; j < 2; ++j) {
2460 g->close[to_send].group_number, data, length)) { 2392 if (j && to_send[1] == to_send[0]) {
2461 ++sent; 2393 break;
2462 }
2463
2464 unsigned int to_send_other = 0;
2465 comp_val_old = -1;
2466
2467 for (i = 0; i < num_connected_closest; ++i) {
2468 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE] = {0};
2469 uint8_t dht_temp_pk[CRYPTO_PUBLIC_KEY_SIZE] = {0};
2470 get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[connected_closest[i]].number);
2471 const uint64_t comp_val = calculate_comp_value(real_pk, g->real_pk);
2472
2473 if (comp_val < comp_val_old) {
2474 to_send_other = connected_closest[i];
2475 comp_val_old = comp_val;
2476 } 2394 }
2477 }
2478
2479 if (to_send_other == to_send) {
2480 return sent;
2481 }
2482 2395
2483 if (send_lossy_group_peer(g_c->fr_c, g->close[to_send_other].number, PACKET_ID_LOSSY_CONFERENCE, 2396 if (send_lossy_group_peer(g_c->fr_c, g->connections[to_send[j]].number, PACKET_ID_LOSSY_CONFERENCE,
2484 g->close[to_send_other].group_number, data, length)) { 2397 g->connections[to_send[j]].group_number, data, length)) {
2485 ++sent; 2398 ++sent;
2399 }
2486 } 2400 }
2487 2401
2488 return sent; 2402 return sent;
@@ -2509,7 +2423,7 @@ static int send_message_group(const Group_Chats *g_c, uint32_t groupnumber, uint
2509 return -2; 2423 return -2;
2510 } 2424 }
2511 2425
2512 if (g->status != GROUPCHAT_STATUS_CONNECTED || count_close_connected(g) == 0) { 2426 if (g->status != GROUPCHAT_STATUS_CONNECTED || count_connected(g) == 0) {
2513 return -3; 2427 return -3;
2514 } 2428 }
2515 2429
@@ -2532,9 +2446,13 @@ static int send_message_group(const Group_Chats *g_c, uint32_t groupnumber, uint
2532 memcpy(packet + sizeof(uint16_t) + sizeof(uint32_t) + 1, data, len); 2446 memcpy(packet + sizeof(uint16_t) + sizeof(uint32_t) + 1, data, len);
2533 } 2447 }
2534 2448
2535 unsigned int ret = send_message_all_close(g_c, groupnumber, packet, SIZEOF_VLA(packet), -1); 2449 unsigned int ret = send_message_all_connections(g_c, g, packet, SIZEOF_VLA(packet), -1);
2450
2451 if (ret == 0) {
2452 return -4;
2453 }
2536 2454
2537 return (ret == 0) ? -4 : ret; 2455 return ret;
2538} 2456}
2539 2457
2540/* send a group message 2458/* send a group message
@@ -2588,7 +2506,7 @@ int send_group_lossy_packet(const Group_Chats *g_c, uint32_t groupnumber, const
2588 memcpy(packet + sizeof(uint16_t), &message_num, sizeof(uint16_t)); 2506 memcpy(packet + sizeof(uint16_t), &message_num, sizeof(uint16_t));
2589 memcpy(packet + sizeof(uint16_t) * 2, data, length); 2507 memcpy(packet + sizeof(uint16_t) * 2, data, length);
2590 2508
2591 if (send_lossy_all_close(g_c, groupnumber, packet, SIZEOF_VLA(packet), -1) == 0) { 2509 if (send_lossy_all_connections(g_c, g, packet, SIZEOF_VLA(packet), -1) == 0) {
2592 return -1; 2510 return -1;
2593 } 2511 }
2594 2512
@@ -2649,13 +2567,13 @@ static bool check_message_info(uint32_t message_number, uint8_t message_id, Grou
2649} 2567}
2650 2568
2651static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *data, uint16_t length, 2569static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *data, uint16_t length,
2652 int close_index, void *userdata) 2570 int connection_index, void *userdata)
2653{ 2571{
2654 if (length < sizeof(uint16_t) + sizeof(uint32_t) + 1) { 2572 if (length < sizeof(uint16_t) + sizeof(uint32_t) + 1) {
2655 return; 2573 return;
2656 } 2574 }
2657 2575
2658 const Group_c *g = get_group_c(g_c, groupnumber); 2576 Group_c *g = get_group_c(g_c, groupnumber);
2659 2577
2660 if (!g) { 2578 if (!g) {
2661 return; 2579 return;
@@ -2683,32 +2601,32 @@ static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber,
2683 return; 2601 return;
2684 } 2602 }
2685 2603
2686 if (g->close[close_index].type != GROUPCHAT_CLOSE_ONLINE) { 2604 if (g->connections[connection_index].type != GROUPCHAT_CONNECTION_ONLINE) {
2687 return; 2605 return;
2688 } 2606 }
2689 2607
2690 /* If we don't know the peer this packet came from, then we query the 2608 /* If we don't know the peer this packet came from, then we query the
2691 * list of peers from the relaying peer. 2609 * list of peers from the relaying peer.
2692 * (They would not have relayed it if they didn't know the peer.) */ 2610 * (They wouldn't have relayed it if they didn't know the peer.) */
2693 send_peer_query(g_c, g->close[close_index].number, g->close[close_index].group_number); 2611 send_peer_query(g_c, g->connections[connection_index].number, g->connections[connection_index].group_number);
2694 return; 2612 return;
2695 } 2613 }
2696 2614
2697 if (g->num_introducer_connections > 0 && count_close_connected(g) > DESIRED_CLOSE_CONNECTIONS) { 2615 if (g->num_introducer_connections > 0 && count_connected(g) > DESIRED_CLOSEST) {
2698 for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { 2616 for (uint32_t i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
2699 if (g->close[i].type == GROUPCHAT_CLOSE_NONE 2617 if (g->connections[i].type == GROUPCHAT_CONNECTION_NONE
2700 || !(g->close[i].reasons & GROUPCHAT_CLOSE_REASON_INTRODUCER) 2618 || !(g->connections[i].reasons & GROUPCHAT_CONNECTION_REASON_INTRODUCER)
2701 || i == close_index) { 2619 || i == connection_index) {
2702 continue; 2620 continue;
2703 } 2621 }
2704 2622
2705 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; 2623 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE];
2706 get_friendcon_public_keys(real_pk, nullptr, g_c->fr_c, g->close[i].number); 2624 get_friendcon_public_keys(real_pk, nullptr, g_c->fr_c, g->connections[i].number);
2707 2625
2708 if (id_equal(g->group[index].real_pk, real_pk)) { 2626 if (id_equal(g->group[index].real_pk, real_pk)) {
2709 /* Received message from peer relayed via another peer, so 2627 /* Received message from peer relayed via another peer, so
2710 * the introduction was successful */ 2628 * the introduction was successful */
2711 remove_conn_reason(g_c, groupnumber, i, GROUPCHAT_CLOSE_REASON_INTRODUCER); 2629 remove_connection_reason(g_c, g, i, GROUPCHAT_CONNECTION_REASON_INTRODUCER);
2712 } 2630 }
2713 } 2631 }
2714 } 2632 }
@@ -2758,14 +2676,14 @@ static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber,
2758 break; 2676 break;
2759 2677
2760 case GROUP_MESSAGE_NAME_ID: { 2678 case GROUP_MESSAGE_NAME_ID: {
2761 if (setnick(g_c, groupnumber, index, msg_data, msg_data_len, userdata, true) == -1) { 2679 if (!setnick(g_c, groupnumber, index, msg_data, msg_data_len, userdata, true)) {
2762 return; 2680 return;
2763 } 2681 }
2764 } 2682 }
2765 break; 2683 break;
2766 2684
2767 case GROUP_MESSAGE_TITLE_ID: { 2685 case GROUP_MESSAGE_TITLE_ID: {
2768 if (settitle(g_c, groupnumber, index, msg_data, msg_data_len, userdata) == -1) { 2686 if (!settitle(g_c, groupnumber, index, msg_data, msg_data_len, userdata)) {
2769 return; 2687 return;
2770 } 2688 }
2771 } 2689 }
@@ -2814,10 +2732,10 @@ static void handle_message_packet_group(Group_Chats *g_c, uint32_t groupnumber,
2814 * are only two peers in the group), this is the only way for them to 2732 * are only two peers in the group), this is the only way for them to
2815 * receive their own message. */ 2733 * receive their own message. */
2816 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; 2734 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE];
2817 get_friendcon_public_keys(real_pk, nullptr, g_c->fr_c, g->close[close_index].number); 2735 get_friendcon_public_keys(real_pk, nullptr, g_c->fr_c, g->connections[connection_index].number);
2818 bool relay_back = id_equal(g->group[index].real_pk, real_pk); 2736 bool relay_back = id_equal(g->group[index].real_pk, real_pk);
2819 2737
2820 send_message_all_close(g_c, groupnumber, data, length, relay_back ? -1 : close_index); 2738 send_message_all_connections(g_c, g, data, length, relay_back ? -1 : connection_index);
2821} 2739}
2822 2740
2823static int g_handle_packet(void *object, int friendcon_id, const uint8_t *data, uint16_t length, void *userdata) 2741static int g_handle_packet(void *object, int friendcon_id, const uint8_t *data, uint16_t length, void *userdata)
@@ -2836,10 +2754,6 @@ static int g_handle_packet(void *object, int friendcon_id, const uint8_t *data,
2836 return handle_packet_rejoin(g_c, friendcon_id, data + 1, length - 1, userdata); 2754 return handle_packet_rejoin(g_c, friendcon_id, data + 1, length - 1, userdata);
2837 } 2755 }
2838 2756
2839 if (data[0] != PACKET_ID_DIRECT_CONFERENCE && data[0] != PACKET_ID_MESSAGE_CONFERENCE) {
2840 return -1;
2841 }
2842
2843 uint16_t groupnumber; 2757 uint16_t groupnumber;
2844 memcpy(&groupnumber, data + 1, sizeof(uint16_t)); 2758 memcpy(&groupnumber, data + 1, sizeof(uint16_t));
2845 groupnumber = net_ntohs(groupnumber); 2759 groupnumber = net_ntohs(groupnumber);
@@ -2849,30 +2763,25 @@ static int g_handle_packet(void *object, int friendcon_id, const uint8_t *data,
2849 return -1; 2763 return -1;
2850 } 2764 }
2851 2765
2852 const int index = friend_in_close(g, friendcon_id); 2766 const int index = friend_in_connections(g, friendcon_id);
2853 2767
2854 if (index == -1) { 2768 if (index == -1) {
2855 return -1; 2769 return -1;
2856 } 2770 }
2857 2771
2858 switch (data[0]) { 2772 if (data[0] == PACKET_ID_DIRECT_CONFERENCE) {
2859 case PACKET_ID_DIRECT_CONFERENCE: { 2773 handle_direct_packet(g_c, groupnumber, data + 1 + sizeof(uint16_t),
2860 handle_direct_packet(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index, userdata); 2774 length - (1 + sizeof(uint16_t)), index, userdata);
2861 break; 2775 return 0;
2862 } 2776 }
2863
2864 case PACKET_ID_MESSAGE_CONFERENCE: {
2865 handle_message_packet_group(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index,
2866 userdata);
2867 break;
2868 }
2869 2777
2870 default: { 2778 if (data[0] == PACKET_ID_MESSAGE_CONFERENCE) {
2871 return 0; 2779 handle_message_packet_group(g_c, groupnumber, data + 1 + sizeof(uint16_t),
2872 } 2780 length - (1 + sizeof(uint16_t)), index, userdata);
2781 return 0;
2873 } 2782 }
2874 2783
2875 return 0; 2784 return -1;
2876} 2785}
2877 2786
2878/* Did we already receive the lossy packet or not. 2787/* Did we already receive the lossy packet or not.
@@ -2883,10 +2792,9 @@ static int g_handle_packet(void *object, int friendcon_id, const uint8_t *data,
2883 * 2792 *
2884 * TODO(irungentoo): test this 2793 * TODO(irungentoo): test this
2885 */ 2794 */
2886static unsigned int lossy_packet_not_received(const Group_c *g, int peer_index, uint16_t message_number) 2795static int lossy_packet_not_received(const Group_c *g, int peer_index, uint16_t message_number)
2887{ 2796{
2888 if (peer_index == -1) { 2797 if (peer_index == -1) {
2889 // TODO(sudden6): invalid return value
2890 return -1; 2798 return -1;
2891 } 2799 }
2892 2800
@@ -2907,7 +2815,6 @@ static unsigned int lossy_packet_not_received(const Group_c *g, int peer_index,
2907 } 2815 }
2908 2816
2909 if ((uint16_t)(message_number - g->group[peer_index].bottom_lossy_number) > (1 << 15)) { 2817 if ((uint16_t)(message_number - g->group[peer_index].bottom_lossy_number) > (1 << 15)) {
2910 // TODO(sudden6): invalid return value
2911 return -1; 2818 return -1;
2912 } 2819 }
2913 2820
@@ -2941,11 +2848,11 @@ static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uin
2941{ 2848{
2942 Group_Chats *g_c = (Group_Chats *)object; 2849 Group_Chats *g_c = (Group_Chats *)object;
2943 2850
2944 if (length < 1 + sizeof(uint16_t) * 3 + 1) { 2851 if (data[0] != PACKET_ID_LOSSY_CONFERENCE) {
2945 return -1; 2852 return -1;
2946 } 2853 }
2947 2854
2948 if (data[0] != PACKET_ID_LOSSY_CONFERENCE) { 2855 if (length < 1 + sizeof(uint16_t) * 3 + 1) {
2949 return -1; 2856 return -1;
2950 } 2857 }
2951 2858
@@ -2967,7 +2874,7 @@ static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uin
2967 return -1; 2874 return -1;
2968 } 2875 }
2969 2876
2970 const int index = friend_in_close(g, friendcon_id); 2877 const int index = friend_in_connections(g, friendcon_id);
2971 2878
2972 if (index == -1) { 2879 if (index == -1) {
2973 return -1; 2880 return -1;
@@ -2983,7 +2890,7 @@ static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uin
2983 return -1; 2890 return -1;
2984 } 2891 }
2985 2892
2986 if (lossy_packet_not_received(g, peer_index, message_number)) { 2893 if (lossy_packet_not_received(g, peer_index, message_number) != 0) {
2987 return -1; 2894 return -1;
2988 } 2895 }
2989 2896
@@ -2993,14 +2900,14 @@ static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uin
2993 ++lossy_data; 2900 ++lossy_data;
2994 --lossy_length; 2901 --lossy_length;
2995 2902
2996 send_lossy_all_close(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index); 2903 send_lossy_all_connections(g_c, g, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index);
2997 2904
2998 if (g_c->lossy_packethandlers[message_id].function) { 2905 if (!g_c->lossy_packethandlers[message_id].function) {
2999 if (g_c->lossy_packethandlers[message_id].function(g->object, groupnumber, peer_index, g->group[peer_index].object, 2906 return -1;
3000 lossy_data, lossy_length) == -1) { 2907 }
3001 return -1; 2908
3002 } 2909 if (g_c->lossy_packethandlers[message_id].function(g->object, groupnumber, peer_index, g->group[peer_index].object,
3003 } else { 2910 lossy_data, lossy_length) == -1) {
3004 return -1; 2911 return -1;
3005 } 2912 }
3006 2913
@@ -3029,7 +2936,7 @@ int group_set_object(const Group_Chats *g_c, uint32_t groupnumber, void *object)
3029 * return 0 on success. 2936 * return 0 on success.
3030 * return -1 on failure 2937 * return -1 on failure
3031 */ 2938 */
3032int group_peer_set_object(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, void *object) 2939int group_peer_set_object(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, void *object)
3033{ 2940{
3034 const Group_c *g = get_group_c(g_c, groupnumber); 2941 const Group_c *g = get_group_c(g_c, groupnumber);
3035 2942
@@ -3037,7 +2944,7 @@ int group_peer_set_object(const Group_Chats *g_c, uint32_t groupnumber, int peer
3037 return -1; 2944 return -1;
3038 } 2945 }
3039 2946
3040 if ((uint32_t)peernumber >= g->numpeers) { 2947 if (peernumber >= g->numpeers) {
3041 return -1; 2948 return -1;
3042 } 2949 }
3043 2950
@@ -3066,7 +2973,7 @@ void *group_get_object(const Group_Chats *g_c, uint32_t groupnumber)
3066 * return NULL on failure. 2973 * return NULL on failure.
3067 * return object on success. 2974 * return object on success.
3068 */ 2975 */
3069void *group_peer_get_object(const Group_Chats *g_c, uint32_t groupnumber, int peernumber) 2976void *group_peer_get_object(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber)
3070{ 2977{
3071 const Group_c *g = get_group_c(g_c, groupnumber); 2978 const Group_c *g = get_group_c(g_c, groupnumber);
3072 2979
@@ -3074,7 +2981,7 @@ void *group_peer_get_object(const Group_Chats *g_c, uint32_t groupnumber, int pe
3074 return nullptr; 2981 return nullptr;
3075 } 2982 }
3076 2983
3077 if ((uint32_t)peernumber >= g->numpeers) { 2984 if (peernumber >= g->numpeers) {
3078 return nullptr; 2985 return nullptr;
3079 } 2986 }
3080 2987
@@ -3084,29 +2991,32 @@ void *group_peer_get_object(const Group_Chats *g_c, uint32_t groupnumber, int pe
3084/* Interval in seconds to send ping messages */ 2991/* Interval in seconds to send ping messages */
3085#define GROUP_PING_INTERVAL 20 2992#define GROUP_PING_INTERVAL 20
3086 2993
3087static int ping_groupchat(Group_Chats *g_c, uint32_t groupnumber) 2994static bool ping_groupchat(Group_Chats *g_c, uint32_t groupnumber)
3088{ 2995{
3089 Group_c *g = get_group_c(g_c, groupnumber); 2996 Group_c *g = get_group_c(g_c, groupnumber);
3090 2997
3091 if (!g) { 2998 if (!g) {
3092 return -1; 2999 return false;
3093 } 3000 }
3094 3001
3095 if (mono_time_is_timeout(g_c->mono_time, g->last_sent_ping, GROUP_PING_INTERVAL)) { 3002 if (mono_time_is_timeout(g_c->mono_time, g->last_sent_ping, GROUP_PING_INTERVAL)) {
3096 if (group_ping_send(g_c, groupnumber) != -1) { /* Ping */ 3003 if (group_ping_send(g_c, groupnumber)) {
3097 g->last_sent_ping = mono_time_get(g_c->mono_time); 3004 g->last_sent_ping = mono_time_get(g_c->mono_time);
3098 } 3005 }
3099 } 3006 }
3100 3007
3101 return 0; 3008 return true;
3102} 3009}
3103 3010
3104static int groupchat_freeze_timedout(Group_Chats *g_c, uint32_t groupnumber, void *userdata) 3011/* Seconds of inactivity after which to freeze a peer */
3012#define FREEZE_TIMEOUT (GROUP_PING_INTERVAL * 3)
3013
3014static bool groupchat_freeze_timedout(Group_Chats *g_c, uint32_t groupnumber, void *userdata)
3105{ 3015{
3106 Group_c *g = get_group_c(g_c, groupnumber); 3016 Group_c *g = get_group_c(g_c, groupnumber);
3107 3017
3108 if (!g) { 3018 if (!g) {
3109 return -1; 3019 return false;
3110 } 3020 }
3111 3021
3112 for (uint32_t i = 0; i < g->numpeers; ++i) { 3022 for (uint32_t i = 0; i < g->numpeers; ++i) {
@@ -3114,7 +3024,7 @@ static int groupchat_freeze_timedout(Group_Chats *g_c, uint32_t groupnumber, voi
3114 continue; 3024 continue;
3115 } 3025 }
3116 3026
3117 if (mono_time_is_timeout(g_c->mono_time, g->group[i].last_active, GROUP_PING_INTERVAL * 3)) { 3027 if (mono_time_is_timeout(g_c->mono_time, g->group[i].last_active, FREEZE_TIMEOUT)) {
3118 freeze_peer(g_c, groupnumber, i, userdata); 3028 freeze_peer(g_c, groupnumber, i, userdata);
3119 } 3029 }
3120 } 3030 }
@@ -3123,7 +3033,7 @@ static int groupchat_freeze_timedout(Group_Chats *g_c, uint32_t groupnumber, voi
3123 g->title_fresh = false; 3033 g->title_fresh = false;
3124 } 3034 }
3125 3035
3126 return 0; 3036 return true;
3127} 3037}
3128 3038
3129/* Send current name (set in messenger) to all online groups. 3039/* Send current name (set in messenger) to all online groups.
diff --git a/toxcore/group.h b/toxcore/group.h
index ee0829cb..1e054de3 100644
--- a/toxcore/group.h
+++ b/toxcore/group.h
@@ -56,37 +56,37 @@ typedef struct Group_Peer {
56 void *object; 56 void *object;
57} Group_Peer; 57} Group_Peer;
58 58
59#define DESIRED_CLOSE_CONNECTIONS 4 59#define DESIRED_CLOSEST 4
60#define MAX_GROUP_CONNECTIONS 16 60#define MAX_GROUP_CONNECTIONS 16
61#define GROUP_ID_LENGTH CRYPTO_SYMMETRIC_KEY_SIZE 61#define GROUP_ID_LENGTH CRYPTO_SYMMETRIC_KEY_SIZE
62 62
63typedef enum Groupchat_Close_Type { 63typedef enum Groupchat_Connection_Type {
64 GROUPCHAT_CLOSE_NONE, 64 GROUPCHAT_CONNECTION_NONE,
65 GROUPCHAT_CLOSE_CONNECTION, 65 GROUPCHAT_CONNECTION_CONNECTING,
66 GROUPCHAT_CLOSE_ONLINE, 66 GROUPCHAT_CONNECTION_ONLINE,
67} Groupchat_Close_Type; 67} Groupchat_Connection_Type;
68 68
69/* Connection is to one of the closest DESIRED_CLOSE_CONNECTIONS peers */ 69/* Connection is to one of the closest DESIRED_CLOSEST peers */
70#define GROUPCHAT_CLOSE_REASON_CLOSEST (1 << 0) 70#define GROUPCHAT_CONNECTION_REASON_CLOSEST (1 << 0)
71 71
72/* Connection is to a peer we are introducing to the conference */ 72/* Connection is to a peer we are introducing to the conference */
73#define GROUPCHAT_CLOSE_REASON_INTRODUCING (1 << 1) 73#define GROUPCHAT_CONNECTION_REASON_INTRODUCING (1 << 1)
74 74
75/* Connection is to a peer who is introducing us to the conference */ 75/* Connection is to a peer who is introducing us to the conference */
76#define GROUPCHAT_CLOSE_REASON_INTRODUCER (1 << 2) 76#define GROUPCHAT_CONNECTION_REASON_INTRODUCER (1 << 2)
77 77
78typedef struct Groupchat_Close { 78typedef struct Groupchat_Connection {
79 uint8_t type; /* `GROUPCHAT_CLOSE_*` */ 79 uint8_t type; /* `GROUPCHAT_CONNECTION_*` */
80 uint8_t reasons; /* bit field with flags `GROUPCHAT_CLOSE_REASON_*` */ 80 uint8_t reasons; /* bit field with flags `GROUPCHAT_CONNECTION_REASON_*` */
81 uint32_t number; 81 uint32_t number;
82 uint16_t group_number; 82 uint16_t group_number;
83} Groupchat_Close; 83} Groupchat_Connection;
84 84
85typedef struct Groupchat_Close_Connection { 85typedef struct Groupchat_Closest {
86 uint8_t entry; 86 uint8_t entry;
87 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; 87 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE];
88 uint8_t temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; 88 uint8_t temp_pk[CRYPTO_PUBLIC_KEY_SIZE];
89} Groupchat_Close_Connection; 89} Groupchat_Closest;
90 90
91typedef void peer_on_join_cb(void *object, uint32_t conference_number, uint32_t peer_number); 91typedef void peer_on_join_cb(void *object, uint32_t conference_number, uint32_t peer_number);
92typedef void peer_on_leave_cb(void *object, uint32_t conference_number, void *peer_object); 92typedef void peer_on_leave_cb(void *object, uint32_t conference_number, void *peer_object);
@@ -109,11 +109,10 @@ typedef struct Group_c {
109 109
110 uint32_t maxfrozen; 110 uint32_t maxfrozen;
111 111
112 /* TODO(zugz) rename close to something more accurate - "connected"? */ 112 Groupchat_Connection connections[MAX_GROUP_CONNECTIONS];
113 Groupchat_Close close[MAX_GROUP_CONNECTIONS];
114 113
115 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; 114 uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE];
116 Groupchat_Close_Connection closest_peers[DESIRED_CLOSE_CONNECTIONS]; 115 Groupchat_Closest closest_peers[DESIRED_CLOSEST];
117 uint8_t changed; 116 uint8_t changed;
118 117
119 uint8_t type; 118 uint8_t type;
@@ -245,7 +244,7 @@ int del_groupchat(Group_Chats *g_c, uint32_t groupnumber, bool leave_permanently
245 * return -1 if groupnumber is invalid. 244 * return -1 if groupnumber is invalid.
246 * return -2 if peernumber is invalid. 245 * return -2 if peernumber is invalid.
247 */ 246 */
248int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *pk, bool frozen); 247int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, uint8_t *pk, bool frozen);
249 248
250/* 249/*
251 * Return the size of (frozen, if frozen is true) peernumber's name. 250 * Return the size of (frozen, if frozen is true) peernumber's name.
@@ -253,7 +252,7 @@ int group_peer_pubkey(const Group_Chats *g_c, uint32_t groupnumber, int peernumb
253 * return -1 if groupnumber is invalid. 252 * return -1 if groupnumber is invalid.
254 * return -2 if peernumber is invalid. 253 * return -2 if peernumber is invalid.
255 */ 254 */
256int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, int32_t peernumber, bool frozen); 255int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, bool frozen);
257 256
258/* Copy the name of (frozen, if frozen is true) peernumber who is in 257/* Copy the name of (frozen, if frozen is true) peernumber who is in
259 * groupnumber to name. 258 * groupnumber to name.
@@ -263,7 +262,7 @@ int group_peername_size(const Group_Chats *g_c, uint32_t groupnumber, int32_t pe
263 * return -1 if groupnumber is invalid. 262 * return -1 if groupnumber is invalid.
264 * return -2 if peernumber is invalid. 263 * return -2 if peernumber is invalid.
265 */ 264 */
266int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, uint8_t *name, bool frozen); 265int group_peername(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, uint8_t *name, bool frozen);
267 266
268/* Copy last active timestamp of frozen peernumber who is in groupnumber to 267/* Copy last active timestamp of frozen peernumber who is in groupnumber to
269 * last_active. 268 * last_active.
@@ -272,7 +271,7 @@ int group_peername(const Group_Chats *g_c, uint32_t groupnumber, int peernumber,
272 * return -1 if groupnumber is invalid. 271 * return -1 if groupnumber is invalid.
273 * return -2 if peernumber is invalid. 272 * return -2 if peernumber is invalid.
274 */ 273 */
275int group_frozen_last_active(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, 274int group_frozen_last_active(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber,
276 uint64_t *last_active); 275 uint64_t *last_active);
277 276
278/* Set maximum number of frozen peers. 277/* Set maximum number of frozen peers.
@@ -292,7 +291,8 @@ int invite_friend(Group_Chats *g_c, uint32_t friendnumber, uint32_t groupnumber)
292 291
293/* Join a group (you need to have been invited first.) 292/* Join a group (you need to have been invited first.)
294 * 293 *
295 * expected_type is the groupchat type we expect the chat we are joining is. 294 * expected_type is the groupchat type we expect the chat we are joining to
295 * have.
296 * 296 *
297 * return group number on success. 297 * return group number on success.
298 * return -1 if data length is invalid. 298 * return -1 if data length is invalid.
@@ -353,7 +353,7 @@ int group_number_peers(const Group_Chats *g_c, uint32_t groupnumber, bool frozen
353 * return -2 if peernumber is invalid. 353 * return -2 if peernumber is invalid.
354 * return -3 if we are not connected to the group chat. 354 * return -3 if we are not connected to the group chat.
355 */ 355 */
356int group_peernumber_is_ours(const Group_Chats *g_c, uint32_t groupnumber, int peernumber); 356int group_peernumber_is_ours(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber);
357 357
358/* List all the (frozen, if frozen is true) peers in the group chat. 358/* List all the (frozen, if frozen is true) peers in the group chat.
359 * 359 *
@@ -423,7 +423,7 @@ int group_set_object(const Group_Chats *g_c, uint32_t groupnumber, void *object)
423 * return 0 on success. 423 * return 0 on success.
424 * return -1 on failure 424 * return -1 on failure
425 */ 425 */
426int group_peer_set_object(const Group_Chats *g_c, uint32_t groupnumber, int peernumber, void *object); 426int group_peer_set_object(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber, void *object);
427 427
428/* Return the object tied to the group chat previously set by group_set_object. 428/* Return the object tied to the group chat previously set by group_set_object.
429 * 429 *
@@ -437,7 +437,7 @@ void *group_get_object(const Group_Chats *g_c, uint32_t groupnumber);
437 * return NULL on failure. 437 * return NULL on failure.
438 * return object on success. 438 * return object on success.
439 */ 439 */
440void *group_peer_get_object(const Group_Chats *g_c, uint32_t groupnumber, int peernumber); 440void *group_peer_get_object(const Group_Chats *g_c, uint32_t groupnumber, uint32_t peernumber);
441 441
442/* Set a function to be called when a new peer joins a group chat. 442/* Set a function to be called when a new peer joins a group chat.
443 * 443 *
diff --git a/toxcore/onion_client.h b/toxcore/onion_client.h
index 88329aee..5b6bea65 100644
--- a/toxcore/onion_client.h
+++ b/toxcore/onion_client.h
@@ -136,8 +136,6 @@ int onion_dht_pk_callback(Onion_Client *onion_c, int friend_num, onion_dht_pk_cb
136 uint32_t number); 136 uint32_t number);
137 137
138/* Set a friends DHT public key. 138/* Set a friends DHT public key.
139 * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to
140 * the other peer.
141 * 139 *
142 * return -1 on failure. 140 * return -1 on failure.
143 * return 0 on success. 141 * return 0 on success.
diff --git a/toxcore/tox.api.h b/toxcore/tox.api.h
index 732262f1..39b457ea 100644
--- a/toxcore/tox.api.h
+++ b/toxcore/tox.api.h
@@ -2232,7 +2232,7 @@ namespace conference {
2232 /** 2232 /**
2233 * Creates a new conference. 2233 * Creates a new conference.
2234 * 2234 *
2235 * This function creates a new text conference. 2235 * This function creates and connects to a new text conference.
2236 * 2236 *
2237 * @return conference number on success, or an unspecified value on failure. 2237 * @return conference number on success, or an unspecified value on failure.
2238 */ 2238 */
@@ -2279,7 +2279,10 @@ namespace conference {
2279 namespace peer { 2279 namespace peer {
2280 2280
2281 /** 2281 /**
2282 * Return the number of peers in the conference. Return value is unspecified on failure. 2282 * Return the number of online peers in the conference. The unsigned
2283 * integers less than this number are the valid values of peer_number for
2284 * the functions querying these peers. Return value is unspecified on
2285 * failure.
2283 */ 2286 */
2284 const uint32_t count(uint32_t conference_number) 2287 const uint32_t count(uint32_t conference_number)
2285 with error for peer_query; 2288 with error for peer_query;
@@ -2327,7 +2330,9 @@ namespace conference {
2327 namespace offline_peer { 2330 namespace offline_peer {
2328 2331
2329 /** 2332 /**
2330 * Return the number of offline peers in the conference. Return value is unspecified on failure. 2333 * Return the number of offline peers in the conference. The unsigned
2334 * integers less than this number are the valid values of offline_peer_number for
2335 * the functions querying these peers. Return value is unspecified on failure.
2331 */ 2336 */
2332 const uint32_t count(uint32_t conference_number) 2337 const uint32_t count(uint32_t conference_number)
2333 with error for peer_query; 2338 with error for peer_query;
@@ -2388,10 +2393,6 @@ namespace conference {
2388 /** 2393 /**
2389 * Invites a friend to a conference. 2394 * Invites a friend to a conference.
2390 * 2395 *
2391 * We must be connected to the conference, meaning that the conference has not
2392 * been deleted, and either we created the conference with the $new function,
2393 * or a `${event connected}` event has occurred for the conference.
2394 *
2395 * @param friend_number The friend number of the friend we want to invite. 2396 * @param friend_number The friend number of the friend we want to invite.
2396 * @param conference_number The conference number of the conference we want to invite the friend to. 2397 * @param conference_number The conference number of the conference we want to invite the friend to.
2397 * 2398 *
@@ -2416,6 +2417,14 @@ namespace conference {
2416 /** 2417 /**
2417 * Joins a conference that the client has been invited to. 2418 * Joins a conference that the client has been invited to.
2418 * 2419 *
2420 * After successfully joining the conference, the client will not be "connected"
2421 * to it until a handshaking procedure has been completed. A
2422 * `${event connected}` event will then occur for the conference. The client
2423 * will then remain connected to the conference until the conference is deleted,
2424 * even across core restarts. Many operations on a conference will fail with a
2425 * corresponding error if attempted on a conference to which the client is not
2426 * yet connected.
2427 *
2419 * @param friend_number The friend number of the friend who sent the invite. 2428 * @param friend_number The friend number of the friend who sent the invite.
2420 * @param cookie Received via the `${event invite}` event. 2429 * @param cookie Received via the `${event invite}` event.
2421 * @param length The size of cookie. 2430 * @param length The size of cookie.
@@ -2552,8 +2561,16 @@ namespace conference {
2552 size(); 2561 size();
2553 2562
2554 /** 2563 /**
2555 * Copy a list of valid conference IDs into the array chatlist. Determine how much space 2564 * Copy a list of valid conference numbers into the array chatlist. Determine
2556 * to allocate for the array with the `$size` function. 2565 * how much space to allocate for the array with the `$size` function.
2566 *
2567 * Note that `${savedata.get}` saves all connected conferences;
2568 * when toxcore is created from savedata in which conferences were saved, those
2569 * conferences will be connected at startup, and will be listed by
2570 * `$get`.
2571 *
2572 * The conference number of a loaded conference may differ from the conference
2573 * number it had when it was saved.
2557 */ 2574 */
2558 get(); 2575 get();
2559 } 2576 }
diff --git a/toxcore/tox.h b/toxcore/tox.h
index ab28be40..32f215d8 100644
--- a/toxcore/tox.h
+++ b/toxcore/tox.h
@@ -2541,7 +2541,7 @@ typedef enum TOX_ERR_CONFERENCE_NEW {
2541/** 2541/**
2542 * Creates a new conference. 2542 * Creates a new conference.
2543 * 2543 *
2544 * This function creates a new text conference. 2544 * This function creates and connects to a new text conference.
2545 * 2545 *
2546 * @return conference number on success, or an unspecified value on failure. 2546 * @return conference number on success, or an unspecified value on failure.
2547 */ 2547 */
@@ -2600,7 +2600,10 @@ typedef enum TOX_ERR_CONFERENCE_PEER_QUERY {
2600 2600
2601 2601
2602/** 2602/**
2603 * Return the number of peers in the conference. Return value is unspecified on failure. 2603 * Return the number of online peers in the conference. The unsigned
2604 * integers less than this number are the valid values of peer_number for
2605 * the functions querying these peers. Return value is unspecified on
2606 * failure.
2604 */ 2607 */
2605uint32_t tox_conference_peer_count(const Tox *tox, uint32_t conference_number, TOX_ERR_CONFERENCE_PEER_QUERY *error); 2608uint32_t tox_conference_peer_count(const Tox *tox, uint32_t conference_number, TOX_ERR_CONFERENCE_PEER_QUERY *error);
2606 2609
@@ -2638,7 +2641,9 @@ bool tox_conference_peer_number_is_ours(const Tox *tox, uint32_t conference_numb
2638 TOX_ERR_CONFERENCE_PEER_QUERY *error); 2641 TOX_ERR_CONFERENCE_PEER_QUERY *error);
2639 2642
2640/** 2643/**
2641 * Return the number of offline peers in the conference. Return value is unspecified on failure. 2644 * Return the number of offline peers in the conference. The unsigned
2645 * integers less than this number are the valid values of offline_peer_number for
2646 * the functions querying these peers. Return value is unspecified on failure.
2642 */ 2647 */
2643uint32_t tox_conference_offline_peer_count(const Tox *tox, uint32_t conference_number, 2648uint32_t tox_conference_offline_peer_count(const Tox *tox, uint32_t conference_number,
2644 TOX_ERR_CONFERENCE_PEER_QUERY *error); 2649 TOX_ERR_CONFERENCE_PEER_QUERY *error);
@@ -2725,10 +2730,6 @@ typedef enum TOX_ERR_CONFERENCE_INVITE {
2725/** 2730/**
2726 * Invites a friend to a conference. 2731 * Invites a friend to a conference.
2727 * 2732 *
2728 * We must be connected to the conference, meaning that the conference has not
2729 * been deleted, and either we created the conference with the tox_conference_new function,
2730 * or a `conference_connected` event has occurred for the conference.
2731 *
2732 * @param friend_number The friend number of the friend we want to invite. 2733 * @param friend_number The friend number of the friend we want to invite.
2733 * @param conference_number The conference number of the conference we want to invite the friend to. 2734 * @param conference_number The conference number of the conference we want to invite the friend to.
2734 * 2735 *
@@ -2780,6 +2781,14 @@ typedef enum TOX_ERR_CONFERENCE_JOIN {
2780/** 2781/**
2781 * Joins a conference that the client has been invited to. 2782 * Joins a conference that the client has been invited to.
2782 * 2783 *
2784 * After successfully joining the conference, the client will not be "connected"
2785 * to it until a handshaking procedure has been completed. A
2786 * `conference_connected` event will then occur for the conference. The client
2787 * will then remain connected to the conference until the conference is deleted,
2788 * even across core restarts. Many operations on a conference will fail with a
2789 * corresponding error if attempted on a conference to which the client is not
2790 * yet connected.
2791 *
2783 * @param friend_number The friend number of the friend who sent the invite. 2792 * @param friend_number The friend number of the friend who sent the invite.
2784 * @param cookie Received via the `conference_invite` event. 2793 * @param cookie Received via the `conference_invite` event.
2785 * @param length The size of cookie. 2794 * @param length The size of cookie.
@@ -2906,8 +2915,16 @@ bool tox_conference_set_title(Tox *tox, uint32_t conference_number, const uint8_
2906size_t tox_conference_get_chatlist_size(const Tox *tox); 2915size_t tox_conference_get_chatlist_size(const Tox *tox);
2907 2916
2908/** 2917/**
2909 * Copy a list of valid conference IDs into the array chatlist. Determine how much space 2918 * Copy a list of valid conference numbers into the array chatlist. Determine
2910 * to allocate for the array with the `tox_conference_get_chatlist_size` function. 2919 * how much space to allocate for the array with the `tox_conference_get_chatlist_size` function.
2920 *
2921 * Note that `tox_get_savedata` saves all connected conferences;
2922 * when toxcore is created from savedata in which conferences were saved, those
2923 * conferences will be connected at startup, and will be listed by
2924 * `tox_conference_get_chatlist`.
2925 *
2926 * The conference number of a loaded conference may differ from the conference
2927 * number it had when it was saved.
2911 */ 2928 */
2912void tox_conference_get_chatlist(const Tox *tox, uint32_t *chatlist); 2929void tox_conference_get_chatlist(const Tox *tox, uint32_t *chatlist);
2913 2930