diff options
Diffstat (limited to 'toxcore/group.c')
-rw-r--r-- | toxcore/group.c | 304 |
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 | ||
223 | static Group_c *get_group_c(Group_Chats *g_c, int groupnumber) | 223 | static 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 | */ | ||
278 | int 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 | */ |
276 | static int addpeer(Group_c *chat, const uint8_t *client_id) | 295 | static 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 | */ | ||
330 | static 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 | */ |
359 | int join_groupchat(Group_Chats *g_c, int32_t friendnumber, uint8_t *data, uint16_t length) | 415 | int 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 | */ | ||
538 | static 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 | */ | ||
565 | static 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 | */ | ||
600 | static 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 | */ | ||
632 | int 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 | |||
641 | static 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 | |||
460 | static void handle_friend_message_packet(Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) | 703 | static 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 | } |