summaryrefslogtreecommitdiff
path: root/toxcore/group.c
diff options
context:
space:
mode:
authorirungentoo <irungentoo@gmail.com>2014-09-26 13:25:52 -0400
committerirungentoo <irungentoo@gmail.com>2014-09-26 13:25:52 -0400
commit8b35d194c040270280bf658e514ef61ee2759dfb (patch)
tree46cad4ec443445b04c668b863239baed7ea2ee82 /toxcore/group.c
parentd5d84818fecc62425281aaf0cbe71d0f264fdc18 (diff)
Group chats are starting to work.
Diffstat (limited to 'toxcore/group.c')
-rw-r--r--toxcore/group.c304
1 files changed, 283 insertions, 21 deletions
diff --git a/toxcore/group.c b/toxcore/group.c
index d3652e17..602c9124 100644
--- a/toxcore/group.c
+++ b/toxcore/group.c
@@ -220,7 +220,7 @@ static int wipe_group_chat(Group_Chats *g_c, int groupnumber)
220 return 0; 220 return 0;
221} 221}
222 222
223static Group_c *get_group_c(Group_Chats *g_c, int groupnumber) 223static Group_c *get_group_c(const Group_Chats *g_c, int groupnumber)
224{ 224{
225 if (groupnumber_not_valid(g_c, groupnumber)) 225 if (groupnumber_not_valid(g_c, groupnumber))
226 return 0; 226 return 0;
@@ -231,7 +231,7 @@ static Group_c *get_group_c(Group_Chats *g_c, int groupnumber)
231/* 231/*
232 * check if peer with client_id is in peer array. 232 * check if peer with client_id is in peer array.
233 * 233 *
234 * return peer number if peer is in chat. 234 * return peer index if peer is in chat.
235 * return -1 if peer is not in chat. 235 * return -1 if peer is not in chat.
236 * 236 *
237 * TODO: make this more efficient. 237 * TODO: make this more efficient.
@@ -268,17 +268,37 @@ static int get_group_num(const Group_Chats *g_c, const uint8_t *identifier)
268} 268}
269 269
270/* 270/*
271 * check if peer with peer_number is in peer array.
272 *
273 * return peer number if peer is in chat.
274 * return -1 if peer is not in chat.
275 *
276 * TODO: make this more efficient.
277 */
278int get_peer_index(Group_c *g, uint16_t peer_number)
279{
280 uint32_t i;
281
282 for (i = 0; i < g->numpeers; ++i)
283 if (g->group[i].peer_number == peer_number)
284 return i;
285
286 return -1;
287}
288
289/*
271 * Add a peer to the group chat. 290 * Add a peer to the group chat.
272 * 291 *
273 * return peernum if success or peer already in chat. 292 * return peer_index if success or peer already in chat.
274 * return -1 if error. 293 * return -1 if error.
275 */ 294 */
276static int addpeer(Group_c *chat, const uint8_t *client_id) 295static int addpeer(Group_c *chat, const uint8_t *client_id, uint16_t peer_number)
277{ 296{
278 int peernum = peer_in_chat(chat, client_id); 297 //TODO
298 //int peer_index = peer_in_chat(chat, client_id);
279 299
280 if (peernum != -1) 300 //if (peer_index != -1)
281 return peernum; 301 // return peer_index;
282 302
283 Group_Peer *temp; 303 Group_Peer *temp;
284 temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers + 1)); 304 temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers + 1));
@@ -290,6 +310,8 @@ static int addpeer(Group_c *chat, const uint8_t *client_id)
290 chat->group = temp; 310 chat->group = temp;
291 311
292 id_copy(chat->group[chat->numpeers].client_id, client_id); 312 id_copy(chat->group[chat->numpeers].client_id, client_id);
313 chat->group[chat->numpeers].peer_number = peer_number;
314
293 chat->group[chat->numpeers].last_recv = unix_time(); 315 chat->group[chat->numpeers].last_recv = unix_time();
294 chat->group[chat->numpeers].last_recv_msgping = unix_time(); 316 chat->group[chat->numpeers].last_recv_msgping = unix_time();
295 ++chat->numpeers; 317 ++chat->numpeers;
@@ -300,6 +322,39 @@ static int addpeer(Group_c *chat, const uint8_t *client_id)
300 return (chat->numpeers - 1); 322 return (chat->numpeers - 1);
301} 323}
302 324
325/* Add friend to group chat.
326 *
327 * return 0 on success
328 * return -1 on failure.
329 */
330static int add_friend_to_groupchat(Group_Chats *g_c, int32_t friendnumber, int groupnumber, uint16_t other_groupnum)
331{
332 if (!m_friend_exists(g_c->m, friendnumber))
333 return -1;
334
335 Group_c *g = get_group_c(g_c, groupnumber);
336
337 if (!g)
338 return -1;
339
340 uint16_t i;
341
342 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
343 if (g->close[i].type != GROUPCHAT_CLOSE_NONE)
344 continue;
345
346 break;
347 }
348
349 if (i == MAX_GROUP_CONNECTIONS)
350 return -1;
351
352 g->close[i].type = GROUPCHAT_CLOSE_FRIEND;
353 g->close[i].number = friendnumber;
354 g->close[i].group_number = other_groupnum;
355
356 return 0;
357}
303 358
304/* Creates a new groupchat and puts it in the chats array. 359/* Creates a new groupchat and puts it in the chats array.
305 * 360 *
@@ -310,13 +365,14 @@ int add_groupchat(Group_Chats *g_c)
310{ 365{
311 int groupnumber = create_group_chat(g_c); 366 int groupnumber = create_group_chat(g_c);
312 367
313 Group_c *g = get_group_c(g_c, groupnumber); 368 if (groupnumber == -1)
314
315 if (!g)
316 return -1; 369 return -1;
317 370
371 Group_c *g = &g_c->chats[groupnumber];
372
318 g->status = GROUPCHAT_STATUS_VALID; 373 g->status = GROUPCHAT_STATUS_VALID;
319 new_symmetric_key(g->identifier); 374 new_symmetric_key(g->identifier);
375 g->peer_number = 0; /* Founder is peer 0. */
320 return groupnumber; 376 return groupnumber;
321} 377}
322 378
@@ -356,18 +412,18 @@ int invite_friend(Group_Chats *g_c, int32_t friendnumber, int groupnumber)
356 * returns group number on success 412 * returns group number on success
357 * returns -1 on failure. 413 * returns -1 on failure.
358 */ 414 */
359int join_groupchat(Group_Chats *g_c, int32_t friendnumber, uint8_t *data, uint16_t length) 415int join_groupchat(Group_Chats *g_c, int32_t friendnumber, const uint8_t *data, uint16_t length)
360{ 416{
361 if (length != sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH) 417 if (length != sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH)
362 return -1; 418 return -1;
363 419
364 int groupnumber = create_group_chat(g_c); 420 int groupnumber = create_group_chat(g_c);
365 421
366 Group_c *g = get_group_c(g_c, groupnumber); 422 if (groupnumber == -1)
367
368 if (!g)
369 return -1; 423 return -1;
370 424
425 Group_c *g = &g_c->chats[groupnumber];
426
371 uint16_t group_num = htons(groupnumber); 427 uint16_t group_num = htons(groupnumber);
372 g->status = GROUPCHAT_STATUS_VALID; 428 g->status = GROUPCHAT_STATUS_VALID;
373 uint8_t response[INVITE_RESPONSE_PACKET_SIZE]; 429 uint8_t response[INVITE_RESPONSE_PACKET_SIZE];
@@ -379,7 +435,9 @@ int join_groupchat(Group_Chats *g_c, int32_t friendnumber, uint8_t *data, uint16
379 uint16_t other_groupnum; 435 uint16_t other_groupnum;
380 memcpy(&other_groupnum, data, sizeof(other_groupnum)); 436 memcpy(&other_groupnum, data, sizeof(other_groupnum));
381 other_groupnum = htons(other_groupnum); 437 other_groupnum = htons(other_groupnum);
382 //TODO add_friend_to_groupchat(g_c, friendnumber, groupnumber, other_groupnum); 438 memcpy(g->identifier, data + sizeof(uint16_t), GROUP_IDENTIFIER_LENGTH);
439 add_friend_to_groupchat(g_c, friendnumber, groupnumber, other_groupnum);
440 g->peer_number = rand(); /* TODO */
383 return groupnumber; 441 return groupnumber;
384 } else { 442 } else {
385 return -1; 443 return -1;
@@ -428,10 +486,16 @@ static void handle_friend_invite_packet(Messenger *m, int32_t friendnumber, cons
428 int groupnumber = get_group_num(g_c, data + 1 + sizeof(uint16_t)); 486 int groupnumber = get_group_num(g_c, data + 1 + sizeof(uint16_t));
429 487
430 if (groupnumber == -1) { 488 if (groupnumber == -1) {
431 g_c->invite_callback(m, friendnumber, invite_data, invite_length, g_c->invite_callback_userdata); 489 if (g_c->invite_callback)
490 g_c->invite_callback(m, friendnumber, invite_data, invite_length, g_c->invite_callback_userdata);
491
432 return; 492 return;
433 } else { 493 } else {
434 //TODO 494 //TODO
495 uint16_t other_groupnum;
496 memcpy(&other_groupnum, data + 1, sizeof(uint16_t));
497 other_groupnum = ntohs(other_groupnum);
498 add_friend_to_groupchat(g_c, friendnumber, groupnumber, other_groupnum);
435 } 499 }
436 500
437 break; 501 break;
@@ -441,13 +505,22 @@ static void handle_friend_invite_packet(Messenger *m, int32_t friendnumber, cons
441 if (length != INVITE_RESPONSE_PACKET_SIZE) 505 if (length != INVITE_RESPONSE_PACKET_SIZE)
442 return; 506 return;
443 507
444 int groupnumber = get_group_num(g_c, data + 1 + sizeof(uint16_t)); 508 uint16_t other_groupnum, groupnum;
509 memcpy(&groupnum, data + 1 + sizeof(uint16_t), sizeof(uint16_t));
510 groupnum = ntohs(groupnum);
445 511
446 if (groupnumber == -1) { 512 Group_c *g = get_group_c(g_c, groupnum);
513
514 if (!g)
515 return;
516
517 if (memcmp(data + 1 + sizeof(uint16_t) * 2, g->identifier, GROUP_IDENTIFIER_LENGTH) != 0)
447 return; 518 return;
448 } else { 519
449 //TODO add_friend_to_groupchat(g_c, friendnumber, groupnumber, other_groupnum); 520 memcpy(&other_groupnum, data + 1, sizeof(uint16_t));
450 } 521 other_groupnum = ntohs(other_groupnum);
522
523 add_friend_to_groupchat(g_c, friendnumber, groupnum, other_groupnum);
451 524
452 break; 525 break;
453 } 526 }
@@ -457,9 +530,197 @@ static void handle_friend_invite_packet(Messenger *m, int32_t friendnumber, cons
457 } 530 }
458} 531}
459 532
533/* Find index of friend in the close list;
534 *
535 * returns index on success
536 * returns -1 on failure.
537 */
538static int friend_in_close(Group_c *g, int32_t friendnumber)
539{
540 int i;
541
542 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
543 if (g->close[i].type != GROUPCHAT_CLOSE_FRIEND)
544 continue;
545
546 if (g->close[i].number != (uint32_t)friendnumber)
547 continue;
548
549 break;
550 }
551
552 if (i == MAX_GROUP_CONNECTIONS)
553 return -1;
554
555 return i;
556}
557
558#define MIN_MESSAGE_PACKET_LEN (sizeof(uint16_t) * 2 + sizeof(uint32_t) + 1)
559
560/* Send message to all close except receiver (if receiver isn't -1)
561 * NOTE: this function appends the group chat number to the data passed to it.
562 *
563 * return number of messages sent.
564 */
565static unsigned int send_message_all_close(const Group_Chats *g_c, int groupnumber, const uint8_t *data,
566 uint16_t length, int receiver)
567{
568
569 Group_c *g = get_group_c(g_c, groupnumber);
570
571 if (!g)
572 return 0;
573
574 uint16_t i, sent = 0;
575
576 for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {
577 if (g->close[i].type == GROUPCHAT_CLOSE_NONE)
578 continue;
579
580 if ((int)i == receiver)
581 continue;
582
583 uint16_t other_groupnum = htons(g->close[i].group_number);
584 uint8_t packet[sizeof(uint16_t) + length];
585 memcpy(packet, &other_groupnum, sizeof(uint16_t));
586 memcpy(packet + sizeof(uint16_t), data, length);
587
588 if (send_group_message_packet(g_c->m, g->close[i].number, packet, sizeof(packet)))
589 ++sent;
590 }
591
592 return sent;
593}
594
595/* Send data of len with message_id to groupnumber.
596 *
597 * return number of peers it was sent to on success.
598 * return 0 on failure.
599 */
600static unsigned int send_message_group(const Group_Chats *g_c, int groupnumber, uint8_t message_id, const uint8_t *data,
601 uint16_t len)
602{
603 Group_c *g = get_group_c(g_c, groupnumber);
604
605 if (!g)
606 return 0;
607
608 uint8_t packet[sizeof(uint16_t) + sizeof(uint32_t) + 1 + len];
609 uint16_t peer_num = htons(g->peer_number);
610 memcpy(packet, &peer_num, sizeof(peer_num));
611
612 ++g->message_number;
613
614 if (!g->message_number)
615 ++g->message_number;
616
617 uint32_t message_num = htonl(g->message_number);
618 memcpy(packet + sizeof(uint16_t), &message_num, sizeof(message_num));
619
620 packet[sizeof(uint16_t) + sizeof(uint32_t)] = message_id;
621
622 if (len)
623 memcpy(packet + sizeof(uint16_t) + sizeof(uint32_t) + 1, data, len);
624
625 return send_message_all_close(g_c, groupnumber, packet, sizeof(packet), -1);
626}
627
628/* send a group message
629 * return 0 on success
630 * return -1 on failure
631 */
632int group_message_send(const Group_Chats *g_c, int groupnumber, const uint8_t *message, uint16_t length)
633{
634 if (send_message_group(g_c, groupnumber, PACKET_ID_MESSAGE, message, length)) {
635 return 0;
636 } else {
637 return -1;
638 }
639}
640
641static void handle_message_packet_group(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length,
642 int close_index)
643{
644 if (length < MIN_MESSAGE_PACKET_LEN)
645 return;
646
647 Group_c *g = get_group_c(g_c, groupnumber);
648
649 if (!g)
650 return;
651
652 uint16_t peer_number;
653 memcpy(&peer_number, data + sizeof(uint16_t), sizeof(uint16_t));
654 peer_number = ntohs(peer_number);
655
656 int index = get_peer_index(g, peer_number);
657
658 //TODO remove
659 if (index == -1) {
660 uint8_t empty_key[crypto_box_PUBLICKEYBYTES];
661 index = addpeer(g, empty_key, peer_number);
662 }
663
664 if (index == -1)
665 return;
666
667 uint32_t message_number;
668 memcpy(&message_number, data + sizeof(uint16_t) * 2, sizeof(message_number));
669 message_number = ntohl(message_number);
670
671 if (g->group[index].last_message_number == 0) {
672 g->group[index].last_message_number = message_number;
673 } else if (message_number - g->group[index].last_message_number > 64 ||
674 message_number == g->group[index].last_message_number) {
675 return;
676 }
677
678 g->group[index].last_message_number = message_number;
679
680 uint8_t message_id = data[sizeof(uint16_t) * 2 + sizeof(message_number)];
681 const uint8_t *msg_data = data + sizeof(uint16_t) * 2 + sizeof(message_number) + 1;
682 uint16_t msg_data_len = length - (sizeof(uint16_t) * 2 + sizeof(message_number) + 1);
683
684 switch (message_id) {
685 case PACKET_ID_MESSAGE: {
686 if (msg_data_len == 0)
687 return;
688
689 //TODO
690 if (g_c->message_callback)
691 g_c->message_callback(g_c->m, groupnumber, index, msg_data, msg_data_len, g_c->message_callback_userdata);
692
693 break;
694 }
695
696 default:
697 return;
698 }
699
700 send_message_all_close(g_c, groupnumber, data + sizeof(uint16_t), length - sizeof(uint16_t), close_index);
701}
702
460static void handle_friend_message_packet(Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) 703static void handle_friend_message_packet(Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length)
461{ 704{
705 Group_Chats *g_c = m->group_chat_object;
706
707 if (length < MIN_MESSAGE_PACKET_LEN)
708 return;
709
710 uint16_t groupnumber;
711 memcpy(&groupnumber, data, sizeof(uint16_t));
712 groupnumber = ntohs(groupnumber);
713 Group_c *g = get_group_c(g_c, groupnumber);
714
715 if (!g)
716 return;
717
718 int index = friend_in_close(g, friendnumber);
719
720 if (index == -1)
721 return;
462 722
723 handle_message_packet_group(g_c, groupnumber, data, length, index);
463} 724}
464 725
465/* Create new groupchat instance. */ 726/* Create new groupchat instance. */
@@ -476,6 +737,7 @@ Group_Chats *new_groupchats(Messenger *m)
476 temp->m = m; 737 temp->m = m;
477 m->group_chat_object = temp; 738 m->group_chat_object = temp;
478 m_callback_group_invite(m, &handle_friend_invite_packet); 739 m_callback_group_invite(m, &handle_friend_invite_packet);
740 m_callback_group_message(m, &handle_friend_message_packet);
479 741
480 return temp; 742 return temp;
481} 743}