2672
|
1 /*
|
|
2 * Server-Side/Stored Information.
|
|
3 *
|
|
4 * Relatively new facility that allows storing of certain types of information,
|
|
5 * such as a users buddy list, permit/deny list, and permit/deny preferences,
|
|
6 * to be stored on the server, so that they can be accessed from any client.
|
|
7 *
|
|
8 * This is entirely too complicated.
|
2991
|
9 * You don't know the half of it.
|
|
10 *
|
|
11 * XXX - Test for memory leaks
|
|
12 * XXX - Better parsing of rights, and use the rights info to limit adds
|
2672
|
13 *
|
|
14 */
|
|
15
|
|
16 #define FAIM_INTERNAL
|
|
17 #include <aim.h>
|
|
18
|
|
19 /*
|
2991
|
20 * Checks if the given screen name is anywhere in our buddy list.
|
|
21 */
|
|
22 faim_export int aim_ssi_inlist(aim_session_t *sess, aim_conn_t *conn, char *name, fu16_t type)
|
|
23 {
|
|
24 struct aim_ssi_item *cur;
|
3017
|
25 if (!sess && !conn && !name)
|
|
26 return -EINVAL;
|
2991
|
27 for (cur=sess->ssi.items; cur; cur=cur->next)
|
|
28 if ((cur->type==type) && (cur->name) && (!aim_sncmp(cur->name, name)))
|
|
29 return 1;
|
|
30 return 0;
|
|
31 }
|
|
32
|
|
33 /*
|
3017
|
34 * Return the parent group of a given buddy.
|
|
35 */
|
|
36 faim_export char *aim_ssi_getparentgroup(aim_session_t *sess, aim_conn_t *conn, char *name)
|
|
37 {
|
|
38 fu16_t gid;
|
|
39 struct aim_ssi_item *cur;
|
|
40 if (!sess && !conn && !name)
|
|
41 return NULL;
|
|
42 for (cur=sess->ssi.items; cur && (cur->type!=AIM_SSI_TYPE_BUDDY || !cur->name || aim_sncmp(cur->name, name)); cur=cur->next)
|
|
43 if (!cur)
|
|
44 return NULL;
|
|
45 gid = cur->gid;
|
|
46 for (cur=sess->ssi.items; cur; cur=cur->next)
|
|
47 if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid == gid) && (cur->name))
|
|
48 return cur->name;
|
|
49 return 0;
|
|
50 }
|
|
51
|
|
52 /*
|
2991
|
53 * Returns a pointer to an item with the given name and type, or NULL if one does not exist.
|
|
54 */
|
|
55 static struct aim_ssi_item *get_ssi_item(struct aim_ssi_item *items, char *name, fu16_t type)
|
|
56 {
|
|
57 struct aim_ssi_item *cur;
|
|
58 if (name) {
|
|
59 for (cur=items; cur; cur=cur->next)
|
|
60 if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, name)))
|
|
61 return cur;
|
3109
|
62 } else { /* return the given type with gid 0 */
|
2991
|
63 for (cur=items; cur; cur=cur->next)
|
|
64 if ((cur->type == type) && (cur->gid == 0x0000))
|
|
65 return cur;
|
|
66 }
|
|
67 return NULL;
|
|
68 }
|
|
69
|
|
70 /*
|
3109
|
71 * Returns the permit/deny byte
|
|
72 */
|
|
73 faim_export int aim_ssi_getpermdeny(aim_session_t *sess, aim_conn_t *conn)
|
|
74 {
|
|
75 struct aim_ssi_item *cur = get_ssi_item(sess->ssi.items, NULL, AIM_SSI_TYPE_PDINFO);
|
|
76 if (cur) {
|
|
77 aim_tlvlist_t *tlvlist = cur->data;
|
|
78 if (tlvlist) {
|
|
79 aim_tlv_t *tlv = aim_gettlv(tlvlist, 0x00ca, 1);
|
|
80 if (tlv && tlv->value)
|
|
81 return aimutil_get8(tlv->value);
|
|
82 }
|
|
83 }
|
|
84
|
|
85 return 0;
|
|
86 }
|
|
87
|
|
88 /*
|
|
89 * Returns the presence flag
|
|
90 * I'm pretty sure this is a bitmask, but really have no evidence for that.
|
|
91 * 0x00000400 - Show up as visible to others
|
|
92 */
|
|
93 faim_export fu32_t aim_ssi_getpresence(aim_session_t *sess, aim_conn_t *conn)
|
|
94 {
|
|
95 struct aim_ssi_item *cur = get_ssi_item(sess->ssi.items, NULL, AIM_SSI_TYPE_PRESENCEPREFS);
|
|
96 if (cur) {
|
|
97 aim_tlvlist_t *tlvlist = cur->data;
|
|
98 if (tlvlist) {
|
|
99 aim_tlv_t *tlv = aim_gettlv(tlvlist, 0x00c9, 1);
|
|
100 if (tlv && tlv->length)
|
|
101 return aimutil_get32(tlv->value);
|
|
102 }
|
|
103 }
|
|
104
|
|
105 return 0xFFFFFFFF;
|
|
106 }
|
|
107
|
|
108 /*
|
2991
|
109 * Add the given packet to the holding queue.
|
|
110 */
|
|
111 static int aim_ssi_enqueue(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr)
|
|
112 {
|
|
113 aim_frame_t *cur;
|
|
114
|
|
115 if (!sess || !conn || !fr)
|
|
116 return -EINVAL;
|
|
117
|
|
118 fr->next = NULL;
|
|
119 if (sess->ssi.holding_queue == NULL) {
|
|
120 sess->ssi.holding_queue = fr;
|
|
121 if (!sess->ssi.waiting_for_ack)
|
|
122 aim_ssi_modbegin(sess, conn);
|
|
123 } else {
|
|
124 for (cur = sess->ssi.holding_queue; cur->next; cur = cur->next) ;
|
|
125 cur->next = fr;
|
|
126 }
|
|
127
|
|
128 return 0;
|
|
129 }
|
|
130
|
|
131 /*
|
|
132 * Send the next SNAC from the holding queue.
|
|
133 */
|
|
134 static int aim_ssi_dispatch(aim_session_t *sess, aim_conn_t *conn)
|
|
135 {
|
|
136 aim_frame_t *cur;
|
|
137
|
|
138 if (!sess || !conn)
|
|
139 return -EINVAL;
|
|
140
|
|
141 if (!sess->ssi.waiting_for_ack) {
|
|
142 if (sess->ssi.holding_queue) {
|
|
143 sess->ssi.waiting_for_ack = 1;
|
|
144 cur = sess->ssi.holding_queue->next;
|
|
145 sess->ssi.holding_queue->next = NULL;
|
|
146 aim_tx_enqueue(sess, sess->ssi.holding_queue);
|
|
147 sess->ssi.holding_queue = cur;
|
|
148 } else
|
|
149 aim_ssi_modend(sess, conn);
|
|
150 }
|
|
151
|
|
152 return 0;
|
|
153 }
|
|
154
|
|
155 /*
|
|
156 * Rebuild the additional data for the given group(s).
|
|
157 */
|
|
158 static int aim_ssi_rebuildgroup(aim_session_t *sess, aim_conn_t *conn, struct aim_ssi_item *parentgroup)
|
|
159 {
|
|
160 int newlen;
|
|
161 struct aim_ssi_item *cur;
|
|
162
|
|
163 if (!sess || !conn || !parentgroup)
|
|
164 return -EINVAL;
|
|
165
|
|
166 /* Free the old additional data */
|
|
167 if (parentgroup->data) {
|
|
168 aim_freetlvchain((aim_tlvlist_t **)&parentgroup->data);
|
|
169 parentgroup->data = NULL;
|
|
170 }
|
|
171
|
|
172 /* Find the length for the new additional data */
|
|
173 newlen = 0;
|
|
174 if (parentgroup->gid == 0x0000) {
|
|
175 for (cur=sess->ssi.items; cur; cur=cur->next)
|
3017
|
176 if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP))
|
2991
|
177 newlen += 2;
|
|
178 } else {
|
|
179 for (cur=sess->ssi.items; cur; cur=cur->next)
|
3017
|
180 if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY))
|
2991
|
181 newlen += 2;
|
|
182 }
|
|
183
|
|
184 /* Rebuild the additional data */
|
|
185 if (newlen>0) {
|
|
186 aim_bstream_t tbs;
|
|
187 tbs.len = newlen+4;
|
|
188 tbs.offset = 0;
|
|
189 if (!(tbs.data = (fu8_t *)malloc((tbs.len)*sizeof(fu8_t))))
|
|
190 return -ENOMEM;
|
|
191 aimbs_put16(&tbs, 0x00c8);
|
|
192 aimbs_put16(&tbs, tbs.len-4);
|
|
193 if (parentgroup->gid == 0x0000) {
|
|
194 for (cur=sess->ssi.items; cur; cur=cur->next)
|
3017
|
195 if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP))
|
2991
|
196 aimbs_put16(&tbs, cur->gid);
|
|
197 } else {
|
|
198 for (cur=sess->ssi.items; cur; cur=cur->next)
|
3017
|
199 if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY))
|
2991
|
200 aimbs_put16(&tbs, cur->bid);
|
|
201 }
|
|
202 tbs.offset = 0;
|
|
203 parentgroup->data = (void *)aim_readtlvchain(&tbs);
|
|
204 free(tbs.data);
|
|
205
|
|
206 /* XXX - WHYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY does this crash?
|
|
207 fu8_t *newdata;
|
|
208 if (!(newdata = (fu8_t *)malloc((newlen)*sizeof(fu8_t))))
|
|
209 return -ENOMEM;
|
|
210 newlen = 0;
|
|
211 if (parentgroup->gid == 0x0000) {
|
|
212 for (cur=sess->ssi.items; cur; cur=cur->next)
|
3017
|
213 if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP)) {
|
2991
|
214 memcpy(&newdata[newlen*2], &cur->gid, 2);
|
|
215 newlen += 2;
|
|
216 }
|
|
217 } else {
|
|
218 for (cur=sess->ssi.items; cur; cur=cur->next)
|
3017
|
219 if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) {
|
|
220 memcpy(&newdata[newlen*2], &cur->bid, 2);
|
2991
|
221 newlen += 2;
|
|
222 }
|
|
223 }
|
|
224 aim_addtlvtochain_raw((aim_tlvlist_t **)&parentgroup->data, 0x00c8, newlen, newdata);
|
|
225 free(newdata); */
|
|
226 }
|
|
227
|
|
228 return 0;
|
|
229 }
|
|
230
|
|
231 /*
|
|
232 * Clears all of our locally stored buddy list information.
|
|
233 */
|
|
234 static int aim_ssi_freelist(aim_session_t *sess)
|
|
235 {
|
|
236 struct aim_ssi_item *cur, *delitem;
|
|
237
|
|
238 cur = sess->ssi.items;
|
|
239 while (cur) {
|
|
240 if (cur->name) free(cur->name);
|
|
241 if (cur->data) aim_freetlvchain((aim_tlvlist_t **)&cur->data);
|
|
242 delitem = cur;
|
|
243 cur = cur->next;
|
|
244 free(delitem);
|
|
245 }
|
|
246
|
|
247 sess->ssi.revision = 0;
|
|
248 sess->ssi.items = NULL;
|
|
249 sess->ssi.timestamp = (time_t)0;
|
|
250
|
|
251 return 0;
|
|
252 }
|
|
253
|
|
254 /*
|
|
255 * This removes all ssi data from server and local copy.
|
|
256 */
|
|
257 faim_export int aim_ssi_deletelist(aim_session_t *sess, aim_conn_t *conn)
|
|
258 {
|
3000
|
259 int num;
|
2991
|
260 struct aim_ssi_item *cur, **items;
|
|
261
|
|
262 for (cur=sess->ssi.items, num=0; cur; cur=cur->next)
|
|
263 num++;
|
|
264
|
|
265 if (!(items = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *))))
|
|
266 return -ENOMEM;
|
3017
|
267 memset(items, 0, num*sizeof(struct aim_ssi_item *));
|
2991
|
268 for (cur=sess->ssi.items, num=0; cur; cur=cur->next) {
|
|
269 items[num] = cur;
|
|
270 num++;
|
|
271 }
|
|
272
|
3017
|
273 aim_ssi_addmoddel(sess, conn, items, num, AIM_CB_SSI_DEL);
|
2995
|
274 free(items);
|
2991
|
275 aim_ssi_dispatch(sess, conn);
|
|
276 aim_ssi_freelist(sess);
|
|
277
|
|
278 return 0;
|
|
279 }
|
|
280
|
|
281 /*
|
|
282 * This "cleans" the ssi list. It makes sure all buddies are in a group, and
|
|
283 * all groups have additional data for the buddies that are in them. It does
|
|
284 * this by rebuilding the additional data for every group, sending mod SNACs
|
|
285 * as necessary.
|
|
286 */
|
|
287 faim_export int aim_ssi_cleanlist(aim_session_t *sess, aim_conn_t *conn)
|
|
288 {
|
|
289 unsigned int num_to_be_fixed;
|
|
290 struct aim_ssi_item *cur, *parentgroup;
|
|
291
|
|
292 /* Make sure we actually need to clean out the list */
|
|
293 for (cur=sess->ssi.items, num_to_be_fixed=0; cur; cur=cur->next) {
|
|
294 /* Any buddies directly in the master group */
|
3017
|
295 if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->gid == 0x0000))
|
2991
|
296 num_to_be_fixed++;
|
|
297 }
|
|
298 if (!num_to_be_fixed)
|
|
299 return 0;
|
|
300
|
|
301 /* Remove all the additional data from all groups and buddies */
|
|
302 for (cur=sess->ssi.items; cur; cur=cur->next)
|
3017
|
303 if (cur->data && ((cur->type == AIM_SSI_TYPE_BUDDY) || (cur->type == AIM_SSI_TYPE_GROUP))) {
|
2991
|
304 aim_freetlvchain((aim_tlvlist_t **)&cur->data);
|
|
305 cur->data = NULL;
|
|
306 }
|
|
307
|
|
308 /* If there are buddies directly in the master group, make sure */
|
|
309 /* there is a group to put them in. Any group, any group at all. */
|
3017
|
310 for (cur=sess->ssi.items; ((cur) && ((cur->type != AIM_SSI_TYPE_BUDDY) || (cur->gid != 0x0000))); cur=cur->next);
|
2991
|
311 if (!cur) {
|
3017
|
312 for (parentgroup=sess->ssi.items; ((parentgroup) && ((parentgroup->type!=AIM_SSI_TYPE_GROUP) || (parentgroup->gid!=0x0000))); parentgroup=parentgroup->next);
|
2991
|
313 if (!parentgroup) {
|
|
314 char *newgroup;
|
|
315 newgroup = (char*)malloc(strlen("Unknown")*sizeof(char));
|
|
316 strcpy(newgroup, "Unknown");
|
|
317 aim_ssi_addgroups(sess, conn, &newgroup, 1);
|
|
318 }
|
|
319 }
|
|
320
|
|
321 /* Set parentgroup equal to any arbitray group */
|
3017
|
322 for (parentgroup=sess->ssi.items; parentgroup->gid==0x0000 || parentgroup->type!=AIM_SSI_TYPE_GROUP; parentgroup=parentgroup->next);
|
2991
|
323
|
|
324 /* If there are any buddies directly in the master group, put them in a real group */
|
|
325 for (cur=sess->ssi.items; cur; cur=cur->next)
|
3017
|
326 if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->gid == 0x0000)) {
|
|
327 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_DEL);
|
2991
|
328 cur->gid = parentgroup->gid;
|
3017
|
329 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD);
|
2991
|
330 }
|
|
331
|
|
332 /* Rebuild additional data for all groups */
|
|
333 for (parentgroup=sess->ssi.items; parentgroup; parentgroup=parentgroup->next)
|
3017
|
334 if (parentgroup->type == AIM_SSI_TYPE_GROUP)
|
2991
|
335 aim_ssi_rebuildgroup(sess, conn, parentgroup);
|
|
336
|
|
337 /* Send a mod snac for all groups */
|
|
338 for (cur=sess->ssi.items; cur; cur=cur->next)
|
3017
|
339 if (cur->type == AIM_SSI_TYPE_GROUP)
|
|
340 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_MOD);
|
2991
|
341
|
|
342 /* Begin sending SSI SNACs */
|
|
343 aim_ssi_dispatch(sess, conn);
|
|
344
|
|
345 return 0;
|
|
346 }
|
|
347
|
|
348 /*
|
|
349 * The next few functions take data as screen names and groups,
|
|
350 * modifies the ssi item list, and calls the functions to
|
|
351 * add, mod, or del an item or items.
|
|
352 *
|
|
353 * These are what the client should call. The client should
|
|
354 * also make sure it's not adding a buddy that's already in
|
|
355 * the list (using aim_ssi_inlist).
|
|
356 */
|
|
357 faim_export int aim_ssi_addbuddies(aim_session_t *sess, aim_conn_t *conn, char *gn, char **sn, unsigned int num)
|
|
358 {
|
|
359 struct aim_ssi_item *cur, *parentgroup, **newitems;
|
|
360 fu16_t i, j;
|
|
361
|
|
362 if (!sess || !conn || !gn || !sn || !num)
|
|
363 return -EINVAL;
|
|
364
|
|
365 /* Look up the parent group */
|
3017
|
366 if (!(parentgroup = get_ssi_item(sess->ssi.items, gn, AIM_SSI_TYPE_GROUP))) {
|
2991
|
367 aim_ssi_addgroups(sess, conn, &gn, 1);
|
3017
|
368 if (!(parentgroup = get_ssi_item(sess->ssi.items, gn, AIM_SSI_TYPE_GROUP)))
|
2991
|
369 return -ENOMEM;
|
|
370 }
|
|
371
|
|
372 /* Allocate an array of pointers to each of the new items */
|
|
373 if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *))))
|
|
374 return -ENOMEM;
|
3017
|
375 memset(newitems, 0, num*sizeof(struct aim_ssi_item *));
|
2991
|
376
|
|
377 /* The following for loop iterates once per item that needs to be added. */
|
|
378 /* For each i, create an item and tack it onto the newitems array */
|
|
379 for (i=0; i<num; i++) {
|
|
380 if (!(newitems[i] = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) {
|
|
381 for (j=0; j<(i-1); j++) {
|
|
382 free(newitems[j]->name);
|
|
383 free(newitems[j]);
|
|
384 }
|
|
385 free(newitems);
|
|
386 return -ENOMEM;
|
|
387 }
|
|
388 if (!(newitems[i]->name = (char *)malloc((strlen(sn[i])+1)*sizeof(char)))) {
|
|
389 for (j=0; j<(i-1); j++) {
|
|
390 free(newitems[j]->name);
|
|
391 free(newitems[j]);
|
|
392 }
|
|
393 free(newitems[i]);
|
|
394 free(newitems);
|
|
395 return -ENOMEM;
|
|
396 }
|
|
397 strcpy(newitems[i]->name, sn[i]);
|
|
398 newitems[i]->gid = parentgroup->gid;
|
|
399 newitems[i]->bid = i ? newitems[i-1]->bid : 0;
|
|
400 do {
|
|
401 newitems[i]->bid += 0x0001;
|
|
402 for (cur=sess->ssi.items, j=0; ((cur) && (!j)); cur=cur->next)
|
3017
|
403 if ((cur->bid == newitems[i]->bid) && (cur->gid == newitems[i]->gid) && (cur->type == AIM_SSI_TYPE_BUDDY))
|
2991
|
404 j=1;
|
|
405 } while (j);
|
3017
|
406 newitems[i]->type = AIM_SSI_TYPE_BUDDY;
|
2991
|
407 newitems[i]->data = NULL;
|
|
408 newitems[i]->next = i ? newitems[i-1] : NULL;
|
|
409 }
|
|
410
|
|
411 /* Add the items to our list */
|
|
412 newitems[0]->next = sess->ssi.items;
|
|
413 sess->ssi.items = newitems[num-1];
|
|
414
|
|
415 /* Send the add item SNAC */
|
3017
|
416 aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD);
|
2991
|
417
|
|
418 /* Free the array of pointers to each of the new items */
|
|
419 free(newitems);
|
|
420
|
|
421 /* Rebuild the additional data in the parent group */
|
|
422 aim_ssi_rebuildgroup(sess, conn, parentgroup);
|
|
423
|
|
424 /* Send the mod item SNAC */
|
3017
|
425 aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD);
|
|
426
|
|
427 /* Begin sending SSI SNACs */
|
|
428 aim_ssi_dispatch(sess, conn);
|
|
429
|
|
430 return 0;
|
|
431 }
|
|
432
|
|
433 /*
|
|
434 * This adds the master group (the group containing all groups) if it doesn't exist.
|
|
435 * It's called by aim_ssi_addgroups, if your list is empty.
|
|
436 */
|
|
437 faim_export int aim_ssi_addmastergroup(aim_session_t *sess, aim_conn_t *conn) {
|
|
438 struct aim_ssi_item *newitem;
|
|
439
|
|
440 if (!sess || !conn)
|
|
441 return -EINVAL;
|
|
442
|
|
443 /* Allocate an array of pointers to each of the new items */
|
|
444 if (!(newitem = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item))))
|
|
445 return -ENOMEM;
|
|
446 memset(newitem, 0, sizeof(struct aim_ssi_item));
|
|
447
|
|
448 /* memset to 0 sets most of the vars to what they should be */
|
|
449 newitem->type = AIM_SSI_TYPE_GROUP;
|
|
450
|
|
451 /* Add the item to our list */
|
|
452 newitem->next = sess->ssi.items;
|
|
453 sess->ssi.items = newitem;
|
|
454
|
|
455 /* If there are any existing groups (technically there shouldn't be, but */
|
|
456 /* just in case) then add their group ID#'s to the additional data */
|
|
457 if (sess->ssi.items)
|
|
458 aim_ssi_rebuildgroup(sess, conn, newitem);
|
|
459
|
|
460 /* Send the add item SNAC */
|
|
461 aim_ssi_addmoddel(sess, conn, &newitem, 1, AIM_CB_SSI_ADD);
|
2991
|
462
|
|
463 /* Begin sending SSI SNACs */
|
|
464 aim_ssi_dispatch(sess, conn);
|
|
465
|
|
466 return 0;
|
|
467 }
|
|
468
|
|
469 faim_export int aim_ssi_addgroups(aim_session_t *sess, aim_conn_t *conn, char **gn, unsigned int num)
|
|
470 {
|
|
471 struct aim_ssi_item *cur, *parentgroup, **newitems;
|
|
472 fu16_t i, j;
|
|
473
|
|
474 if (!sess || !conn || !gn || !num)
|
|
475 return -EINVAL;
|
|
476
|
|
477 /* Look up the parent group */
|
3017
|
478 if (!(parentgroup = get_ssi_item(sess->ssi.items, NULL, AIM_SSI_TYPE_GROUP))) {
|
2991
|
479 aim_ssi_addmastergroup(sess, conn);
|
3017
|
480 if (!(parentgroup = get_ssi_item(sess->ssi.items, NULL, AIM_SSI_TYPE_GROUP)))
|
2991
|
481 return -ENOMEM;
|
|
482 }
|
|
483
|
|
484 /* Allocate an array of pointers to each of the new items */
|
|
485 if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *))))
|
|
486 return -ENOMEM;
|
3017
|
487 memset(newitems, 0, num*sizeof(struct aim_ssi_item *));
|
2991
|
488
|
|
489 /* The following for loop iterates once per item that needs to be added. */
|
|
490 /* For each i, create an item and tack it onto the newitems array */
|
|
491 for (i=0; i<num; i++) {
|
|
492 if (!(newitems[i] = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) {
|
|
493 for (j=0; j<(i-1); j++) {
|
|
494 free(newitems[j]->name);
|
|
495 free(newitems[j]);
|
|
496 }
|
|
497 free(newitems);
|
|
498 return -ENOMEM;
|
|
499 }
|
|
500 if (!(newitems[i]->name = (char *)malloc((strlen(gn[i])+1)*sizeof(char)))) {
|
|
501 for (j=0; j<(i-1); j++) {
|
|
502 free(newitems[j]->name);
|
|
503 free(newitems[j]);
|
|
504 }
|
|
505 free(newitems[i]);
|
|
506 free(newitems);
|
|
507 return -ENOMEM;
|
|
508 }
|
|
509 strcpy(newitems[i]->name, gn[i]);
|
|
510 newitems[i]->gid = i ? newitems[i-1]->gid : 0;
|
|
511 do {
|
|
512 newitems[i]->gid += 0x0001;
|
|
513 for (cur=sess->ssi.items, j=0; ((cur) && (!j)); cur=cur->next)
|
3017
|
514 if ((cur->gid == newitems[i]->gid) && (cur->type == AIM_SSI_TYPE_GROUP))
|
2991
|
515 j=1;
|
|
516 } while (j);
|
|
517 newitems[i]->bid = 0x0000;
|
3017
|
518 newitems[i]->type = AIM_SSI_TYPE_GROUP;
|
2991
|
519 newitems[i]->data = NULL;
|
|
520 newitems[i]->next = i ? newitems[i-1] : NULL;
|
|
521 }
|
|
522
|
|
523 /* Add the items to our list */
|
|
524 newitems[0]->next = sess->ssi.items;
|
|
525 sess->ssi.items = newitems[num-1];
|
|
526
|
|
527 /* Send the add item SNAC */
|
3017
|
528 aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD);
|
2991
|
529
|
|
530 /* Free the array of pointers to each of the new items */
|
|
531 free(newitems);
|
|
532
|
|
533 /* Rebuild the additional data in the parent group */
|
|
534 aim_ssi_rebuildgroup(sess, conn, parentgroup);
|
|
535
|
|
536 /* Send the mod item SNAC */
|
3017
|
537 aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD);
|
2991
|
538
|
|
539 /* Begin sending SSI SNACs */
|
|
540 aim_ssi_dispatch(sess, conn);
|
|
541
|
|
542 return 0;
|
|
543 }
|
|
544
|
3017
|
545 /*
|
|
546 * Add permit or deny buddies to the permit or deny list.
|
|
547 * The buddies are passed as an array of pointers to char strings.
|
|
548 */
|
|
549 faim_export int aim_ssi_addpord(aim_session_t *sess, aim_conn_t *conn, char **sn, unsigned int num, fu16_t type)
|
2991
|
550 {
|
|
551 struct aim_ssi_item *cur, **newitems;
|
|
552 fu16_t i, j;
|
|
553
|
3017
|
554 if (!sess || !conn || !sn || !num || (type!=AIM_SSI_TYPE_PERMIT && type!=AIM_SSI_TYPE_DENY))
|
2991
|
555 return -EINVAL;
|
|
556
|
|
557 /* Allocate an array of pointers to each of the new items */
|
|
558 if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *))))
|
|
559 return -ENOMEM;
|
3017
|
560 memset(newitems, 0, num*sizeof(struct aim_ssi_item *));
|
2991
|
561
|
|
562 /* The following for loop iterates once per item that needs to be added. */
|
|
563 /* For each i, create an item and tack it onto the newitems array */
|
|
564 for (i=0; i<num; i++) {
|
|
565 if (!(newitems[i] = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) {
|
|
566 for (j=0; j<(i-1); j++) {
|
|
567 free(newitems[j]->name);
|
|
568 free(newitems[j]);
|
|
569 }
|
|
570 free(newitems);
|
|
571 return -ENOMEM;
|
|
572 }
|
|
573 if (!(newitems[i]->name = (char *)malloc((strlen(sn[i])+1)*sizeof(char)))) {
|
|
574 for (j=0; j<(i-1); j++) {
|
|
575 free(newitems[j]->name);
|
|
576 free(newitems[j]);
|
|
577 }
|
|
578 free(newitems[i]);
|
|
579 free(newitems);
|
|
580 return -ENOMEM;
|
|
581 }
|
|
582 strcpy(newitems[i]->name, sn[i]);
|
|
583 newitems[i]->gid = 0x0000;
|
|
584 newitems[i]->bid = i ? newitems[i-1]->bid : 0x0000;
|
|
585 do {
|
|
586 newitems[i]->bid += 0x0001;
|
|
587 for (cur=sess->ssi.items, j=0; ((cur) && (!j)); cur=cur->next)
|
3017
|
588 if ((cur->bid == newitems[i]->bid) && ((cur->type == AIM_SSI_TYPE_PERMIT) || (cur->type == AIM_SSI_TYPE_DENY)))
|
2991
|
589 j=1;
|
|
590 } while (j);
|
3017
|
591 newitems[i]->type = type;
|
2991
|
592 newitems[i]->data = NULL;
|
|
593 newitems[i]->next = i ? newitems[i-1] : NULL;
|
|
594 }
|
|
595
|
|
596 /* Add the items to our list */
|
|
597 newitems[0]->next = sess->ssi.items;
|
|
598 sess->ssi.items = newitems[num-1];
|
|
599
|
|
600 /* Send the add item SNAC */
|
3017
|
601 aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD);
|
2991
|
602
|
|
603 /* Free the array of pointers to each of the new items */
|
|
604 free(newitems);
|
|
605
|
|
606 /* Begin sending SSI SNACs */
|
|
607 aim_ssi_dispatch(sess, conn);
|
|
608
|
|
609 return 0;
|
|
610 }
|
|
611
|
3140
|
612 faim_export int aim_ssi_movebuddy(aim_session_t *sess, aim_conn_t *conn, char *oldgn, char *newgn, char *sn)
|
|
613 {
|
|
614 struct aim_ssi_item **groups, *buddy, *cur;
|
|
615 fu16_t i;
|
|
616
|
|
617 if (!sess || !conn || !oldgn || !newgn || !sn)
|
|
618 return -EINVAL;
|
|
619
|
|
620 /* Look up the buddy */
|
|
621 if (!(buddy = get_ssi_item(sess->ssi.items, sn, AIM_SSI_TYPE_BUDDY)))
|
|
622 return -ENOMEM;
|
|
623
|
|
624 /* Allocate an array of pointers to the two groups */
|
|
625 if (!(groups = (struct aim_ssi_item **)malloc(2*sizeof(struct aim_ssi_item *))))
|
|
626 return -ENOMEM;
|
|
627
|
|
628 /* Look up the old parent group */
|
|
629 if (!(groups[0] = get_ssi_item(sess->ssi.items, oldgn, AIM_SSI_TYPE_GROUP))) {
|
|
630 free(groups);
|
|
631 return -ENOMEM;
|
|
632 }
|
|
633
|
|
634 /* Look up the new parent group */
|
|
635 if (!(groups[1] = get_ssi_item(sess->ssi.items, newgn, AIM_SSI_TYPE_GROUP))) {
|
|
636 free(groups);
|
|
637 return -ENOMEM;
|
|
638 }
|
|
639
|
|
640 /* Send the delete item SNAC */
|
|
641 aim_ssi_addmoddel(sess, conn, &buddy, 1, AIM_CB_SSI_DEL);
|
|
642
|
|
643 /* Put the buddy in the new group */
|
|
644 buddy->gid = groups[1]->gid;
|
|
645
|
|
646 /* Assign a new buddy ID#, because the new group might already have a buddy with this ID# */
|
|
647 buddy->bid = 0;
|
|
648 do {
|
|
649 buddy->bid += 0x0001;
|
|
650 for (cur=sess->ssi.items, i=0; ((cur) && (!i)); cur=cur->next)
|
|
651 if ((cur->bid == buddy->bid) && (cur->gid == buddy->gid) && (cur->type == AIM_SSI_TYPE_BUDDY) && (cur->name) && aim_sncmp(cur->name, buddy->name))
|
|
652 i=1;
|
|
653 } while (i);
|
|
654
|
|
655 /* Rebuild the additional data in the two parent groups */
|
|
656 aim_ssi_rebuildgroup(sess, conn, groups[0]);
|
|
657 aim_ssi_rebuildgroup(sess, conn, groups[1]);
|
|
658
|
|
659 /* Send the add item SNAC */
|
|
660 aim_ssi_addmoddel(sess, conn, &buddy, 1, AIM_CB_SSI_ADD);
|
|
661
|
|
662 /* Send the mod item SNAC */
|
|
663 aim_ssi_addmoddel(sess, conn, groups, 2, AIM_CB_SSI_MOD);
|
|
664
|
|
665 /* Free the temporary array */
|
|
666 free(groups);
|
|
667
|
|
668 /* Begin sending SSI SNACs */
|
|
669 aim_ssi_dispatch(sess, conn);
|
|
670
|
|
671 return 0;
|
|
672 }
|
|
673
|
2991
|
674 faim_export int aim_ssi_delbuddies(aim_session_t *sess, aim_conn_t *conn, char *gn, char **sn, unsigned int num)
|
|
675 {
|
|
676 struct aim_ssi_item *cur, *parentgroup, **delitems;
|
|
677 int i;
|
|
678
|
|
679 if (!sess || !conn || !gn || !sn || !num)
|
|
680 return -EINVAL;
|
|
681
|
|
682 /* Look up the parent group */
|
3017
|
683 if (!(parentgroup = get_ssi_item(sess->ssi.items, gn, AIM_SSI_TYPE_GROUP)))
|
2991
|
684 return -EINVAL;
|
|
685
|
|
686 /* Allocate an array of pointers to each of the items to be deleted */
|
|
687 delitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *));
|
3017
|
688 memset(delitems, 0, num*sizeof(struct aim_ssi_item *));
|
2991
|
689
|
|
690 /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */
|
|
691 for (i=0; i<num; i++) {
|
3017
|
692 if (!(delitems[i] = get_ssi_item(sess->ssi.items, sn[i], AIM_SSI_TYPE_BUDDY))) {
|
2991
|
693 free(delitems);
|
|
694 return -EINVAL;
|
|
695 }
|
|
696
|
|
697 /* Remove the delitems from the item list */
|
|
698 if (sess->ssi.items == delitems[i]) {
|
|
699 sess->ssi.items = sess->ssi.items->next;
|
|
700 } else {
|
|
701 for (cur=sess->ssi.items; (cur->next && (cur->next!=delitems[i])); cur=cur->next);
|
|
702 if (cur->next)
|
|
703 cur->next = cur->next->next;
|
|
704 }
|
|
705 }
|
|
706
|
|
707 /* Send the del item SNAC */
|
3017
|
708 aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL);
|
2991
|
709
|
|
710 /* Free the items */
|
|
711 for (i=0; i<num; i++) {
|
|
712 if (delitems[i]->name)
|
|
713 free(delitems[i]->name);
|
|
714 if (delitems[i]->data)
|
|
715 aim_freetlvchain((aim_tlvlist_t **)&delitems[i]->data);
|
|
716 free(delitems[i]);
|
|
717 }
|
|
718 free(delitems);
|
|
719
|
|
720 /* Rebuild the additional data in the parent group */
|
|
721 aim_ssi_rebuildgroup(sess, conn, parentgroup);
|
|
722
|
|
723 /* Send the mod item SNAC */
|
3017
|
724 aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD);
|
2991
|
725
|
|
726 /* Delete the group, but only if it's empty */
|
|
727 if (!parentgroup->data)
|
|
728 aim_ssi_delgroups(sess, conn, &parentgroup->name, 1);
|
|
729
|
|
730 /* Begin sending SSI SNACs */
|
|
731 aim_ssi_dispatch(sess, conn);
|
|
732
|
|
733 return 0;
|
|
734 }
|
|
735
|
3017
|
736 faim_export int aim_ssi_delmastergroup(aim_session_t *sess, aim_conn_t *conn) {
|
|
737 struct aim_ssi_item *cur, *delitem;
|
|
738
|
|
739 if (!sess || !conn)
|
|
740 return -EINVAL;
|
|
741
|
|
742 /* Make delitem a pointer to the aim_ssi_item to be deleted */
|
|
743 if (!(delitem = get_ssi_item(sess->ssi.items, NULL, AIM_SSI_TYPE_GROUP)))
|
|
744 return -EINVAL;
|
|
745
|
|
746 /* Remove delitem from the item list */
|
|
747 if (sess->ssi.items == delitem) {
|
|
748 sess->ssi.items = sess->ssi.items->next;
|
|
749 } else {
|
|
750 for (cur=sess->ssi.items; (cur->next && (cur->next!=delitem)); cur=cur->next);
|
|
751 if (cur->next)
|
|
752 cur->next = cur->next->next;
|
|
753 }
|
|
754
|
|
755 /* Send the del item SNAC */
|
|
756 aim_ssi_addmoddel(sess, conn, &delitem, 1, AIM_CB_SSI_DEL);
|
|
757
|
|
758 /* Free the item */
|
|
759 if (delitem->name)
|
|
760 free(delitem->name);
|
|
761 if (delitem->data)
|
|
762 aim_freetlvchain((aim_tlvlist_t **)&delitem->data);
|
|
763 free(delitem);
|
|
764
|
|
765 /* Begin sending SSI SNACs */
|
|
766 aim_ssi_dispatch(sess, conn);
|
|
767
|
|
768 return 0;
|
|
769 }
|
|
770
|
|
771 faim_export int aim_ssi_delgroups(aim_session_t *sess, aim_conn_t *conn, char **gn, unsigned int num) {
|
|
772 struct aim_ssi_item *cur, *parentgroup, **delitems;
|
2991
|
773 int i;
|
|
774
|
3017
|
775 if (!sess || !conn || !gn || !num)
|
|
776 return -EINVAL;
|
|
777
|
|
778 /* Look up the parent group */
|
|
779 if (!(parentgroup = get_ssi_item(sess->ssi.items, NULL, AIM_SSI_TYPE_GROUP)))
|
2991
|
780 return -EINVAL;
|
|
781
|
|
782 /* Allocate an array of pointers to each of the items to be deleted */
|
|
783 delitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *));
|
3017
|
784 memset(delitems, 0, num*sizeof(struct aim_ssi_item *));
|
2991
|
785
|
|
786 /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */
|
|
787 for (i=0; i<num; i++) {
|
3017
|
788 if (!(delitems[i] = get_ssi_item(sess->ssi.items, gn[i], AIM_SSI_TYPE_GROUP))) {
|
2991
|
789 free(delitems);
|
|
790 return -EINVAL;
|
|
791 }
|
|
792
|
|
793 /* Remove the delitems from the item list */
|
|
794 if (sess->ssi.items == delitems[i]) {
|
|
795 sess->ssi.items = sess->ssi.items->next;
|
|
796 } else {
|
|
797 for (cur=sess->ssi.items; (cur->next && (cur->next!=delitems[i])); cur=cur->next);
|
|
798 if (cur->next)
|
|
799 cur->next = cur->next->next;
|
|
800 }
|
|
801 }
|
|
802
|
|
803 /* Send the del item SNAC */
|
3017
|
804 aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL);
|
2991
|
805
|
|
806 /* Free the items */
|
|
807 for (i=0; i<num; i++) {
|
|
808 if (delitems[i]->name)
|
|
809 free(delitems[i]->name);
|
|
810 if (delitems[i]->data)
|
|
811 aim_freetlvchain((aim_tlvlist_t **)&delitems[i]->data);
|
|
812 free(delitems[i]);
|
|
813 }
|
|
814 free(delitems);
|
|
815
|
3017
|
816 /* Rebuild the additional data in the parent group */
|
|
817 aim_ssi_rebuildgroup(sess, conn, parentgroup);
|
|
818
|
|
819 /* Send the mod item SNAC */
|
|
820 aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD);
|
|
821
|
|
822 /* Delete the group, but only if it's empty */
|
|
823 if (!parentgroup->data)
|
|
824 aim_ssi_delmastergroup(sess, conn);
|
|
825
|
2991
|
826 /* Begin sending SSI SNACs */
|
|
827 aim_ssi_dispatch(sess, conn);
|
|
828
|
|
829 return 0;
|
|
830 }
|
|
831
|
3017
|
832 faim_export int aim_ssi_delpord(aim_session_t *sess, aim_conn_t *conn, char **sn, unsigned int num, fu16_t type) {
|
2991
|
833 struct aim_ssi_item *cur, **delitems;
|
|
834 int i;
|
|
835
|
3017
|
836 if (!sess || !conn || !sn || !num || (type!=AIM_SSI_TYPE_PERMIT && type!=AIM_SSI_TYPE_DENY))
|
2991
|
837 return -EINVAL;
|
|
838
|
|
839 /* Allocate an array of pointers to each of the items to be deleted */
|
|
840 delitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *));
|
3017
|
841 memset(delitems, 0, num*sizeof(struct aim_ssi_item *));
|
2991
|
842
|
|
843 /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */
|
|
844 for (i=0; i<num; i++) {
|
3017
|
845 if (!(delitems[i] = get_ssi_item(sess->ssi.items, sn[i], type))) {
|
2991
|
846 free(delitems);
|
|
847 return -EINVAL;
|
|
848 }
|
|
849
|
|
850 /* Remove the delitems from the item list */
|
|
851 if (sess->ssi.items == delitems[i]) {
|
|
852 sess->ssi.items = sess->ssi.items->next;
|
|
853 } else {
|
|
854 for (cur=sess->ssi.items; (cur->next && (cur->next!=delitems[i])); cur=cur->next);
|
|
855 if (cur->next)
|
|
856 cur->next = cur->next->next;
|
|
857 }
|
|
858 }
|
|
859
|
|
860 /* Send the del item SNAC */
|
3017
|
861 aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL);
|
2991
|
862
|
|
863 /* Free the items */
|
|
864 for (i=0; i<num; i++) {
|
|
865 if (delitems[i]->name)
|
|
866 free(delitems[i]->name);
|
|
867 if (delitems[i]->data)
|
|
868 aim_freetlvchain((aim_tlvlist_t **)&delitems[i]->data);
|
|
869 free(delitems[i]);
|
|
870 }
|
|
871 free(delitems);
|
|
872
|
|
873 /* Begin sending SSI SNACs */
|
|
874 aim_ssi_dispatch(sess, conn);
|
|
875
|
|
876 return 0;
|
|
877 }
|
|
878
|
|
879 /*
|
|
880 * Stores your permit/deny setting on the server, and starts using it.
|
|
881 * The permit/deny byte should be:
|
|
882 * 1 - Allow all users
|
|
883 * 2 - Block all users
|
|
884 * 3 - Allow only the users below
|
|
885 * 4 - Block the users below
|
|
886 * 5 - Allow only users on my buddy list
|
|
887 * To block AIM users, change the x00cb tlv from xffff to x0004
|
|
888 */
|
|
889 faim_export int aim_ssi_setpermdeny(aim_session_t *sess, aim_conn_t *conn, int permdeny) {
|
|
890 struct aim_ssi_item *cur, *tmp;
|
3000
|
891 fu16_t j;
|
2991
|
892 aim_tlv_t *tlv;
|
|
893
|
|
894 if (!sess || !conn)
|
|
895 return -EINVAL;
|
|
896
|
|
897 /* Look up the permit/deny settings item */
|
3109
|
898 cur = get_ssi_item(sess->ssi.items, NULL, AIM_SSI_TYPE_PDINFO);
|
2991
|
899
|
|
900 if (cur) {
|
|
901 /* The permit/deny item exists */
|
|
902 if (cur->data && (tlv = aim_gettlv(cur->data, 0x00ca, 1))) {
|
|
903 /* Just change the value of the x00ca TLV */
|
|
904 if (tlv->length != 1) {
|
|
905 tlv->length = 1;
|
|
906 free(tlv->value);
|
|
907 tlv->value = (fu8_t *)malloc(sizeof(fu8_t));
|
|
908 }
|
3090
|
909 tlv->value[0] = permdeny;
|
2991
|
910 } else {
|
|
911 /* Need to add the x00ca TLV to the TLV chain */
|
|
912 aim_addtlvtochain8((aim_tlvlist_t**)&cur->data, 0x00ca, permdeny);
|
|
913 }
|
|
914
|
|
915 /* Send the mod item SNAC */
|
3017
|
916 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_MOD);
|
2991
|
917 } else {
|
|
918 /* Need to add the permit/deny item */
|
|
919 if (!(cur = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item))))
|
|
920 return -ENOMEM;
|
|
921 cur->name = NULL;
|
|
922 cur->gid = 0x0000;
|
|
923 cur->bid = 0x007a; /* XXX - Is this number significant? */
|
|
924 do {
|
|
925 cur->bid += 0x0001;
|
|
926 for (tmp=sess->ssi.items, j=0; ((tmp) && (!j)); tmp=tmp->next)
|
|
927 if (tmp->bid == cur->bid)
|
|
928 j=1;
|
|
929 } while (j);
|
3017
|
930 cur->type = AIM_SSI_TYPE_PDINFO;
|
2991
|
931 cur->data = NULL;
|
|
932 aim_addtlvtochain8((aim_tlvlist_t**)&cur->data, 0x00ca, permdeny);
|
|
933 aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00cb, 0xffffffff);
|
|
934
|
|
935 /* Add the item to our list */
|
|
936 cur->next = sess->ssi.items;
|
|
937 sess->ssi.items = cur;
|
|
938
|
|
939 /* Send the add item SNAC */
|
3017
|
940 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD);
|
2991
|
941 }
|
|
942
|
|
943 /* Begin sending SSI SNACs */
|
|
944 aim_ssi_dispatch(sess, conn);
|
|
945
|
|
946 return 0;
|
|
947 }
|
|
948
|
|
949 /*
|
3109
|
950 * Stores your setting for whether you should show up as idle or not.
|
|
951 * presence is a bitmask (at least, I think so...)
|
|
952 * 0x00000400 if you want others to see your idle time
|
|
953 */
|
|
954 faim_export int aim_ssi_setpresence(aim_session_t *sess, aim_conn_t *conn, fu32_t presence) {
|
|
955 struct aim_ssi_item *cur, *tmp;
|
|
956 fu16_t j;
|
|
957 aim_tlv_t *tlv;
|
|
958
|
|
959 if (!sess || !conn)
|
|
960 return -EINVAL;
|
|
961
|
|
962 /* Look up the item */
|
|
963 cur = get_ssi_item(sess->ssi.items, NULL, AIM_SSI_TYPE_PRESENCEPREFS);
|
|
964
|
|
965 if (cur) {
|
|
966 /* The item exists */
|
|
967 if (cur->data && (tlv = aim_gettlv(cur->data, 0x00c9, 1))) {
|
|
968 /* Just change the value of the x00c9 TLV */
|
|
969 if (tlv->length != 4) {
|
|
970 tlv->length = 4;
|
|
971 free(tlv->value);
|
|
972 tlv->value = (fu8_t *)malloc(4*sizeof(fu8_t));
|
|
973 }
|
|
974 aimutil_put32(tlv->value, presence);
|
|
975 } else {
|
|
976 /* Need to add the x00c9 TLV to the TLV chain */
|
|
977 aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00c9, presence);
|
|
978 }
|
|
979
|
|
980 /* Send the mod item SNAC */
|
|
981 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_MOD);
|
|
982 } else {
|
|
983 /* Need to add the item */
|
|
984 if (!(cur = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item))))
|
|
985 return -ENOMEM;
|
|
986 cur->name = NULL;
|
|
987 cur->gid = 0x0000;
|
|
988 cur->bid = 0x007a; /* XXX - Is this number significant? */
|
|
989 do {
|
|
990 cur->bid += 0x0001;
|
|
991 for (tmp=sess->ssi.items, j=0; ((tmp) && (!j)); tmp=tmp->next)
|
|
992 if (tmp->bid == cur->bid)
|
|
993 j=1;
|
|
994 } while (j);
|
|
995 cur->type = AIM_SSI_TYPE_PRESENCEPREFS;
|
|
996 cur->data = NULL;
|
|
997 aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00c9, presence);
|
|
998
|
|
999 /* Add the item to our list */
|
|
1000 cur->next = sess->ssi.items;
|
|
1001 sess->ssi.items = cur;
|
|
1002
|
|
1003 /* Send the add item SNAC */
|
|
1004 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD);
|
|
1005 }
|
|
1006
|
|
1007 /* Begin sending SSI SNACs */
|
|
1008 aim_ssi_dispatch(sess, conn);
|
|
1009
|
|
1010 return 0;
|
|
1011 }
|
|
1012
|
|
1013 /*
|
2672
|
1014 * Request SSI Rights.
|
|
1015 */
|
|
1016 faim_export int aim_ssi_reqrights(aim_session_t *sess, aim_conn_t *conn)
|
|
1017 {
|
3017
|
1018 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQRIGHTS);
|
2672
|
1019 }
|
|
1020
|
|
1021 /*
|
|
1022 * SSI Rights Information.
|
|
1023 */
|
|
1024 static int parserights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
1025 {
|
|
1026 int ret = 0;
|
|
1027 aim_rxcallback_t userfunc;
|
|
1028
|
|
1029 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
|
|
1030 ret = userfunc(sess, rx);
|
|
1031
|
|
1032 return ret;
|
|
1033 }
|
|
1034
|
|
1035 /*
|
|
1036 * Request SSI Data.
|
|
1037 *
|
|
1038 * The data will only be sent if it is newer than the posted local
|
|
1039 * timestamp and revision.
|
|
1040 *
|
|
1041 * Note that the client should never increment the revision, only the server.
|
|
1042 *
|
|
1043 */
|
|
1044 faim_export int aim_ssi_reqdata(aim_session_t *sess, aim_conn_t *conn, time_t localstamp, fu16_t localrev)
|
|
1045 {
|
|
1046 aim_frame_t *fr;
|
|
1047 aim_snacid_t snacid;
|
|
1048
|
|
1049 if (!sess || !conn)
|
|
1050 return -EINVAL;
|
|
1051
|
|
1052 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+4+2)))
|
|
1053 return -ENOMEM;
|
|
1054
|
3017
|
1055 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_REQLIST, 0x0000, NULL, 0);
|
2672
|
1056
|
3017
|
1057 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_REQLIST, 0x0000, snacid);
|
2672
|
1058 aimbs_put32(&fr->data, localstamp);
|
|
1059 aimbs_put16(&fr->data, localrev);
|
|
1060
|
|
1061 aim_tx_enqueue(sess, fr);
|
|
1062
|
|
1063 return 0;
|
|
1064 }
|
|
1065
|
|
1066 /*
|
|
1067 * SSI Data.
|
|
1068 */
|
|
1069 static int parsedata(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
1070 {
|
|
1071 int ret = 0;
|
|
1072 aim_rxcallback_t userfunc;
|
2991
|
1073 struct aim_ssi_item *cur = NULL;
|
2672
|
1074 fu8_t fmtver; /* guess */
|
2991
|
1075 fu16_t revision;
|
|
1076 fu32_t timestamp;
|
2672
|
1077
|
2991
|
1078 fmtver = aimbs_get8(bs); /* Version of ssi data. Should be 0x00 */
|
|
1079 revision = aimbs_get16(bs); /* # of times ssi data has been modified */
|
|
1080 if (revision != 0)
|
|
1081 sess->ssi.revision = revision;
|
|
1082
|
|
1083 for (cur = sess->ssi.items; cur && cur->next; cur=cur->next) ;
|
2672
|
1084
|
|
1085 while (aim_bstream_empty(bs) > 4) { /* last four bytes are stamp */
|
|
1086 fu16_t namelen, tbslen;
|
|
1087
|
2991
|
1088 if (!sess->ssi.items) {
|
|
1089 if (!(sess->ssi.items = malloc(sizeof(struct aim_ssi_item))))
|
|
1090 return -ENOMEM;
|
|
1091 cur = sess->ssi.items;
|
|
1092 } else {
|
|
1093 if (!(cur->next = malloc(sizeof(struct aim_ssi_item))))
|
|
1094 return -ENOMEM;
|
|
1095 cur = cur->next;
|
|
1096 }
|
|
1097 memset(cur, 0, sizeof(struct aim_ssi_item));
|
2672
|
1098
|
|
1099 if ((namelen = aimbs_get16(bs)))
|
2991
|
1100 cur->name = aimbs_getstr(bs, namelen);
|
|
1101 cur->gid = aimbs_get16(bs);
|
|
1102 cur->bid = aimbs_get16(bs);
|
|
1103 cur->type = aimbs_get16(bs);
|
2672
|
1104
|
|
1105 if ((tbslen = aimbs_get16(bs))) {
|
|
1106 aim_bstream_t tbs;
|
|
1107
|
|
1108 aim_bstream_init(&tbs, bs->data + bs->offset /* XXX */, tbslen);
|
2991
|
1109 cur->data = (void *)aim_readtlvchain(&tbs);
|
2672
|
1110 aim_bstream_advance(bs, tbslen);
|
|
1111 }
|
|
1112 }
|
|
1113
|
2991
|
1114 timestamp = aimbs_get32(bs);
|
|
1115 if (timestamp != 0)
|
|
1116 sess->ssi.timestamp = timestamp;
|
|
1117 sess->ssi.received_data = 1;
|
2672
|
1118
|
|
1119 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
|
2991
|
1120 ret = userfunc(sess, rx, fmtver, sess->ssi.revision, sess->ssi.timestamp, sess->ssi.items);
|
2672
|
1121
|
|
1122 return ret;
|
|
1123 }
|
|
1124
|
|
1125 /*
|
|
1126 * SSI Data Enable Presence.
|
|
1127 *
|
|
1128 * Should be sent after receiving 13/6 or 13/f to tell the server you
|
|
1129 * are ready to begin using the list. It will promptly give you the
|
|
1130 * presence information for everyone in your list and put your permit/deny
|
|
1131 * settings into effect.
|
|
1132 *
|
|
1133 */
|
|
1134 faim_export int aim_ssi_enable(aim_session_t *sess, aim_conn_t *conn)
|
|
1135 {
|
3017
|
1136 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, 0x0007);
|
2672
|
1137 }
|
|
1138
|
|
1139 /*
|
3017
|
1140 * SSI Add/Mod/Del Item(s).
|
2991
|
1141 *
|
3017
|
1142 * Sends the SNAC to add, modify, or delete an item from the server-stored
|
|
1143 * information. These 3 SNACs all have an identical structure. The only
|
|
1144 * difference is the subtype that is set for the SNAC.
|
2991
|
1145 *
|
|
1146 */
|
3017
|
1147 faim_export int aim_ssi_addmoddel(aim_session_t *sess, aim_conn_t *conn, struct aim_ssi_item **items, unsigned int num, fu16_t subtype)
|
2991
|
1148 {
|
|
1149 aim_frame_t *fr;
|
|
1150 aim_snacid_t snacid;
|
|
1151 int i, snaclen;
|
|
1152
|
|
1153 if (!sess || !conn || !items || !num)
|
|
1154 return -EINVAL;
|
|
1155
|
|
1156 snaclen = 10; /* For family, subtype, flags, and SNAC ID */
|
|
1157 for (i=0; i<num; i++) {
|
|
1158 snaclen += 10; /* For length, GID, BID, type, and length */
|
|
1159 if (items[i]->name)
|
|
1160 snaclen += strlen(items[i]->name);
|
|
1161 if (items[i]->data)
|
|
1162 snaclen += aim_sizetlvchain((aim_tlvlist_t **)&items[i]->data);
|
|
1163 }
|
|
1164
|
|
1165 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, snaclen)))
|
|
1166 return -ENOMEM;
|
|
1167
|
3017
|
1168 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, subtype, 0x0000, NULL, 0);
|
|
1169 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, subtype, 0x0000, snacid);
|
2991
|
1170
|
|
1171 for (i=0; i<num; i++) {
|
|
1172 aimbs_put16(&fr->data, items[i]->name ? strlen(items[i]->name) : 0);
|
|
1173 if (items[i]->name)
|
|
1174 aimbs_putraw(&fr->data, items[i]->name, strlen(items[i]->name));
|
|
1175 aimbs_put16(&fr->data, items[i]->gid);
|
|
1176 aimbs_put16(&fr->data, items[i]->bid);
|
|
1177 aimbs_put16(&fr->data, items[i]->type);
|
|
1178 aimbs_put16(&fr->data, items[i]->data ? aim_sizetlvchain((aim_tlvlist_t **)&items[i]->data) : 0);
|
|
1179 if (items[i]->data)
|
|
1180 aim_writetlvchain(&fr->data, (aim_tlvlist_t **)&items[i]->data);
|
|
1181 }
|
|
1182
|
|
1183 aim_ssi_enqueue(sess, conn, fr);
|
|
1184
|
|
1185 return 0;
|
|
1186 }
|
|
1187
|
|
1188 /*
|
|
1189 * SSI Add/Mod/Del Ack.
|
|
1190 *
|
3017
|
1191 * Response to add, modify, or delete SNAC (sent with aim_ssi_addmoddel).
|
2991
|
1192 *
|
|
1193 */
|
|
1194 static int parseack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
1195 {
|
|
1196 int ret = 0;
|
|
1197 aim_rxcallback_t userfunc;
|
|
1198
|
|
1199 sess->ssi.waiting_for_ack = 0;
|
|
1200 aim_ssi_dispatch(sess, rx->conn);
|
|
1201
|
|
1202 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
|
|
1203 ret = userfunc(sess, rx);
|
|
1204
|
|
1205 return ret;
|
|
1206 }
|
|
1207
|
|
1208 /*
|
2672
|
1209 * SSI Begin Data Modification.
|
|
1210 *
|
|
1211 * Tells the server you're going to start modifying data.
|
|
1212 *
|
|
1213 */
|
|
1214 faim_export int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn)
|
|
1215 {
|
3017
|
1216 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTART);
|
2672
|
1217 }
|
|
1218
|
|
1219 /*
|
|
1220 * SSI End Data Modification.
|
|
1221 *
|
|
1222 * Tells the server you're done modifying data.
|
|
1223 *
|
|
1224 */
|
|
1225 faim_export int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn)
|
|
1226 {
|
3017
|
1227 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTOP);
|
2672
|
1228 }
|
|
1229
|
|
1230 /*
|
|
1231 * SSI Data Unchanged.
|
|
1232 *
|
|
1233 * Response to aim_ssi_reqdata() if the server-side data is not newer than
|
|
1234 * posted local stamp/revision.
|
|
1235 *
|
|
1236 */
|
|
1237 static int parsedataunchanged(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
1238 {
|
|
1239 int ret = 0;
|
|
1240 aim_rxcallback_t userfunc;
|
|
1241
|
2991
|
1242 sess->ssi.received_data = 1;
|
|
1243
|
2672
|
1244 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
|
|
1245 ret = userfunc(sess, rx);
|
|
1246
|
|
1247 return ret;
|
|
1248 }
|
|
1249
|
|
1250 static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
|
|
1251 {
|
|
1252
|
3017
|
1253 if (snac->subtype == AIM_CB_SSI_RIGHTSINFO)
|
2672
|
1254 return parserights(sess, mod, rx, snac, bs);
|
3017
|
1255 else if (snac->subtype == AIM_CB_SSI_LIST)
|
2672
|
1256 return parsedata(sess, mod, rx, snac, bs);
|
2991
|
1257 else if (snac->subtype == AIM_CB_SSI_SRVACK)
|
|
1258 return parseack(sess, mod, rx, snac, bs);
|
3017
|
1259 else if (snac->subtype == AIM_CB_SSI_NOLIST)
|
2672
|
1260 return parsedataunchanged(sess, mod, rx, snac, bs);
|
|
1261
|
|
1262 return 0;
|
|
1263 }
|
|
1264
|
2991
|
1265 static void ssi_shutdown(aim_session_t *sess, aim_module_t *mod)
|
|
1266 {
|
|
1267 aim_ssi_freelist(sess);
|
|
1268
|
|
1269 return;
|
|
1270 }
|
|
1271
|
2672
|
1272 faim_internal int ssi_modfirst(aim_session_t *sess, aim_module_t *mod)
|
|
1273 {
|
|
1274
|
3017
|
1275 mod->family = AIM_CB_FAM_SSI;
|
2672
|
1276 mod->version = 0x0001;
|
|
1277 mod->toolid = 0x0110;
|
|
1278 mod->toolversion = 0x047b;
|
|
1279 mod->flags = 0;
|
|
1280 strncpy(mod->name, "ssi", sizeof(mod->name));
|
|
1281 mod->snachandler = snachandler;
|
2991
|
1282 mod->shutdown = ssi_shutdown;
|
2672
|
1283
|
|
1284 return 0;
|
|
1285 }
|