diff options
Diffstat (limited to 'toxcore/group.c')
-rw-r--r-- | toxcore/group.c | 100 |
1 files changed, 93 insertions, 7 deletions
diff --git a/toxcore/group.c b/toxcore/group.c index 20ee5459..f6f8c704 100644 --- a/toxcore/group.c +++ b/toxcore/group.c | |||
@@ -118,6 +118,8 @@ static bool realloc_conferences(Group_Chats *g_c, uint16_t num) | |||
118 | static void setup_conference(Group_c *g) | 118 | static void setup_conference(Group_c *g) |
119 | { | 119 | { |
120 | memset(g, 0, sizeof(Group_c)); | 120 | memset(g, 0, sizeof(Group_c)); |
121 | |||
122 | g->maxfrozen = MAX_FROZEN_DEFAULT; | ||
121 | } | 123 | } |
122 | 124 | ||
123 | /* Create a new empty groupchat connection. | 125 | /* Create a new empty groupchat connection. |
@@ -644,8 +646,8 @@ static int addpeer(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_p | |||
644 | id_copy(g->group[g->numpeers].temp_pk, temp_pk); | 646 | id_copy(g->group[g->numpeers].temp_pk, temp_pk); |
645 | g->group[g->numpeers].temp_pk_updated = true; | 647 | g->group[g->numpeers].temp_pk_updated = true; |
646 | g->group[g->numpeers].peer_number = peer_number; | 648 | g->group[g->numpeers].peer_number = peer_number; |
647 | |||
648 | g->group[g->numpeers].last_active = mono_time_get(g_c->mono_time); | 649 | g->group[g->numpeers].last_active = mono_time_get(g_c->mono_time); |
650 | g->group[g->numpeers].is_friend = (getfriend_id(g_c->m, real_pk) != -1); | ||
649 | ++g->numpeers; | 651 | ++g->numpeers; |
650 | 652 | ||
651 | add_to_closest(g_c, groupnumber, real_pk, temp_pk); | 653 | add_to_closest(g_c, groupnumber, real_pk, temp_pk); |
@@ -752,6 +754,56 @@ static int delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void | |||
752 | return 0; | 754 | return 0; |
753 | } | 755 | } |
754 | 756 | ||
757 | static int cmp_u64(uint64_t a, uint64_t b) | ||
758 | { | ||
759 | return (a > b) - (a < b); | ||
760 | } | ||
761 | |||
762 | /* Order peers with friends first and with more recently active earlier */ | ||
763 | static int cmp_frozen(const void *a, const void *b) | ||
764 | { | ||
765 | const Group_Peer *pa = (const Group_Peer *) a; | ||
766 | const Group_Peer *pb = (const Group_Peer *) b; | ||
767 | |||
768 | if (pa->is_friend ^ pb->is_friend) { | ||
769 | return pa->is_friend ? -1 : 1; | ||
770 | } | ||
771 | |||
772 | return cmp_u64(pb->last_active, pa->last_active); | ||
773 | } | ||
774 | |||
775 | /* Delete frozen peers as necessary to ensure at most g->maxfrozen remain. | ||
776 | * | ||
777 | * return true if any frozen peers are removed. | ||
778 | */ | ||
779 | static bool delete_old_frozen(Group_c *g) | ||
780 | { | ||
781 | if (g->numfrozen <= g->maxfrozen) { | ||
782 | return false; | ||
783 | } | ||
784 | |||
785 | if (g->maxfrozen == 0) { | ||
786 | free(g->frozen); | ||
787 | g->frozen = nullptr; | ||
788 | g->numfrozen = 0; | ||
789 | return true; | ||
790 | } | ||
791 | |||
792 | qsort(g->frozen, g->numfrozen, sizeof(Group_Peer), cmp_frozen); | ||
793 | |||
794 | Group_Peer *temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * g->maxfrozen); | ||
795 | |||
796 | if (temp == nullptr) { | ||
797 | return false; | ||
798 | } | ||
799 | |||
800 | g->frozen = temp; | ||
801 | |||
802 | g->numfrozen = g->maxfrozen; | ||
803 | |||
804 | return true; | ||
805 | } | ||
806 | |||
755 | static bool try_send_rejoin(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk); | 807 | static bool try_send_rejoin(Group_Chats *g_c, uint32_t groupnumber, const uint8_t *real_pk); |
756 | 808 | ||
757 | static int freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void *userdata) | 809 | static int freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void *userdata) |
@@ -762,8 +814,6 @@ static int freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, v | |||
762 | return -1; | 814 | return -1; |
763 | } | 815 | } |
764 | 816 | ||
765 | try_send_rejoin(g_c, groupnumber, g->group[peer_index].real_pk); | ||
766 | |||
767 | Group_Peer *temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * (g->numfrozen + 1)); | 817 | Group_Peer *temp = (Group_Peer *)realloc(g->frozen, sizeof(Group_Peer) * (g->numfrozen + 1)); |
768 | 818 | ||
769 | if (temp == nullptr) { | 819 | if (temp == nullptr) { |
@@ -773,9 +823,18 @@ static int freeze_peer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, v | |||
773 | g->frozen = temp; | 823 | g->frozen = temp; |
774 | g->frozen[g->numfrozen] = g->group[peer_index]; | 824 | g->frozen[g->numfrozen] = g->group[peer_index]; |
775 | g->frozen[g->numfrozen].object = nullptr; | 825 | g->frozen[g->numfrozen].object = nullptr; |
826 | |||
827 | if (delpeer(g_c, groupnumber, peer_index, userdata, true) != 0) { | ||
828 | return -1; | ||
829 | } | ||
830 | |||
831 | try_send_rejoin(g_c, groupnumber, g->frozen[g->numfrozen].real_pk); | ||
832 | |||
776 | ++g->numfrozen; | 833 | ++g->numfrozen; |
777 | 834 | ||
778 | return delpeer(g_c, groupnumber, peer_index, userdata, true); | 835 | delete_old_frozen(g); |
836 | |||
837 | return 0; | ||
779 | } | 838 | } |
780 | 839 | ||
781 | 840 | ||
@@ -1236,6 +1295,24 @@ int group_frozen_last_active(const Group_Chats *g_c, uint32_t groupnumber, int p | |||
1236 | return 0; | 1295 | return 0; |
1237 | } | 1296 | } |
1238 | 1297 | ||
1298 | /* Set maximum number of frozen peers. | ||
1299 | * | ||
1300 | * return 0 on success. | ||
1301 | * return -1 if groupnumber is invalid. | ||
1302 | */ | ||
1303 | int group_set_max_frozen(const Group_Chats *g_c, uint32_t groupnumber, uint32_t maxfrozen) | ||
1304 | { | ||
1305 | Group_c *g = get_group_c(g_c, groupnumber); | ||
1306 | |||
1307 | if (!g) { | ||
1308 | return -1; | ||
1309 | } | ||
1310 | |||
1311 | g->maxfrozen = maxfrozen; | ||
1312 | delete_old_frozen(g); | ||
1313 | return 0; | ||
1314 | } | ||
1315 | |||
1239 | /* List all the (frozen, if frozen is true) peers in the group chat. | 1316 | /* List all the (frozen, if frozen is true) peers in the group chat. |
1240 | * | 1317 | * |
1241 | * Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array. | 1318 | * Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array. |
@@ -3208,10 +3285,12 @@ static State_Load_Status load_conferences(Group_Chats *g_c, const uint8_t *data, | |||
3208 | lendian_bytes_to_host32(&g->numfrozen, data); | 3285 | lendian_bytes_to_host32(&g->numfrozen, data); |
3209 | data += sizeof(uint32_t); | 3286 | data += sizeof(uint32_t); |
3210 | 3287 | ||
3211 | g->frozen = (Group_Peer *)malloc(sizeof(Group_Peer) * g->numfrozen); | 3288 | if (g->numfrozen > 0) { |
3289 | g->frozen = (Group_Peer *)malloc(sizeof(Group_Peer) * g->numfrozen); | ||
3212 | 3290 | ||
3213 | if (g->frozen == nullptr) { | 3291 | if (g->frozen == nullptr) { |
3214 | return STATE_LOAD_STATUS_ERROR; | 3292 | return STATE_LOAD_STATUS_ERROR; |
3293 | } | ||
3215 | } | 3294 | } |
3216 | 3295 | ||
3217 | g->title_len = *data; | 3296 | g->title_len = *data; |
@@ -3252,6 +3331,13 @@ static State_Load_Status load_conferences(Group_Chats *g_c, const uint8_t *data, | |||
3252 | 3331 | ||
3253 | memcpy(peer->nick, data, peer->nick_len); | 3332 | memcpy(peer->nick, data, peer->nick_len); |
3254 | data += peer->nick_len; | 3333 | data += peer->nick_len; |
3334 | |||
3335 | // NOTE: this relies on friends being loaded before conferences. | ||
3336 | peer->is_friend = (getfriend_id(g_c->m, peer->real_pk) != -1); | ||
3337 | } | ||
3338 | |||
3339 | if (g->numfrozen > g->maxfrozen) { | ||
3340 | g->maxfrozen = g->numfrozen; | ||
3255 | } | 3341 | } |
3256 | 3342 | ||
3257 | g->status = GROUPCHAT_STATUS_CONNECTED; | 3343 | g->status = GROUPCHAT_STATUS_CONNECTED; |