diff options
Diffstat (limited to 'toxcore/group.c')
-rw-r--r-- | toxcore/group.c | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/toxcore/group.c b/toxcore/group.c new file mode 100644 index 00000000..65ae078c --- /dev/null +++ b/toxcore/group.c | |||
@@ -0,0 +1,331 @@ | |||
1 | /* group.c | ||
2 | * | ||
3 | * Slightly better groupchats implementation. | ||
4 | * | ||
5 | * Copyright (C) 2014 Tox project All Rights Reserved. | ||
6 | * | ||
7 | * This file is part of Tox. | ||
8 | * | ||
9 | * Tox is free software: you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation, either version 3 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * Tox is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifdef HAVE_CONFIG_H | ||
25 | #include "config.h" | ||
26 | #endif | ||
27 | |||
28 | #include "group.h" | ||
29 | #include "util.h" | ||
30 | |||
31 | /* return 1 if the con_number is not valid. | ||
32 | * return 0 if the con_number is valid. | ||
33 | */ | ||
34 | static uint8_t con_number_not_valid(const Group_Chats *g_c, int con_number) | ||
35 | { | ||
36 | if ((unsigned int)con_number >= g_c->num_cons) | ||
37 | return 1; | ||
38 | |||
39 | if (g_c->cons == NULL) | ||
40 | return 1; | ||
41 | |||
42 | if (g_c->cons[con_number].status == GROUPCON_STATUS_NONE) | ||
43 | return 1; | ||
44 | |||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | |||
49 | /* Set the size of the groupchat connections list to num. | ||
50 | * | ||
51 | * return -1 if realloc fails. | ||
52 | * return 0 if it succeeds. | ||
53 | */ | ||
54 | static int realloc_groupcons(Group_Chats *g_c, uint32_t num) | ||
55 | { | ||
56 | if (num == 0) { | ||
57 | free(g_c->cons); | ||
58 | g_c->cons = NULL; | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | Group_Connection *newgroup_cons = realloc(g_c->cons, num * sizeof(Group_Connection)); | ||
63 | |||
64 | if (newgroup_cons == NULL) | ||
65 | return -1; | ||
66 | |||
67 | g_c->cons = newgroup_cons; | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | /* Create a new empty groupchat connection. | ||
72 | * | ||
73 | * return -1 on failure. | ||
74 | * return con_number on success. | ||
75 | */ | ||
76 | static int create_group_con(Group_Chats *g_c) | ||
77 | { | ||
78 | uint32_t i; | ||
79 | |||
80 | for (i = 0; i < g_c->num_cons; ++i) { | ||
81 | if (g_c->cons[i].status == GROUPCON_STATUS_NONE) | ||
82 | return i; | ||
83 | } | ||
84 | |||
85 | int id = -1; | ||
86 | |||
87 | if (realloc_groupcons(g_c, g_c->num_cons + 1) == 0) { | ||
88 | id = g_c->num_cons; | ||
89 | ++g_c->num_cons; | ||
90 | memset(&(g_c->cons[id]), 0, sizeof(Group_Connection)); | ||
91 | } | ||
92 | |||
93 | return id; | ||
94 | } | ||
95 | |||
96 | /* Wipe a groupchat connection. | ||
97 | * | ||
98 | * return -1 on failure. | ||
99 | * return 0 on success. | ||
100 | */ | ||
101 | static int wipe_group_con(Group_Chats *g_c, int con_number) | ||
102 | { | ||
103 | if (con_number_not_valid(g_c, con_number)) | ||
104 | return -1; | ||
105 | |||
106 | uint32_t i; | ||
107 | memset(&(g_c->cons[con_number]), 0 , sizeof(Group_c)); | ||
108 | |||
109 | for (i = g_c->num_cons; i != 0; --i) { | ||
110 | if (g_c->cons[i - 1].status != GROUPCON_STATUS_NONE) | ||
111 | break; | ||
112 | } | ||
113 | |||
114 | if (g_c->num_cons != i) { | ||
115 | g_c->num_cons = i; | ||
116 | realloc_groupcons(g_c, g_c->num_cons); | ||
117 | } | ||
118 | |||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static Group_Connection *get_con_group(Group_Chats *g_c, int con_number) | ||
123 | { | ||
124 | if (con_number_not_valid(g_c, con_number)) | ||
125 | return 0; | ||
126 | |||
127 | return &g_c->cons[con_number]; | ||
128 | } | ||
129 | |||
130 | /* return 1 if the groupnumber is not valid. | ||
131 | * return 0 if the groupnumber is valid. | ||
132 | */ | ||
133 | static uint8_t groupnumber_not_valid(const Group_Chats *g_c, int groupnumber) | ||
134 | { | ||
135 | if ((unsigned int)groupnumber >= g_c->num_chats) | ||
136 | return 1; | ||
137 | |||
138 | if (g_c->chats == NULL) | ||
139 | return 1; | ||
140 | |||
141 | if (g_c->chats[groupnumber].status == GROUPCHAT_STATUS_NONE) | ||
142 | return 1; | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | |||
148 | /* Set the size of the groupchat list to num. | ||
149 | * | ||
150 | * return -1 if realloc fails. | ||
151 | * return 0 if it succeeds. | ||
152 | */ | ||
153 | static int realloc_groupchats(Group_Chats *g_c, uint32_t num) | ||
154 | { | ||
155 | if (num == 0) { | ||
156 | free(g_c->chats); | ||
157 | g_c->chats = NULL; | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | Group_c *newgroup_chats = realloc(g_c->chats, num * sizeof(Group_c)); | ||
162 | |||
163 | if (newgroup_chats == NULL) | ||
164 | return -1; | ||
165 | |||
166 | g_c->chats = newgroup_chats; | ||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | |||
171 | /* Create a new empty groupchat connection. | ||
172 | * | ||
173 | * return -1 on failure. | ||
174 | * return groupnumber on success. | ||
175 | */ | ||
176 | static int create_group_chat(Group_Chats *g_c) | ||
177 | { | ||
178 | uint32_t i; | ||
179 | |||
180 | for (i = 0; i < g_c->num_chats; ++i) { | ||
181 | if (g_c->chats[i].status == GROUPCHAT_STATUS_NONE) | ||
182 | return i; | ||
183 | } | ||
184 | |||
185 | int id = -1; | ||
186 | |||
187 | if (realloc_groupchats(g_c, g_c->num_chats + 1) == 0) { | ||
188 | id = g_c->num_chats; | ||
189 | ++g_c->num_chats; | ||
190 | memset(&(g_c->chats[id]), 0, sizeof(Group_c)); | ||
191 | } | ||
192 | |||
193 | return id; | ||
194 | } | ||
195 | |||
196 | |||
197 | /* Wipe a groupchat. | ||
198 | * | ||
199 | * return -1 on failure. | ||
200 | * return 0 on success. | ||
201 | */ | ||
202 | static int wipe_group_chat(Group_Chats *g_c, int groupnumber) | ||
203 | { | ||
204 | if (groupnumber_not_valid(g_c, groupnumber)) | ||
205 | return -1; | ||
206 | |||
207 | uint32_t i; | ||
208 | memset(&(g_c->chats[groupnumber]), 0 , sizeof(Group_c)); | ||
209 | |||
210 | for (i = g_c->num_chats; i != 0; --i) { | ||
211 | if (g_c->chats[i - 1].status != GROUPCHAT_STATUS_NONE) | ||
212 | break; | ||
213 | } | ||
214 | |||
215 | if (g_c->num_chats != i) { | ||
216 | g_c->num_chats = i; | ||
217 | realloc_groupchats(g_c, g_c->num_chats); | ||
218 | } | ||
219 | |||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static Group_c *get_group_c(Group_Chats *g_c, int groupnumber) | ||
224 | { | ||
225 | if (groupnumber_not_valid(g_c, groupnumber)) | ||
226 | return 0; | ||
227 | |||
228 | return &g_c->chats[groupnumber]; | ||
229 | } | ||
230 | |||
231 | /* | ||
232 | * check if peer with client_id is in peer array. | ||
233 | * | ||
234 | * return peer number if peer is in chat. | ||
235 | * return -1 if peer is not in chat. | ||
236 | * | ||
237 | * TODO: make this more efficient. | ||
238 | */ | ||
239 | |||
240 | static int peer_in_chat(const Group_c *chat, const uint8_t *client_id) | ||
241 | { | ||
242 | uint32_t i; | ||
243 | |||
244 | for (i = 0; i < chat->numpeers; ++i) | ||
245 | if (id_equal(chat->group[i].client_id, client_id)) | ||
246 | return i; | ||
247 | |||
248 | return -1; | ||
249 | } | ||
250 | |||
251 | /* | ||
252 | * Add a peer to the group chat. | ||
253 | * | ||
254 | * return peernum if success or peer already in chat. | ||
255 | * return -1 if error. | ||
256 | */ | ||
257 | static int addpeer(Group_c *chat, const uint8_t *client_id) | ||
258 | { | ||
259 | int peernum = peer_in_chat(chat, client_id); | ||
260 | |||
261 | if (peernum != -1) | ||
262 | return peernum; | ||
263 | |||
264 | Group_Peer *temp; | ||
265 | temp = realloc(chat->group, sizeof(Group_Peer) * (chat->numpeers + 1)); | ||
266 | |||
267 | if (temp == NULL) | ||
268 | return -1; | ||
269 | |||
270 | memset(&(temp[chat->numpeers]), 0, sizeof(Group_Peer)); | ||
271 | chat->group = temp; | ||
272 | |||
273 | id_copy(chat->group[chat->numpeers].client_id, client_id); | ||
274 | chat->group[chat->numpeers].last_recv = unix_time(); | ||
275 | chat->group[chat->numpeers].last_recv_msgping = unix_time(); | ||
276 | ++chat->numpeers; | ||
277 | |||
278 | //if (chat->peer_namelistchange != NULL) | ||
279 | // (*chat->peer_namelistchange)(chat, chat->numpeers - 1, CHAT_CHANGE_PEER_ADD, chat->group_namelistchange_userdata); | ||
280 | |||
281 | return (chat->numpeers - 1); | ||
282 | } | ||
283 | |||
284 | |||
285 | /* Creates a new groupchat and puts it in the chats array. | ||
286 | * | ||
287 | * return group number on success. | ||
288 | * return -1 on failure. | ||
289 | */ | ||
290 | int temp_c_add_groupchat(Group_Chats *g_c) | ||
291 | { | ||
292 | int groupnumber = create_group_chat(g_c); | ||
293 | |||
294 | Group_c *g = get_group_c(g_c, groupnumber); | ||
295 | |||
296 | if (!g) { | ||
297 | return -1; | ||
298 | } | ||
299 | |||
300 | g->status = GROUPCHAT_STATUS_VALID; | ||
301 | return groupnumber; | ||
302 | } | ||
303 | |||
304 | /* Create new groupchat instance. */ | ||
305 | Group_Chats *new_groupchats(Messenger *m) | ||
306 | { | ||
307 | if (!m) | ||
308 | return NULL; | ||
309 | |||
310 | Group_Chats *temp = calloc(1, sizeof(Group_Chats)); | ||
311 | |||
312 | if (temp == NULL) | ||
313 | return NULL; | ||
314 | |||
315 | temp->m = m; | ||
316 | return temp; | ||
317 | } | ||
318 | |||
319 | /* main groupchats loop. */ | ||
320 | void do_groupchats(Group_Chats *g_c) | ||
321 | { | ||
322 | //TODO | ||
323 | } | ||
324 | |||
325 | /* Free everything related with group chats. */ | ||
326 | void kill_groupchats(Group_Chats *g_c) | ||
327 | { | ||
328 | //TODO | ||
329 | free(g_c); | ||
330 | } | ||
331 | |||