Mercurial > pidgin.yaz
comparison src/protocols/oscar/ssi.c @ 4230:9f729d6d88a6
[gaim-migrate @ 4475]
This is 128KB of raw kickassyness. AKA ICQ SSI.
I've rewritten all the important parts of ssi.c. Things should be better.
One thing I like a lot is that gaim will store the alias you assign to
buddies in your server list for both AIM and ICQ. WinICQ supports this,
but WinAIM doesn't. However, it doesn't seem to interfere with WinAIM,
and Gaim can still use it. I dunno, I just think it's neat.
Anyway, go nuts. Let me know if something doesn't work, because that's bad.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Tue, 07 Jan 2003 21:19:05 +0000 |
parents | 2532f1192da3 |
children | 64d834b6caf2 |
comparison
equal
deleted
inserted
replaced
4229:c1857c9c912d | 4230:9f729d6d88a6 |
---|---|
1 /* | 1 /* |
2 * Server-Side/Stored Information. | 2 * Family 0x0013 - Server-Side/Stored Information. |
3 * | 3 * |
4 * Relatively new facility that allows storing of certain types of information, | 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, | 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. | 6 * to be stored on the server, so that they can be accessed from any client. |
7 * | 7 * |
8 * We keep a copy of the ssi data in sess->ssi, because the data needs to be | 8 * We keep 2 copies of SSI data: |
9 * accessed for various reasons. So all the "aim_ssi_itemlist_bleh" functions | 9 * 1) An exact copy of what is stored on the AIM servers. |
10 * near the top just manage the local data. | 10 * 2) A local copy that we make changes to, and then send diffs |
11 * between this and the exact copy to keep them in sync. | |
12 * | |
13 * All the "aim_ssi_itemlist_bleh" functions near the top just modify the list | |
14 * that is given to them (eg. they don't send SNACs). | |
11 * | 15 * |
12 * The SNAC sending and receiving functions are lower down in the file, and | 16 * The SNAC sending and receiving functions are lower down in the file, and |
13 * they're simpler. They are in the order of the subtypes they deal with, | 17 * they're simpler. They are in the order of the subtypes they deal with, |
14 * starting with the request rights function (subtype 0x0002), then parse | 18 * starting with the request rights function (subtype 0x0002), then parse |
15 * rights (subtype 0x0003), then--well, you get the idea. | 19 * rights (subtype 0x0003), then--well, you get the idea. |
16 * | 20 * |
17 * This is entirely too complicated. | 21 * This is entirely too complicated. |
18 * You don't know the half of it. | 22 * You don't know the half of it. |
19 * | 23 * |
20 * XXX - Test for memory leaks | 24 * XXX - Preserve unknown data in TLV lists |
21 * XXX - Better parsing of rights, and use the rights info to limit adds | |
22 * | 25 * |
23 */ | 26 */ |
24 | 27 |
25 #define FAIM_INTERNAL | 28 #define FAIM_INTERNAL |
26 #include <aim.h> | 29 #include <aim.h> |
27 | 30 |
28 /** | 31 /** |
32 * Locally rebuild the 0x00c8 TLV in the additional data of the given group. | |
33 * | |
34 * @param list A pointer to a pointer to the current list of items. | |
35 * @param name A null terminated string containing the group name, or NULL | |
36 * if you want to modify the master group. | |
37 * @return Return a pointer to the modified item. | |
38 */ | |
39 static struct aim_ssi_item *aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item *list, const char *name) | |
40 { | |
41 int newlen; | |
42 struct aim_ssi_item *cur, *group; | |
43 | |
44 if (!list) | |
45 return NULL; | |
46 | |
47 /* Find the group */ | |
48 if (!(group = aim_ssi_itemlist_finditem(list, name, NULL, AIM_SSI_TYPE_GROUP))) | |
49 return NULL; | |
50 | |
51 /* Free the old data */ | |
52 aim_freetlvchain(&group->data); | |
53 group->data = NULL; | |
54 | |
55 /* Find the length for the new additional data */ | |
56 newlen = 0; | |
57 if (group->gid == 0x0000) { | |
58 for (cur=list; cur; cur=cur->next) | |
59 if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000)) | |
60 newlen += 2; | |
61 } else { | |
62 for (cur=list; cur; cur=cur->next) | |
63 if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) | |
64 newlen += 2; | |
65 } | |
66 | |
67 /* Build the new TLV list */ | |
68 if (newlen > 0) { | |
69 fu8_t *newdata; | |
70 | |
71 if (!(newdata = (fu8_t *)malloc((newlen)*sizeof(fu8_t)))) | |
72 return NULL; | |
73 newlen = 0; | |
74 if (group->gid == 0x0000) { | |
75 for (cur=list; cur; cur=cur->next) | |
76 if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid != 0x0000)) | |
77 newlen += aimutil_put16(newdata+newlen, cur->gid); | |
78 } else { | |
79 for (cur=list; cur; cur=cur->next) | |
80 if ((cur->gid == group->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) | |
81 newlen += aimutil_put16(newdata+newlen, cur->bid); | |
82 } | |
83 aim_addtlvtochain_raw(&group->data, 0x00c8, newlen, newdata); | |
84 | |
85 free(newdata); | |
86 } | |
87 | |
88 return group; | |
89 } | |
90 | |
91 /** | |
29 * Locally add a new item to the given item list. | 92 * Locally add a new item to the given item list. |
30 * | 93 * |
94 * XXX - This should copy data, not just use it. | |
95 * | |
31 * @param list A pointer to a pointer to the current list of items. | 96 * @param list A pointer to a pointer to the current list of items. |
32 * @param parent A pointer to the parent group, or NULL if the item should have no | |
33 * parent group (ie. the group ID# should be 0). | |
34 * @param name A null terminated string of the name of the new item, or NULL if the | 97 * @param name A null terminated string of the name of the new item, or NULL if the |
35 * item should have no name. | 98 * item should have no name. |
36 * @param type The type of the item, 0x0001 for a contact, 0x0002 for a group, etc. | 99 * @param gid The group ID# you want the new item to have, or 0xFFFF if we should pick something. |
37 * @return The newly created item. | 100 * @param bid The buddy ID# you want the new item to have, or 0xFFFF if we should pick something. |
38 */ | 101 * @param type The type of the item, 0x0000 for a contact, 0x0001 for a group, etc. |
39 static struct aim_ssi_item *aim_ssi_itemlist_add(struct aim_ssi_item **list, struct aim_ssi_item *parent, const char *name, fu16_t type) | 102 * @param data The additional data for the new item. |
103 * @return A pointer to the newly created item. | |
104 */ | |
105 static struct aim_ssi_item *aim_ssi_itemlist_add(struct aim_ssi_item **list, const char *name, fu16_t gid, fu16_t bid, fu16_t type, aim_tlvlist_t *data) | |
40 { | 106 { |
41 int i; | 107 int i; |
42 struct aim_ssi_item *cur, *newitem; | 108 struct aim_ssi_item *cur, *new; |
43 | 109 |
44 if (!(newitem = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) | 110 if (!list) |
111 return NULL; | |
112 | |
113 if (!(new = (struct aim_ssi_item *)malloc(sizeof(struct aim_ssi_item)))) | |
45 return NULL; | 114 return NULL; |
46 | 115 |
47 /* Set the name */ | 116 /* Set the name */ |
48 if (name) { | 117 if (name) { |
49 if (!(newitem->name = (char *)malloc((strlen(name)+1)*sizeof(char)))) { | 118 new->name = (char *)malloc((strlen(name)+1)*sizeof(char)); |
50 free(newitem); | 119 strcpy(new->name, name); |
51 return NULL; | |
52 } | |
53 strcpy(newitem->name, name); | |
54 } else | 120 } else |
55 newitem->name = NULL; | 121 new->name = NULL; |
56 | 122 |
57 /* Set the group ID# and the buddy ID# */ | 123 /* Set the group ID# and buddy ID# */ |
58 newitem->gid = 0x0000; | 124 new->gid = gid; |
59 newitem->bid = 0x0000; | 125 new->bid = bid; |
60 if (type == AIM_SSI_TYPE_GROUP) { | 126 if (type == AIM_SSI_TYPE_GROUP) { |
61 if (name) | 127 if ((new->gid == 0xFFFF) && name) { |
62 do { | 128 do { |
63 newitem->gid += 0x0001; | 129 new->gid += 0x0001; |
64 for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next) | 130 for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next) |
65 if ((cur->gid == newitem->gid) && (cur->gid == newitem->gid)) | 131 if ((cur->type == AIM_SSI_TYPE_GROUP) && (cur->gid == new->gid)) |
66 i=1; | 132 i=1; |
67 } while (i); | 133 } while (i); |
134 } | |
68 } else { | 135 } else { |
69 if (parent) | 136 if (new->bid == 0xFFFF) { |
70 newitem->gid = parent->gid; | 137 do { |
71 do { | 138 new->bid += 0x0001; |
72 newitem->bid += 0x0001; | 139 for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next) |
73 for (cur=*list, i=0; ((cur) && (!i)); cur=cur->next) | 140 if ((cur->bid == new->bid) && (cur->gid == new->gid)) |
74 if ((cur->bid == newitem->bid) && (cur->gid == newitem->gid)) | 141 i=1; |
75 i=1; | 142 } while (i); |
76 } while (i); | 143 } |
77 } | 144 } |
78 | 145 |
79 /* Set the rest */ | 146 /* Set the type */ |
80 newitem->type = type; | 147 new->type = type; |
81 newitem->data = NULL; | 148 |
82 newitem->next = *list; | 149 /* Set the TLV list */ |
83 *list = newitem; | 150 new->data = data; |
84 | 151 |
85 return newitem; | 152 /* Add the item to the list in the correct numerical position. Fancy, eh? */ |
86 } | 153 if (*list) { |
87 | 154 if ((new->gid < (*list)->gid) || ((new->gid == (*list)->gid) && (new->bid < (*list)->bid))) { |
88 /** | 155 new->next = *list; |
89 * Locally rebuild the 0x00c8 TLV in the additional data of the given group. | 156 *list = new; |
157 } else { | |
158 struct aim_ssi_item *prev; | |
159 for ((prev=*list, cur=(*list)->next); (cur && (new->gid > cur->gid || ((new->gid == cur->gid) && (new->bid > cur->bid)))); prev=cur, cur=cur->next); | |
160 new->next = prev->next; | |
161 prev->next = new; | |
162 } | |
163 } else { | |
164 new->next = *list; | |
165 *list = new; | |
166 } | |
167 | |
168 return new; | |
169 } | |
170 | |
171 /** | |
172 * Locally delete an item from the given item list. | |
90 * | 173 * |
91 * @param list A pointer to a pointer to the current list of items. | 174 * @param list A pointer to a pointer to the current list of items. |
92 * @param parentgroup A pointer to the group who's additional data you want to rebuild. | 175 * @param del A pointer to the item you want to remove from the list. |
93 * @return Return 0 if no errors, otherwise return the error number. | 176 * @return Return 0 if no errors, otherwise return the error number. |
94 */ | 177 */ |
95 static int aim_ssi_itemlist_rebuildgroup(struct aim_ssi_item **list, struct aim_ssi_item *parentgroup) | 178 static int aim_ssi_itemlist_del(struct aim_ssi_item **list, struct aim_ssi_item *del) |
96 { | 179 { |
97 int newlen; | 180 if (!list || !(*list) || !del) |
98 struct aim_ssi_item *cur; | 181 return -EINVAL; |
99 | 182 |
100 /* Free the old additional data */ | 183 /* Remove the item from the list */ |
101 if (parentgroup->data) { | 184 if (*list == del) { |
102 aim_freetlvchain((aim_tlvlist_t **)&parentgroup->data); | 185 *list = del->next; |
103 parentgroup->data = NULL; | |
104 } | |
105 | |
106 /* Find the length for the new additional data */ | |
107 newlen = 0; | |
108 if (parentgroup->gid == 0x0000) { | |
109 for (cur=*list; cur; cur=cur->next) | |
110 if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP)) | |
111 newlen += 2; | |
112 } else { | 186 } else { |
113 for (cur=*list; cur; cur=cur->next) | 187 struct aim_ssi_item *cur; |
114 if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) | 188 for (cur=*list; (cur->next && (cur->next!=del)); cur=cur->next); |
115 newlen += 2; | 189 if (cur->next) |
116 } | 190 cur->next = cur->next->next; |
117 | 191 } |
118 /* Rebuild the additional data */ | 192 |
119 if (newlen>0) { | 193 /* Free the deleted item */ |
120 fu8_t *newdata; | 194 free(del->name); |
121 | 195 aim_freetlvchain(&del->data); |
122 if (!(newdata = (fu8_t *)malloc((newlen)*sizeof(fu8_t)))) | 196 free(del); |
123 return -ENOMEM; | 197 |
124 newlen = 0; | 198 return 0; |
125 if (parentgroup->gid == 0x0000) { | 199 } |
126 for (cur=*list; cur; cur=cur->next) | 200 |
127 if ((cur->gid != 0x0000) && (cur->type == AIM_SSI_TYPE_GROUP)) | 201 /** |
128 newlen += aimutil_put16(newdata+newlen, cur->gid); | 202 * Compare two items to see if they have the same data. |
129 } else { | 203 * |
130 for (cur=*list; cur; cur=cur->next) | 204 * @param cur1 A pointer to a pointer to the first item. |
131 if ((cur->gid == parentgroup->gid) && (cur->type == AIM_SSI_TYPE_BUDDY)) | 205 * @param cur2 A pointer to a pointer to the second item. |
132 newlen += aimutil_put16(newdata+newlen, cur->bid); | 206 * @return Return 0 if no differences, or a number if there are differences. |
207 */ | |
208 static int aim_ssi_itemlist_cmp(struct aim_ssi_item *cur1, struct aim_ssi_item *cur2) | |
209 { | |
210 if (!cur1 || !cur2) | |
211 return 1; | |
212 | |
213 if (cur1->data && !cur2->data) | |
214 return 2; | |
215 | |
216 if (!cur1->data && cur2->data) | |
217 return 3; | |
218 | |
219 if (cur1->data && cur2->data) { | |
220 /* Write each TLV list to a bstream and then memcmp them */ | |
221 aim_bstream_t bs1, bs2; | |
222 | |
223 if (aim_sizetlvchain(&cur1->data) != aim_sizetlvchain(&cur2->data)) | |
224 return 4; | |
225 | |
226 aim_bstream_init(&bs1, ((fu8_t *)malloc(aim_sizetlvchain(&cur1->data)*sizeof(fu8_t))), aim_sizetlvchain(&cur1->data)); | |
227 aim_bstream_init(&bs2, ((fu8_t *)malloc(aim_sizetlvchain(&cur2->data)*sizeof(fu8_t))), aim_sizetlvchain(&cur2->data)); | |
228 | |
229 aim_writetlvchain(&bs1, &cur1->data); | |
230 aim_writetlvchain(&bs2, &cur2->data); | |
231 | |
232 if (memcmp(bs1.data, bs2.data, bs1.len)) { | |
233 free(bs1.data); | |
234 free(bs2.data); | |
235 return 4; | |
133 } | 236 } |
134 aim_addtlvtochain_raw((aim_tlvlist_t **)&(parentgroup->data), 0x00c8, newlen, newdata); | 237 |
135 | 238 free(bs1.data); |
136 free(newdata); | 239 free(bs2.data); |
137 } | 240 } |
138 | 241 |
139 return 0; | 242 if (cur1->name && !cur2->name) |
140 } | 243 return 5; |
141 | 244 |
142 /** | 245 if (!cur1->name && cur2->name) |
143 * Locally free all of the stored buddy list information. | 246 return 6; |
144 * | 247 |
145 * @param sess The oscar session. | 248 if (cur1->name && cur2->name && aim_sncmp(cur1->name, cur2->name)) |
146 * @return Return 0 if no errors, otherwise return the error number. | 249 return 7; |
147 */ | 250 |
148 static int aim_ssi_freelist(aim_session_t *sess) | 251 if (cur1->gid != cur2->gid) |
149 { | 252 return 8; |
150 struct aim_ssi_item *cur, *delitem; | 253 |
151 | 254 if (cur1->bid != cur2->bid) |
152 cur = sess->ssi.items; | 255 return 9; |
153 while (cur) { | 256 |
154 if (cur->name) free(cur->name); | 257 if (cur1->type != cur2->type) |
155 if (cur->data) aim_freetlvchain((aim_tlvlist_t **)&cur->data); | 258 return 10; |
156 delitem = cur; | |
157 cur = cur->next; | |
158 free(delitem); | |
159 } | |
160 | |
161 sess->ssi.items = NULL; | |
162 sess->ssi.revision = 0; | |
163 sess->ssi.timestamp = (time_t)0; | |
164 | 259 |
165 return 0; | 260 return 0; |
166 } | 261 } |
167 | 262 |
168 /** | 263 /** |
205 for (curg=list; curg; curg=curg->next) | 300 for (curg=list; curg; curg=curg->next) |
206 if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid) && (curg->name) && !(aim_sncmp(curg->name, gn))) | 301 if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid) && (curg->name) && !(aim_sncmp(curg->name, gn))) |
207 return cur; | 302 return cur; |
208 } | 303 } |
209 | 304 |
210 } else if (sn) { /* For finding groups, permits, denies, and ignores */ | 305 } else if (gn) { /* For finding groups */ |
211 for (cur=list; cur; cur=cur->next) | 306 for (cur=list; cur; cur=cur->next) { |
212 if ((cur->type == type) && (cur->name) && !(aim_sncmp(cur->name, sn))) | 307 if ((cur->type == type) && (cur->bid == 0x0000) && (cur->name) && !(aim_sncmp(cur->name, gn))) { |
213 return cur; | 308 return cur; |
309 } | |
310 } | |
311 | |
312 } else if (sn) { /* For finding permits, denies, and ignores */ | |
313 for (cur=list; cur; cur=cur->next) { | |
314 if ((cur->type == type) && (cur->gid == 0x0000) && (cur->name) && !(aim_sncmp(cur->name, sn))) { | |
315 return cur; | |
316 } | |
317 } | |
214 | 318 |
215 /* For stuff without names--permit deny setting, visibility mask, etc. */ | 319 /* For stuff without names--permit deny setting, visibility mask, etc. */ |
216 } else for (cur=list; cur; cur=cur->next) { | 320 } else for (cur=list; cur; cur=cur->next) { |
217 if (cur->type == type) | 321 if ((cur->type == type) && (!cur->name)) |
218 return cur; | 322 return cur; |
219 } | 323 } |
220 | 324 |
325 return NULL; | |
326 } | |
327 | |
328 /** | |
329 * Check if the given buddy exists in any group in the buddy list. | |
330 * | |
331 * @param list A pointer to the current list of items. | |
332 * @param sn The group name of the desired item. | |
333 * @return Return a pointer to the name of the item if found, else return NULL; | |
334 */ | |
335 faim_export struct aim_ssi_item *aim_ssi_itemlist_exists(struct aim_ssi_item *list, const char *sn) | |
336 { | |
337 struct aim_ssi_item *cur; | |
338 if (!list || !sn) | |
339 return NULL; | |
340 for (cur=list; cur; cur=cur->next) | |
341 if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->name) && (!aim_sncmp(cur->name, sn))) | |
342 return cur; | |
221 return NULL; | 343 return NULL; |
222 } | 344 } |
223 | 345 |
224 /** | 346 /** |
225 * Locally find the parent item of the given buddy name. | 347 * Locally find the parent item of the given buddy name. |
226 * | 348 * |
227 * @param list A pointer to the current list of items. | 349 * @param list A pointer to the current list of items. |
228 * @param bn The buddy name of the desired item. | 350 * @param bn The buddy name of the desired item. |
229 * @return Return a pointer to the item if found, else return NULL; | 351 * @return Return a pointer to the name of the item if found, else return NULL; |
230 */ | 352 */ |
231 faim_export struct aim_ssi_item *aim_ssi_itemlist_findparent(struct aim_ssi_item *list, char *sn) | 353 faim_export char *aim_ssi_itemlist_findparentname(struct aim_ssi_item *list, const char *sn) |
232 { | 354 { |
233 struct aim_ssi_item *cur, *curg; | 355 struct aim_ssi_item *cur, *curg; |
234 if (!list || !sn) | 356 if (!list || !sn) |
235 return NULL; | 357 return NULL; |
236 if (!(cur = aim_ssi_itemlist_finditem(list, NULL, sn, AIM_SSI_TYPE_BUDDY))) | 358 if (!(cur = aim_ssi_itemlist_exists(list, sn))) |
237 return NULL; | 359 return NULL; |
238 for (curg=list; curg; curg=curg->next) | 360 if (!(curg = aim_ssi_itemlist_find(list, cur->gid, 0x0000))) |
239 if ((curg->type == AIM_SSI_TYPE_GROUP) && (curg->gid == cur->gid)) | 361 return NULL; |
240 return curg; | 362 return curg->name; |
241 return NULL; | |
242 } | 363 } |
243 | 364 |
244 /** | 365 /** |
245 * Locally find the permit/deny setting item, and return the setting. | 366 * Locally find the permit/deny setting item, and return the setting. |
246 * | 367 * |
282 } | 403 } |
283 return 0xFFFFFFFF; | 404 return 0xFFFFFFFF; |
284 } | 405 } |
285 | 406 |
286 /** | 407 /** |
287 * Add the given packet to the holding queue. We totally need to send SSI SNACs one at | 408 * Locally find the alias of the given buddy. |
288 * a time, so we have a local queue where packets get put before they are sent, and | 409 * |
289 * then we send stuff one at a time, nice and orderly-like. | 410 * @param list A pointer to the current list of items. |
290 * | 411 * @return A pointer to a NULL terminated string that is the buddies |
291 * @param sess The oscar session. | 412 * alias, or NULL if the buddy has no alias. You should free |
292 * @param conn The bos connection for this session. | 413 * this returned value! |
293 * @param fr The newly created SNAC that you want to send. | 414 */ |
294 * @return Return 0 if no errors, otherwise return the error number. | 415 faim_export char *aim_ssi_getalias(struct aim_ssi_item *list, char *gn, char *sn) |
295 */ | 416 { |
296 static int aim_ssi_enqueue(aim_session_t *sess, aim_conn_t *conn, aim_frame_t *fr) | 417 struct aim_ssi_item *cur = aim_ssi_itemlist_finditem(list, gn, sn, AIM_SSI_TYPE_BUDDY); |
297 { | 418 if (cur) { |
298 aim_frame_t *cur; | 419 aim_tlvlist_t *tlvlist = cur->data; |
299 | 420 if (tlvlist) { |
300 if (!sess || !conn || !fr) | 421 aim_tlv_t *tlv = aim_gettlv(tlvlist, 0x0131, 1); |
301 return -EINVAL; | 422 if (tlv && tlv->length) { |
302 | 423 char *alias = (char *)(char *)malloc((tlv->length+1)*sizeof(char)); |
303 fr->next = NULL; | 424 strncpy(alias, tlv->value, tlv->length); |
304 if (sess->ssi.holding_queue == NULL) { | 425 alias[tlv->length] = 0; |
305 sess->ssi.holding_queue = fr; | 426 return alias; |
306 if (!sess->ssi.waiting_for_ack) | 427 } |
307 aim_ssi_modbegin(sess, conn); | 428 } |
308 } else { | 429 } |
309 for (cur = sess->ssi.holding_queue; cur->next; cur = cur->next) ; | 430 return NULL; |
310 cur->next = fr; | 431 } |
311 } | 432 |
312 | 433 /** |
313 return 0; | 434 * If there are changes, then create temporary items and |
314 } | 435 * call addmoddel. |
315 | |
316 /** | |
317 * Send the next SNAC from the holding queue. This is called | |
318 * automatically when an ack from an add, mod, or del is received. | |
319 * If the queue is empty, it sends the modend SNAC. | |
320 * | 436 * |
321 * @param sess The oscar session. | 437 * @param sess The oscar session. |
322 * @param conn The bos connection for this session. | 438 * @param conn The bos connection for this session. |
323 * @return Return 0 if no errors, otherwise return the error number. | 439 * @return Return 0 if no errors, otherwise return the error number. |
324 */ | 440 */ |
325 static int aim_ssi_dispatch(aim_session_t *sess, aim_conn_t *conn) | 441 static int aim_ssi_sync(aim_session_t *sess, aim_conn_t *conn) |
326 { | 442 { |
327 aim_frame_t *cur; | 443 struct aim_ssi_item *cur1, *cur2; |
444 struct aim_ssi_tmp *cur, *new; | |
328 | 445 |
329 if (!sess || !conn) | 446 if (!sess || !conn) |
330 return -EINVAL; | 447 return -EINVAL; |
331 | 448 |
332 if (!sess->ssi.waiting_for_ack) { | 449 /* If we're waiting for an ack, we shouldn't do anything else */ |
333 if (sess->ssi.holding_queue) { | 450 if (sess->ssi.waiting_for_ack) |
334 sess->ssi.waiting_for_ack = 1; | 451 return 0; |
335 cur = sess->ssi.holding_queue->next; | 452 |
336 sess->ssi.holding_queue->next = NULL; | 453 /* |
337 aim_tx_enqueue(sess, sess->ssi.holding_queue); | 454 * Compare the 2 lists and create an aim_ssi_tmp for each difference. |
338 sess->ssi.holding_queue = cur; | 455 * We should only send either additions, modifications, or deletions |
339 } else | 456 * before waiting for an acknowledgement. So first do deletions, then |
340 aim_ssi_modend(sess, conn); | 457 * additions, then modifications. Also, both the official and the local |
341 } | 458 * list should be in ascending numerical order for the group ID#s and the |
342 | 459 * buddy ID#s, which makes things more efficient. I think. |
343 return 0; | 460 */ |
344 } | 461 |
345 | 462 /* Deletions */ |
346 /** | 463 if (!sess->ssi.pending) { |
347 * Send SNACs necessary to remove all SSI data from the server list, | 464 for (cur1=sess->ssi.official; cur1; cur1=cur1->next) { |
348 * and then free the local copy as well. | 465 if (!aim_ssi_itemlist_find(sess->ssi.local, cur1->gid, cur1->bid)) { |
466 new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp)); | |
467 new->action = AIM_CB_SSI_DEL; | |
468 new->ack = 0xffff; | |
469 new->name = NULL; | |
470 new->item = cur1; | |
471 new->next = NULL; | |
472 if (sess->ssi.pending) { | |
473 for (cur=sess->ssi.pending; cur->next; cur=cur->next); | |
474 cur->next = new; | |
475 } else | |
476 sess->ssi.pending = new; | |
477 } | |
478 } | |
479 } | |
480 | |
481 /* Additions */ | |
482 if (!sess->ssi.pending) { | |
483 for (cur1=sess->ssi.local; cur1; cur1=cur1->next) { | |
484 if (!aim_ssi_itemlist_find(sess->ssi.official, cur1->gid, cur1->bid)) { | |
485 new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp)); | |
486 new->action = AIM_CB_SSI_ADD; | |
487 new->ack = 0xffff; | |
488 new->name = NULL; | |
489 new->item = cur1; | |
490 new->next = NULL; | |
491 if (sess->ssi.pending) { | |
492 for (cur=sess->ssi.pending; cur->next; cur=cur->next); | |
493 cur->next = new; | |
494 } else | |
495 sess->ssi.pending = new; | |
496 } | |
497 } | |
498 } | |
499 | |
500 /* Modifications */ | |
501 if (!sess->ssi.pending) { | |
502 for (cur1=sess->ssi.local; cur1; cur1=cur1->next) { | |
503 cur2 = aim_ssi_itemlist_find(sess->ssi.official, cur1->gid, cur1->bid); | |
504 if (cur2 && (aim_ssi_itemlist_cmp(cur1, cur2))) { | |
505 new = (struct aim_ssi_tmp *)malloc(sizeof(struct aim_ssi_tmp)); | |
506 new->action = AIM_CB_SSI_MOD; | |
507 new->ack = 0xffff; | |
508 new->name = NULL; | |
509 new->item = cur1; | |
510 new->next = NULL; | |
511 if (sess->ssi.pending) { | |
512 for (cur=sess->ssi.pending; cur->next; cur=cur->next); | |
513 cur->next = new; | |
514 } else | |
515 sess->ssi.pending = new; | |
516 } | |
517 } | |
518 } | |
519 | |
520 /* We're out of stuff to do, so tell the AIM servers we're done and exit */ | |
521 if (!sess->ssi.pending) { | |
522 aim_ssi_modend(sess, conn); | |
523 return 0; | |
524 } | |
525 | |
526 /* Make sure we don't send anything else between now | |
527 * and when we receive the ack for the following operation */ | |
528 sess->ssi.waiting_for_ack = 1; | |
529 | |
530 /* Now go mail off our data and wait 4 to 6 weeks */ | |
531 aim_ssi_addmoddel(sess, conn); | |
532 | |
533 return 0; | |
534 } | |
535 | |
536 /** | |
537 * Free all SSI data. | |
538 * | |
539 * This doesn't remove it from the server, that's different. | |
540 * | |
541 * @param sess The oscar session. | |
542 * @return Return 0 if no errors, otherwise return the error number. | |
543 */ | |
544 static int aim_ssi_freelist(aim_session_t *sess) | |
545 { | |
546 struct aim_ssi_item *cur, *del; | |
547 struct aim_ssi_tmp *curtmp, *deltmp; | |
548 | |
549 cur = sess->ssi.official; | |
550 while (cur) { | |
551 del = cur; | |
552 cur = cur->next; | |
553 free(del->name); | |
554 aim_freetlvchain(&del->data); | |
555 free(del); | |
556 } | |
557 | |
558 cur = sess->ssi.local; | |
559 while (cur) { | |
560 del = cur; | |
561 cur = cur->next; | |
562 free(del->name); | |
563 aim_freetlvchain(&del->data); | |
564 free(del); | |
565 } | |
566 | |
567 curtmp = sess->ssi.pending; | |
568 while (curtmp) { | |
569 deltmp = curtmp; | |
570 curtmp = curtmp->next; | |
571 free(deltmp); | |
572 } | |
573 | |
574 sess->ssi.numitems = 0; | |
575 sess->ssi.official = NULL; | |
576 sess->ssi.local = NULL; | |
577 sess->ssi.pending = NULL; | |
578 sess->ssi.timestamp = (time_t)0; | |
579 | |
580 return 0; | |
581 } | |
582 | |
583 /** | |
584 * Delete all SSI data. | |
349 * | 585 * |
350 * @param sess The oscar session. | 586 * @param sess The oscar session. |
351 * @param conn The bos connection for this session. | 587 * @param conn The bos connection for this session. |
352 * @return Return 0 if no errors, otherwise return the error number. | 588 * @return Return 0 if no errors, otherwise return the error number. |
353 */ | 589 */ |
354 faim_export int aim_ssi_deletelist(aim_session_t *sess, aim_conn_t *conn) | 590 faim_export int aim_ssi_deletelist(aim_session_t *sess, aim_conn_t *conn) |
355 { | 591 { |
356 int num; | 592 struct aim_ssi_item *cur, *del; |
357 struct aim_ssi_item *cur, **items; | 593 |
358 | 594 /* Free the local list */ |
359 for (cur=sess->ssi.items, num=0; cur; cur=cur->next) | 595 cur = sess->ssi.local; |
360 num++; | 596 while (cur) { |
361 | 597 del = cur; |
362 if (!(items = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)))) | 598 cur = cur->next; |
363 return -ENOMEM; | 599 free(del->name); |
364 memset(items, 0, num*sizeof(struct aim_ssi_item *)); | 600 aim_freetlvchain(&del->data); |
365 for (cur=sess->ssi.items, num=0; cur; cur=cur->next) { | 601 free(del); |
366 items[num] = cur; | 602 } |
367 num++; | 603 sess->ssi.local = NULL; |
368 } | 604 |
369 | 605 /* Sync our local list with the server list */ |
370 aim_ssi_addmoddel(sess, conn, items, num, AIM_CB_SSI_DEL); | 606 aim_ssi_sync(sess, conn); |
371 free(items); | 607 |
372 aim_ssi_dispatch(sess, conn); | 608 return 0; |
373 aim_ssi_freelist(sess); | 609 } |
374 | 610 |
375 return 0; | 611 /** |
376 } | 612 * This "cleans" the ssi list. It does the following: |
377 | 613 * 1) Makes sure that all buddies are in a group. |
378 /** | 614 * 2) Makes sure there are no empty groups |
379 * This "cleans" the ssi list. It does a few things, with the intent of making | |
380 * sure there ain't nothin' wrong with your SSI. | |
381 * -Make sure all buddies are in a group, and all groups have the correct | |
382 * additional data. | |
383 * -Make sure there are no empty groups in the list. While there is nothing | |
384 * wrong empty groups in the SSI, it's wiser to not have them. | |
385 * | 615 * |
386 * @param sess The oscar session. | 616 * @param sess The oscar session. |
387 * @param conn The bos connection for this session. | 617 * @param conn The bos connection for this session. |
388 * @return Return 0 if no errors, otherwise return the error number. | 618 * @return Return 0 if no errors, otherwise return the error number. |
389 */ | 619 */ |
390 faim_export int aim_ssi_cleanlist(aim_session_t *sess, aim_conn_t *conn) | 620 faim_export int aim_ssi_cleanlist(aim_session_t *sess, aim_conn_t *conn) |
391 { | 621 { |
392 unsigned int i; | 622 struct aim_ssi_item *cur; |
393 struct aim_ssi_item *cur, *parentgroup; | 623 |
394 | 624 /* If there are any buddies directly in the master group, put them in a real group */ |
395 /* Make sure we actually need to clean out the list */ | 625 /* This will kind of mess up if you hit the item limit, but this function isn't too critical */ |
396 for (cur=sess->ssi.items, i=0; cur && !i; cur=cur->next) | 626 for (cur=sess->ssi.local; cur; cur=cur->next) |
397 /* Any buddies directly in the master group */ | |
398 if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->gid == 0x0000)) | 627 if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->gid == 0x0000)) |
399 i++; | 628 aim_ssi_addbuddy(sess, conn, cur->name, "orphans", NULL, NULL, NULL, 0); |
400 if (!i) | 629 |
401 return 0; | 630 /* Now DESTROY any buddies that are directly in the master group */ |
402 | 631 for (cur=sess->ssi.local; cur; cur=cur->next) |
403 /* Remove all the additional data from all groups */ | 632 if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->gid == 0x0000)) |
404 for (cur=sess->ssi.items; cur; cur=cur->next) | 633 aim_ssi_delbuddy(sess, conn, cur->name, NULL); |
405 if ((cur->data) && (cur->type == AIM_SSI_TYPE_GROUP)) { | 634 |
406 aim_freetlvchain((aim_tlvlist_t **)&cur->data); | 635 /* Check if there are empty groups */ |
407 cur->data = NULL; | 636 for (cur=sess->ssi.local; cur; cur=cur->next) |
408 } | 637 if ((cur->type == AIM_SSI_TYPE_GROUP) && (!cur->data)) |
409 | 638 aim_ssi_itemlist_del(&sess->ssi.local, cur); |
410 /* If there are buddies directly in the master group, make sure */ | 639 |
411 /* there is a group to put them in. Any group, any group at all. */ | 640 /* Check if the master group is empty */ |
412 for (cur=sess->ssi.items; ((cur) && ((cur->type != AIM_SSI_TYPE_BUDDY) || (cur->gid != 0x0000))); cur=cur->next); | 641 if ((cur = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)) && (!cur->data)) |
413 if (!cur) { | 642 aim_ssi_itemlist_del(&sess->ssi.local, cur); |
414 for (parentgroup=sess->ssi.items; ((parentgroup) && (parentgroup->type!=AIM_SSI_TYPE_GROUP) && (parentgroup->gid==0x0000)); parentgroup=parentgroup->next); | 643 |
415 if (!parentgroup) { | 644 /* Sync our local list with the server list */ |
416 char *newgroup; | 645 aim_ssi_sync(sess, conn); |
417 newgroup = (char*)malloc(strlen("Unknown")*sizeof(char)); | 646 |
418 strcpy(newgroup, "Unknown"); | 647 return 0; |
419 aim_ssi_addgroups(sess, conn, (const char**)&newgroup, 1); | 648 } |
420 } | 649 |
421 } | 650 /** |
422 | 651 * Add a buddy to the list. |
423 /* Set parentgroup equal to any arbitray group */ | |
424 for (parentgroup=sess->ssi.items; parentgroup->gid==0x0000 || parentgroup->type!=AIM_SSI_TYPE_GROUP; parentgroup=parentgroup->next); | |
425 | |
426 /* If there are any buddies directly in the master group, put them in a real group */ | |
427 for (cur=sess->ssi.items; cur; cur=cur->next) | |
428 if ((cur->type == AIM_SSI_TYPE_BUDDY) && (cur->gid == 0x0000)) { | |
429 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_DEL); | |
430 cur->gid = parentgroup->gid; | |
431 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD); | |
432 } | |
433 | |
434 /* Rebuild additional data for all groups */ | |
435 for (parentgroup=sess->ssi.items; parentgroup; parentgroup=parentgroup->next) | |
436 if (parentgroup->type == AIM_SSI_TYPE_GROUP) | |
437 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup); | |
438 | |
439 /* Send a mod snac for all groups */ | |
440 i = 0; | |
441 for (cur=sess->ssi.items; cur; cur=cur->next) | |
442 if (cur->type == AIM_SSI_TYPE_GROUP) | |
443 i++; | |
444 if (i > 0) { | |
445 /* Allocate an array of pointers to each of the groups */ | |
446 struct aim_ssi_item **groups; | |
447 if (!(groups = (struct aim_ssi_item **)malloc(i*sizeof(struct aim_ssi_item *)))) | |
448 return -ENOMEM; | |
449 | |
450 for (cur=sess->ssi.items, i=0; cur; cur=cur->next) | |
451 if (cur->type == AIM_SSI_TYPE_GROUP) | |
452 groups[i] = cur; | |
453 | |
454 aim_ssi_addmoddel(sess, conn, groups, i, AIM_CB_SSI_MOD); | |
455 free(groups); | |
456 } | |
457 | |
458 /* Send a del snac for any empty groups */ | |
459 i = 0; | |
460 for (cur=sess->ssi.items; cur; cur=cur->next) | |
461 if ((cur->type == AIM_SSI_TYPE_GROUP) && !(cur->data)) | |
462 i++; | |
463 if (i > 0) { | |
464 /* Allocate an array of pointers to each of the groups */ | |
465 struct aim_ssi_item **groups; | |
466 if (!(groups = (struct aim_ssi_item **)malloc(i*sizeof(struct aim_ssi_item *)))) | |
467 return -ENOMEM; | |
468 | |
469 for (cur=sess->ssi.items, i=0; cur; cur=cur->next) | |
470 if ((cur->type == AIM_SSI_TYPE_GROUP) && !(cur->data)) | |
471 groups[i] = cur; | |
472 | |
473 aim_ssi_addmoddel(sess, conn, groups, i, AIM_CB_SSI_DEL); | |
474 free(groups); | |
475 } | |
476 | |
477 /* Begin sending SSI SNACs */ | |
478 aim_ssi_dispatch(sess, conn); | |
479 | |
480 return 0; | |
481 } | |
482 | |
483 /** | |
484 * Add an array of screen names to the given group. | |
485 * | 652 * |
486 * @param sess The oscar session. | 653 * @param sess The oscar session. |
487 * @param conn The bos connection for this session. | 654 * @param conn The bos connection for this session. |
488 * @param gn The name of the group to which you want to add these names. | 655 * @param name The name of the item. |
489 * @param sn An array of null terminated strings of the names you want to add. | 656 * @param group The group of the item. |
490 * @param num The number of screen names you are adding (size of the sn array). | 657 * @param alias The alias/nickname of the item, or NULL. |
658 * @param comment The buddy comment for the item, or NULL. | |
659 * @param smsnum The locally assigned SMS number, or NULL. | |
491 * @return Return 0 if no errors, otherwise return the error number. | 660 * @return Return 0 if no errors, otherwise return the error number. |
492 */ | 661 */ |
493 faim_export int aim_ssi_addbuddies(aim_session_t *sess, aim_conn_t *conn, const char *gn, const char **sn, unsigned int num) | 662 faim_export int aim_ssi_addbuddy(aim_session_t *sess, aim_conn_t *conn, const char *name, const char *group, const char *alias, const char *comment, const char *smsnum, int needauth) |
494 { | 663 { |
495 struct aim_ssi_item *parentgroup, **newitems; | 664 struct aim_ssi_item *parent; |
496 fu16_t i; | 665 aim_tlvlist_t *data = NULL; |
497 | 666 |
498 if (!sess || !conn || !gn || !sn || !num) | 667 if (!sess || !conn || !name || !group) |
499 return -EINVAL; | 668 return -EINVAL; |
500 | 669 |
501 /* Look up the parent group */ | 670 /* Find the parent */ |
502 if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP))) { | 671 if (!(parent = aim_ssi_itemlist_finditem(sess->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP))) { |
503 aim_ssi_addgroups(sess, conn, (const char **)&gn, 1); | 672 /* Find the parent's parent (the master group) */ |
504 if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP))) | 673 if (!(parent = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000))) |
674 if (!(parent = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL))) | |
675 return -ENOMEM; | |
676 /* Add the parent */ | |
677 if (!(parent = aim_ssi_itemlist_add(&sess->ssi.local, group, 0xFFFF, 0x0000, AIM_SSI_TYPE_GROUP, NULL))) | |
505 return -ENOMEM; | 678 return -ENOMEM; |
506 } | 679 |
507 | 680 /* Modify the parent's parent (the master group) */ |
508 /* Allocate an array of pointers to each of the new items */ | 681 aim_ssi_itemlist_rebuildgroup(sess->ssi.local, NULL); |
509 if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)))) | 682 } |
510 return -ENOMEM; | 683 |
511 | 684 /* Create a TLV list for the new buddy */ |
512 /* Add items to the local list, and index them in the array */ | 685 if (needauth) |
513 for (i=0; i<num; i++) | 686 aim_addtlvtochain_noval(&data, 0x0066); |
514 if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, parentgroup, sn[i], AIM_SSI_TYPE_BUDDY))) { | 687 if (alias) |
515 free(newitems); | 688 aim_addtlvtochain_raw(&data, 0x0131, strlen(alias), alias); |
516 return -ENOMEM; | 689 if (smsnum) |
517 } | 690 aim_addtlvtochain_raw(&data, 0x013a, strlen(smsnum), smsnum); |
518 | 691 if (comment) |
519 /* Send the add item SNAC */ | 692 aim_addtlvtochain_raw(&data, 0x013c, strlen(comment), comment); |
520 if ((i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD))) { | 693 |
521 free(newitems); | 694 /* Add that bad boy */ |
522 return -i; | 695 aim_ssi_itemlist_add(&sess->ssi.local, name, parent->gid, 0xFFFF, AIM_SSI_TYPE_BUDDY, data); |
523 } | 696 |
524 | 697 /* Modify the parent group */ |
525 /* Free the array of pointers to each of the new items */ | 698 aim_ssi_itemlist_rebuildgroup(sess->ssi.local, group); |
526 free(newitems); | 699 |
527 | 700 /* Sync our local list with the server list */ |
528 /* Rebuild the additional data in the parent group */ | 701 aim_ssi_sync(sess, conn); |
529 if ((i = aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup))) | 702 |
530 return i; | 703 return 0; |
531 | 704 } |
532 /* Send the mod item SNAC */ | 705 |
533 if ((i = aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD))) | 706 /** |
534 return i; | 707 * Add a permit buddy to the list. |
535 | |
536 /* Begin sending SSI SNACs */ | |
537 if (!(i = aim_ssi_dispatch(sess, conn))) | |
538 return i; | |
539 | |
540 return 0; | |
541 } | |
542 | |
543 /** | |
544 * Add the master group (the group containing all groups). This is called by | |
545 * aim_ssi_addgroups, if necessary. | |
546 * | 708 * |
547 * @param sess The oscar session. | 709 * @param sess The oscar session. |
548 * @param conn The bos connection for this session. | 710 * @param conn The bos connection for this session. |
711 * @param name The name of the item.. | |
549 * @return Return 0 if no errors, otherwise return the error number. | 712 * @return Return 0 if no errors, otherwise return the error number. |
550 */ | 713 */ |
551 faim_export int aim_ssi_addmastergroup(aim_session_t *sess, aim_conn_t *conn) | 714 faim_export int aim_ssi_addpermit(aim_session_t *sess, aim_conn_t *conn, const char *name) |
552 { | 715 { |
553 struct aim_ssi_item *newitem; | 716 if (!sess || !conn || !name) |
554 | 717 return -EINVAL; |
555 if (!sess || !conn) | 718 |
556 return -EINVAL; | 719 /* Add that bad boy */ |
557 | 720 aim_ssi_itemlist_add(&sess->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_PERMIT, NULL); |
558 /* Add the item to the local list, and keep a pointer to it */ | 721 |
559 if (!(newitem = aim_ssi_itemlist_add(&sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_GROUP))) | 722 /* Sync our local list with the server list */ |
560 return -ENOMEM; | 723 aim_ssi_sync(sess, conn); |
561 | 724 |
562 /* If there are any existing groups (technically there shouldn't be, but */ | 725 return 0; |
563 /* just in case) then add their group ID#'s to the additional data */ | 726 } |
564 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, newitem); | 727 |
565 | 728 /** |
566 /* Send the add item SNAC */ | 729 * Add a deny buddy to the list. |
567 aim_ssi_addmoddel(sess, conn, &newitem, 1, AIM_CB_SSI_ADD); | |
568 | |
569 /* Begin sending SSI SNACs */ | |
570 aim_ssi_dispatch(sess, conn); | |
571 | |
572 return 0; | |
573 } | |
574 | |
575 /** | |
576 * Add an array of groups to the list. | |
577 * | 730 * |
578 * @param sess The oscar session. | 731 * @param sess The oscar session. |
579 * @param conn The bos connection for this session. | 732 * @param conn The bos connection for this session. |
580 * @param gn An array of null terminated strings of the names you want to add. | 733 * @param name The name of the item.. |
581 * @param num The number of groups names you are adding (size of the sn array). | |
582 * @return Return 0 if no errors, otherwise return the error number. | 734 * @return Return 0 if no errors, otherwise return the error number. |
583 */ | 735 */ |
584 faim_export int aim_ssi_addgroups(aim_session_t *sess, aim_conn_t *conn, const char **gn, unsigned int num) | 736 faim_export int aim_ssi_adddeny(aim_session_t *sess, aim_conn_t *conn, const char *name) |
585 { | 737 { |
586 struct aim_ssi_item *parentgroup, **newitems; | 738 if (!sess || !conn || !name) |
587 fu16_t i; | 739 return -EINVAL; |
588 | 740 |
589 if (!sess || !conn || !gn || !num) | 741 /* Add that bad boy */ |
590 return -EINVAL; | 742 aim_ssi_itemlist_add(&sess->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_DENY, NULL); |
591 | 743 |
592 /* Look up the parent group */ | 744 /* Sync our local list with the server list */ |
593 if (!(parentgroup = aim_ssi_itemlist_find(sess->ssi.items, 0, 0))) { | 745 aim_ssi_sync(sess, conn); |
594 aim_ssi_addmastergroup(sess, conn); | 746 |
595 if (!(parentgroup = aim_ssi_itemlist_find(sess->ssi.items, 0, 0))) | 747 return 0; |
596 return -ENOMEM; | 748 } |
597 } | 749 |
598 | 750 /** |
599 /* Allocate an array of pointers to each of the new items */ | 751 * Deletes a buddy from the list. |
600 if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)))) | |
601 return -ENOMEM; | |
602 | |
603 /* Add items to the local list, and index them in the array */ | |
604 for (i=0; i<num; i++) | |
605 if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, parentgroup, gn[i], AIM_SSI_TYPE_GROUP))) { | |
606 free(newitems); | |
607 return -ENOMEM; | |
608 } | |
609 | |
610 /* Send the add item SNAC */ | |
611 if ((i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD))) { | |
612 free(newitems); | |
613 return -i; | |
614 } | |
615 | |
616 /* Free the array of pointers to each of the new items */ | |
617 free(newitems); | |
618 | |
619 /* Rebuild the additional data in the parent group */ | |
620 if ((i = aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup))) | |
621 return i; | |
622 | |
623 /* Send the mod item SNAC */ | |
624 if ((i = aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD))) | |
625 return i; | |
626 | |
627 /* Begin sending SSI SNACs */ | |
628 if (!(i = aim_ssi_dispatch(sess, conn))) | |
629 return i; | |
630 | |
631 return 0; | |
632 } | |
633 | |
634 /** | |
635 * Add an array of a certain type of item to the list. This can be used for | |
636 * permit buddies, deny buddies, ICQ's ignore buddies, and probably other | |
637 * types, also. | |
638 * | 752 * |
639 * @param sess The oscar session. | 753 * @param sess The oscar session. |
640 * @param conn The bos connection for this session. | 754 * @param conn The bos connection for this session. |
641 * @param sn An array of null terminated strings of the names you want to add. | 755 * @param name The name of the item, or NULL. |
642 * @param num The number of groups names you are adding (size of the sn array). | 756 * @param group The group of the item, or NULL. |
643 * @param type The type of item you want to add. See the AIM_SSI_TYPE_BLEH | |
644 * #defines in aim.h. | |
645 * @return Return 0 if no errors, otherwise return the error number. | 757 * @return Return 0 if no errors, otherwise return the error number. |
646 */ | 758 */ |
647 faim_export int aim_ssi_addpord(aim_session_t *sess, aim_conn_t *conn, const char **sn, unsigned int num, fu16_t type) | 759 faim_export int aim_ssi_delbuddy(aim_session_t *sess, aim_conn_t *conn, const char *name, const char *group) |
648 { | 760 { |
649 struct aim_ssi_item **newitems; | 761 struct aim_ssi_item *del; |
650 fu16_t i; | 762 |
651 | 763 if (!sess || !conn || !name || !group) |
652 if (!sess || !conn || !sn || !num) | 764 return -EINVAL; |
653 return -EINVAL; | 765 |
654 | 766 /* Find the buddy */ |
655 /* Allocate an array of pointers to each of the new items */ | 767 if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, group, name, AIM_SSI_TYPE_BUDDY))) |
656 if (!(newitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)))) | 768 return -EINVAL; |
657 return -ENOMEM; | 769 |
658 | 770 /* Remove the item from the list */ |
659 /* Add items to the local list, and index them in the array */ | 771 aim_ssi_itemlist_del(&sess->ssi.local, del); |
660 for (i=0; i<num; i++) | 772 |
661 if (!(newitems[i] = aim_ssi_itemlist_add(&sess->ssi.items, NULL, sn[i], type))) { | 773 /* Modify the parent group */ |
662 free(newitems); | 774 aim_ssi_itemlist_rebuildgroup(sess->ssi.local, group); |
663 return -ENOMEM; | 775 |
776 /* Check if we should delete the parent group */ | |
777 if ((del = aim_ssi_itemlist_finditem(sess->ssi.local, group, NULL, AIM_SSI_TYPE_GROUP)) && (!del->data)) { | |
778 aim_ssi_itemlist_del(&sess->ssi.local, del); | |
779 | |
780 /* Modify the parent group */ | |
781 aim_ssi_itemlist_rebuildgroup(sess->ssi.local, NULL); | |
782 | |
783 /* Check if we should delete the parent's parent (the master group) */ | |
784 if ((del = aim_ssi_itemlist_find(sess->ssi.local, 0x0000, 0x0000)) && (!del->data)) { | |
785 aim_ssi_itemlist_del(&sess->ssi.local, del); | |
664 } | 786 } |
665 | 787 } |
666 /* Send the add item SNAC */ | 788 |
667 if ((i = aim_ssi_addmoddel(sess, conn, newitems, num, AIM_CB_SSI_ADD))) { | 789 /* Sync our local list with the server list */ |
668 free(newitems); | 790 aim_ssi_sync(sess, conn); |
669 return -i; | 791 |
670 } | 792 return 0; |
671 | 793 } |
672 /* Free the array of pointers to each of the new items */ | 794 |
673 free(newitems); | 795 /** |
674 | 796 * Deletes a permit buddy from the list. |
675 /* Begin sending SSI SNACs */ | 797 * |
676 if (!(i = aim_ssi_dispatch(sess, conn))) | 798 * @param sess The oscar session. |
677 return i; | 799 * @param conn The bos connection for this session. |
800 * @param name The name of the item, or NULL. | |
801 * @return Return 0 if no errors, otherwise return the error number. | |
802 */ | |
803 faim_export int aim_ssi_delpermit(aim_session_t *sess, aim_conn_t *conn, const char *name) | |
804 { | |
805 struct aim_ssi_item *del; | |
806 | |
807 if (!sess || !conn || !name) | |
808 return -EINVAL; | |
809 | |
810 /* Find the item */ | |
811 if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, name, AIM_SSI_TYPE_PERMIT))) | |
812 return -EINVAL; | |
813 | |
814 /* Remove the item from the list */ | |
815 aim_ssi_itemlist_del(&sess->ssi.local, del); | |
816 | |
817 /* Sync our local list with the server list */ | |
818 aim_ssi_sync(sess, conn); | |
819 | |
820 return 0; | |
821 } | |
822 | |
823 /** | |
824 * Deletes a deny buddy from the list. | |
825 * | |
826 * @param sess The oscar session. | |
827 * @param conn The bos connection for this session. | |
828 * @param name The name of the item, or NULL. | |
829 * @return Return 0 if no errors, otherwise return the error number. | |
830 */ | |
831 faim_export int aim_ssi_deldeny(aim_session_t *sess, aim_conn_t *conn, const char *name) | |
832 { | |
833 struct aim_ssi_item *del; | |
834 | |
835 if (!sess || !conn || !name) | |
836 return -EINVAL; | |
837 | |
838 /* Find the item */ | |
839 if (!(del = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, name, AIM_SSI_TYPE_PERMIT))) | |
840 return -EINVAL; | |
841 | |
842 /* Remove the item from the list */ | |
843 aim_ssi_itemlist_del(&sess->ssi.local, del); | |
844 | |
845 /* Sync our local list with the server list */ | |
846 aim_ssi_sync(sess, conn); | |
678 | 847 |
679 return 0; | 848 return 0; |
680 } | 849 } |
681 | 850 |
682 /** | 851 /** |
690 * @param sn The name of the buddy to be moved. | 859 * @param sn The name of the buddy to be moved. |
691 * @return Return 0 if no errors, otherwise return the error number. | 860 * @return Return 0 if no errors, otherwise return the error number. |
692 */ | 861 */ |
693 faim_export int aim_ssi_movebuddy(aim_session_t *sess, aim_conn_t *conn, const char *oldgn, const char *newgn, const char *sn) | 862 faim_export int aim_ssi_movebuddy(aim_session_t *sess, aim_conn_t *conn, const char *oldgn, const char *newgn, const char *sn) |
694 { | 863 { |
695 struct aim_ssi_item **groups, *buddy, *cur; | 864 aim_ssi_delbuddy(sess, conn, sn, oldgn); |
696 fu16_t i; | 865 aim_ssi_addbuddy(sess, conn, sn, newgn, NULL, NULL, NULL, 0); |
697 | 866 return 0; |
698 if (!sess || !conn || !oldgn || !newgn || !sn) | 867 } |
699 return -EINVAL; | 868 |
700 | 869 /** |
701 /* Look up the buddy */ | 870 * Rename a group. |
702 if (!(buddy = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn, AIM_SSI_TYPE_BUDDY))) | |
703 return -ENOMEM; | |
704 | |
705 /* Allocate an array of pointers to the two groups */ | |
706 if (!(groups = (struct aim_ssi_item **)malloc(2*sizeof(struct aim_ssi_item *)))) | |
707 return -ENOMEM; | |
708 | |
709 /* Look up the old parent group */ | |
710 if (!(groups[0] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, oldgn, AIM_SSI_TYPE_GROUP))) { | |
711 free(groups); | |
712 return -ENOMEM; | |
713 } | |
714 | |
715 /* Look up the new parent group */ | |
716 if (!(groups[1] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, newgn, AIM_SSI_TYPE_GROUP))) { | |
717 aim_ssi_addgroups(sess, conn, (const char**)&newgn, 1); | |
718 if (!(groups[1] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, newgn, AIM_SSI_TYPE_GROUP))) { | |
719 free(groups); | |
720 return -ENOMEM; | |
721 } | |
722 } | |
723 | |
724 /* Send the delete item SNAC */ | |
725 aim_ssi_addmoddel(sess, conn, &buddy, 1, AIM_CB_SSI_DEL); | |
726 | |
727 /* Put the buddy in the new group */ | |
728 buddy->gid = groups[1]->gid; | |
729 | |
730 /* Assign a new buddy ID#, because the new group might already have a buddy with this ID# */ | |
731 buddy->bid = 0; | |
732 do { | |
733 buddy->bid += 0x0001; | |
734 for (cur=sess->ssi.items, i=0; ((cur) && (!i)); cur=cur->next) | |
735 if ((cur->bid == buddy->bid) && (cur->gid == buddy->gid) && (cur->type == AIM_SSI_TYPE_BUDDY) && (cur->name) && aim_sncmp(cur->name, buddy->name)) | |
736 i=1; | |
737 } while (i); | |
738 | |
739 /* Rebuild the additional data in the two parent groups */ | |
740 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, groups[0]); | |
741 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, groups[1]); | |
742 | |
743 /* Send the add item SNAC */ | |
744 aim_ssi_addmoddel(sess, conn, &buddy, 1, AIM_CB_SSI_ADD); | |
745 | |
746 /* Send the mod item SNAC */ | |
747 aim_ssi_addmoddel(sess, conn, groups, 2, AIM_CB_SSI_MOD); | |
748 | |
749 /* Free the temporary array */ | |
750 free(groups); | |
751 | |
752 /* Begin sending SSI SNACs */ | |
753 aim_ssi_dispatch(sess, conn); | |
754 | |
755 return 0; | |
756 } | |
757 | |
758 /** | |
759 * Rename a group. I really like how this is done. It turns me on. | |
760 * | |
761 * Did I say that out loud?... | |
762 * | 871 * |
763 * @param sess The oscar session. | 872 * @param sess The oscar session. |
764 * @param conn The bos connection for this session. | 873 * @param conn The bos connection for this session. |
765 * @param oldgn The old group name. | 874 * @param oldgn The old group name. |
766 * @param newgn The new group name. | 875 * @param newgn The new group name. |
771 struct aim_ssi_item *group; | 880 struct aim_ssi_item *group; |
772 | 881 |
773 if (!sess || !conn || !oldgn || !newgn) | 882 if (!sess || !conn || !oldgn || !newgn) |
774 return -EINVAL; | 883 return -EINVAL; |
775 | 884 |
776 /* Look up the group */ | 885 if (!(group = aim_ssi_itemlist_finditem(sess->ssi.local, oldgn, NULL, AIM_SSI_TYPE_GROUP))) |
777 if (!(group = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, oldgn, AIM_SSI_TYPE_GROUP))) | 886 return -EINVAL; |
778 return -ENOMEM; | 887 |
779 | 888 free(group->name); |
780 /* Free the old group name and copy the new one in its place. */ | 889 group->name = (char *)malloc((strlen(newgn)+1)*sizeof(char)); |
781 if (group->name) | |
782 free(group->name); | |
783 if (!(group->name = (char *)malloc((strlen(newgn)+1)*sizeof(char)))) { | |
784 group->name = NULL; | |
785 return -ENOMEM; | |
786 } | |
787 strcpy(group->name, newgn); | 890 strcpy(group->name, newgn); |
788 | 891 |
789 /* Send the mod item SNAC */ | 892 /* Sync our local list with the server list */ |
790 aim_ssi_addmoddel(sess, conn, &group, 1, AIM_CB_SSI_MOD); | 893 aim_ssi_sync(sess, conn); |
791 | |
792 /* Begin sending SSI SNACs */ | |
793 aim_ssi_dispatch(sess, conn); | |
794 | |
795 return 0; | |
796 } | |
797 | |
798 /** | |
799 * Delete an array of screen names from the given group. | |
800 * | |
801 * @param sess The oscar session. | |
802 * @param conn The bos connection for this session. | |
803 * @param gn The name of the group from which you want to delete these names. | |
804 * @param sn An array of null terminated strings of the names you want to delete. | |
805 * @param num The number of screen names you are deleting (size of the sn array). | |
806 * @return Return 0 if no errors, otherwise return the error number. | |
807 */ | |
808 faim_export int aim_ssi_delbuddies(aim_session_t *sess, aim_conn_t *conn, const char *gn, char **sn, unsigned int num) | |
809 { | |
810 struct aim_ssi_item *cur, *parentgroup, **delitems; | |
811 int i; | |
812 | |
813 if (!sess || !conn || !gn || !sn || !num) | |
814 return -EINVAL; | |
815 | |
816 /* Look up the parent group */ | |
817 if (!(parentgroup = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn, AIM_SSI_TYPE_GROUP))) | |
818 return -EINVAL; | |
819 | |
820 /* Allocate an array of pointers to each of the items to be deleted */ | |
821 delitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)); | |
822 memset(delitems, 0, num*sizeof(struct aim_ssi_item *)); | |
823 | |
824 /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */ | |
825 for (i=0; i<num; i++) { | |
826 if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn[i], AIM_SSI_TYPE_BUDDY))) { | |
827 free(delitems); | |
828 return -EINVAL; | |
829 } | |
830 | |
831 /* Remove the delitems from the item list */ | |
832 if (sess->ssi.items == delitems[i]) { | |
833 sess->ssi.items = sess->ssi.items->next; | |
834 } else { | |
835 for (cur=sess->ssi.items; (cur->next && (cur->next!=delitems[i])); cur=cur->next); | |
836 if (cur->next) | |
837 cur->next = cur->next->next; | |
838 } | |
839 } | |
840 | |
841 /* Send the del item SNAC */ | |
842 aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL); | |
843 | |
844 /* Free the items */ | |
845 for (i=0; i<num; i++) { | |
846 if (delitems[i]->name) | |
847 free(delitems[i]->name); | |
848 if (delitems[i]->data) | |
849 aim_freetlvchain((aim_tlvlist_t **)&delitems[i]->data); | |
850 free(delitems[i]); | |
851 } | |
852 free(delitems); | |
853 | |
854 /* Rebuild the additional data in the parent group */ | |
855 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup); | |
856 | |
857 /* Send the mod item SNAC */ | |
858 aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD); | |
859 | |
860 /* Delete the group, but only if it's empty */ | |
861 if (!parentgroup->data) | |
862 aim_ssi_delgroups(sess, conn, &parentgroup->name, 1); | |
863 | |
864 /* Begin sending SSI SNACs */ | |
865 aim_ssi_dispatch(sess, conn); | |
866 | |
867 return 0; | |
868 } | |
869 | |
870 /** | |
871 * Delete the master group from the item list. There can be only one. | |
872 * Er, so just find the one master group and delete it. | |
873 * | |
874 * @param sess The oscar session. | |
875 * @param conn The bos connection for this session. | |
876 * @return Return 0 if no errors, otherwise return the error number. | |
877 */ | |
878 faim_export int aim_ssi_delmastergroup(aim_session_t *sess, aim_conn_t *conn) | |
879 { | |
880 struct aim_ssi_item *cur, *delitem; | |
881 | |
882 if (!sess || !conn) | |
883 return -EINVAL; | |
884 | |
885 /* Make delitem a pointer to the aim_ssi_item to be deleted */ | |
886 if (!(delitem = aim_ssi_itemlist_find(sess->ssi.items, 0, 0))) | |
887 return -EINVAL; | |
888 | |
889 /* Remove delitem from the item list */ | |
890 if (sess->ssi.items == delitem) { | |
891 sess->ssi.items = sess->ssi.items->next; | |
892 } else { | |
893 for (cur=sess->ssi.items; (cur->next && (cur->next!=delitem)); cur=cur->next); | |
894 if (cur->next) | |
895 cur->next = cur->next->next; | |
896 } | |
897 | |
898 /* Send the del item SNAC */ | |
899 aim_ssi_addmoddel(sess, conn, &delitem, 1, AIM_CB_SSI_DEL); | |
900 | |
901 /* Free the item */ | |
902 if (delitem->name) | |
903 free(delitem->name); | |
904 if (delitem->data) | |
905 aim_freetlvchain((aim_tlvlist_t **)&delitem->data); | |
906 free(delitem); | |
907 | |
908 /* Begin sending SSI SNACs */ | |
909 aim_ssi_dispatch(sess, conn); | |
910 | |
911 return 0; | |
912 } | |
913 | |
914 /** | |
915 * Delete an array of groups. | |
916 * | |
917 * @param sess The oscar session. | |
918 * @param conn The bos connection for this session. | |
919 * @param gn An array of null terminated strings of the groups you want to delete. | |
920 * @param num The number of groups you are deleting (size of the gn array). | |
921 * @return Return 0 if no errors, otherwise return the error number. | |
922 */ | |
923 faim_export int aim_ssi_delgroups(aim_session_t *sess, aim_conn_t *conn, char **gn, unsigned int num) { | |
924 struct aim_ssi_item *cur, *parentgroup, **delitems; | |
925 int i; | |
926 | |
927 if (!sess || !conn || !gn || !num) | |
928 return -EINVAL; | |
929 | |
930 /* Look up the parent group */ | |
931 if (!(parentgroup = aim_ssi_itemlist_find(sess->ssi.items, 0, 0))) | |
932 return -EINVAL; | |
933 | |
934 /* Allocate an array of pointers to each of the items to be deleted */ | |
935 delitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)); | |
936 memset(delitems, 0, num*sizeof(struct aim_ssi_item *)); | |
937 | |
938 /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */ | |
939 for (i=0; i<num; i++) { | |
940 if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, gn[i], AIM_SSI_TYPE_GROUP))) { | |
941 free(delitems); | |
942 return -EINVAL; | |
943 } | |
944 | |
945 /* Remove the delitems from the item list */ | |
946 if (sess->ssi.items == delitems[i]) { | |
947 sess->ssi.items = sess->ssi.items->next; | |
948 } else { | |
949 for (cur=sess->ssi.items; (cur->next && (cur->next!=delitems[i])); cur=cur->next); | |
950 if (cur->next) | |
951 cur->next = cur->next->next; | |
952 } | |
953 } | |
954 | |
955 /* Send the del item SNAC */ | |
956 aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL); | |
957 | |
958 /* Free the items */ | |
959 for (i=0; i<num; i++) { | |
960 if (delitems[i]->name) | |
961 free(delitems[i]->name); | |
962 if (delitems[i]->data) | |
963 aim_freetlvchain((aim_tlvlist_t **)&delitems[i]->data); | |
964 free(delitems[i]); | |
965 } | |
966 free(delitems); | |
967 | |
968 /* Rebuild the additional data in the parent group */ | |
969 aim_ssi_itemlist_rebuildgroup(&sess->ssi.items, parentgroup); | |
970 | |
971 /* Send the mod item SNAC */ | |
972 aim_ssi_addmoddel(sess, conn, &parentgroup, 1, AIM_CB_SSI_MOD); | |
973 | |
974 /* Delete the group, but only if it's empty */ | |
975 if (!parentgroup->data) | |
976 aim_ssi_delmastergroup(sess, conn); | |
977 | |
978 /* Begin sending SSI SNACs */ | |
979 aim_ssi_dispatch(sess, conn); | |
980 | |
981 return 0; | |
982 } | |
983 | |
984 /** | |
985 * Delete an array of a certain type of item from the list. This can be | |
986 * used for permit buddies, deny buddies, ICQ's ignore buddies, and | |
987 * probably other types, also. | |
988 * | |
989 * @param sess The oscar session. | |
990 * @param conn The bos connection for this session. | |
991 * @param sn An array of null terminated strings of the items you want to delete. | |
992 * @param num The number of items you are deleting (size of the sn array). | |
993 * @return Return 0 if no errors, otherwise return the error number. | |
994 */ | |
995 faim_export int aim_ssi_delpord(aim_session_t *sess, aim_conn_t *conn, const char **sn, unsigned int num, fu16_t type) { | |
996 struct aim_ssi_item *cur, **delitems; | |
997 int i; | |
998 | |
999 if (!sess || !conn || !sn || !num || (type!=AIM_SSI_TYPE_PERMIT && type!=AIM_SSI_TYPE_DENY)) | |
1000 return -EINVAL; | |
1001 | |
1002 /* Allocate an array of pointers to each of the items to be deleted */ | |
1003 delitems = (struct aim_ssi_item **)malloc(num*sizeof(struct aim_ssi_item *)); | |
1004 memset(delitems, 0, num*sizeof(struct aim_ssi_item *)); | |
1005 | |
1006 /* Make the delitems array a pointer to the aim_ssi_item structs to be deleted */ | |
1007 for (i=0; i<num; i++) { | |
1008 if (!(delitems[i] = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, sn[i], type))) { | |
1009 free(delitems); | |
1010 return -EINVAL; | |
1011 } | |
1012 | |
1013 /* Remove the delitems from the item list */ | |
1014 if (sess->ssi.items == delitems[i]) { | |
1015 sess->ssi.items = sess->ssi.items->next; | |
1016 } else { | |
1017 for (cur=sess->ssi.items; (cur->next && (cur->next!=delitems[i])); cur=cur->next); | |
1018 if (cur->next) | |
1019 cur->next = cur->next->next; | |
1020 } | |
1021 } | |
1022 | |
1023 /* Send the del item SNAC */ | |
1024 aim_ssi_addmoddel(sess, conn, delitems, num, AIM_CB_SSI_DEL); | |
1025 | |
1026 /* Free the items */ | |
1027 for (i=0; i<num; i++) { | |
1028 if (delitems[i]->name) | |
1029 free(delitems[i]->name); | |
1030 if (delitems[i]->data) | |
1031 aim_freetlvchain((aim_tlvlist_t **)&delitems[i]->data); | |
1032 free(delitems[i]); | |
1033 } | |
1034 free(delitems); | |
1035 | |
1036 /* Begin sending SSI SNACs */ | |
1037 aim_ssi_dispatch(sess, conn); | |
1038 | 894 |
1039 return 0; | 895 return 0; |
1040 } | 896 } |
1041 | 897 |
1042 /** | 898 /** |
1052 * 5 - Allow only users on my buddy list | 908 * 5 - Allow only users on my buddy list |
1053 * @param vismask A bitmask of the class of users to whom you want to be | 909 * @param vismask A bitmask of the class of users to whom you want to be |
1054 * visible. See the AIM_FLAG_BLEH #defines in aim.h | 910 * visible. See the AIM_FLAG_BLEH #defines in aim.h |
1055 * @return Return 0 if no errors, otherwise return the error number. | 911 * @return Return 0 if no errors, otherwise return the error number. |
1056 */ | 912 */ |
1057 faim_export int aim_ssi_setpermdeny(aim_session_t *sess, aim_conn_t *conn, fu8_t permdeny, fu32_t vismask) { | 913 faim_export int aim_ssi_setpermdeny(aim_session_t *sess, aim_conn_t *conn, fu8_t permdeny, fu32_t vismask) |
1058 struct aim_ssi_item *cur; | 914 { |
1059 aim_tlv_t *tlv; | 915 struct aim_ssi_item *tmp; |
916 aim_tlvlist_t *data = NULL; | |
1060 | 917 |
1061 if (!sess || !conn) | 918 if (!sess || !conn) |
1062 return -EINVAL; | 919 return -EINVAL; |
1063 | 920 |
1064 /* Look up the permit/deny settings item */ | 921 /* Need to add the x00ca TLV to the TLV chain */ |
1065 cur = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PDINFO); | 922 aim_addtlvtochain8(&data, 0x00ca, permdeny); |
1066 | 923 |
1067 if (cur) { | 924 /* Need to add the x00cb TLV to the TLV chain */ |
1068 /* The permit/deny item exists */ | 925 aim_addtlvtochain32(&data, 0x00cb, vismask); |
1069 if (cur->data && (tlv = aim_gettlv(cur->data, 0x00ca, 1))) { | 926 |
1070 /* Just change the value of the x00ca TLV */ | 927 if ((tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, NULL, AIM_SSI_TYPE_PDINFO))) { |
1071 if (tlv->length != 1) { | 928 aim_freetlvchain(&tmp->data); |
1072 tlv->length = 1; | 929 tmp->data = data; |
1073 free(tlv->value); | |
1074 tlv->value = (fu8_t *)malloc(sizeof(fu8_t)); | |
1075 } | |
1076 tlv->value[0] = permdeny; | |
1077 } else { | |
1078 /* Need to add the x00ca TLV to the TLV chain */ | |
1079 aim_addtlvtochain8((aim_tlvlist_t**)&cur->data, 0x00ca, permdeny); | |
1080 } | |
1081 | |
1082 if (cur->data && (tlv = aim_gettlv(cur->data, 0x00cb, 1))) { | |
1083 /* Just change the value of the x00cb TLV */ | |
1084 if (tlv->length != 4) { | |
1085 tlv->length = 4; | |
1086 free(tlv->value); | |
1087 tlv->value = (fu8_t *)malloc(4*sizeof(fu8_t)); | |
1088 } | |
1089 aimutil_put32(tlv->value, vismask); | |
1090 } else { | |
1091 /* Need to add the x00cb TLV to the TLV chain */ | |
1092 aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00cb, vismask); | |
1093 } | |
1094 | |
1095 /* Send the mod item SNAC */ | |
1096 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_MOD); | |
1097 } else { | 930 } else { |
1098 /* Need to add the permit/deny item */ | 931 tmp = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PDINFO, data); |
1099 if (!(cur = aim_ssi_itemlist_add(&sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PDINFO))) | 932 } |
1100 return -ENOMEM; | 933 |
1101 aim_addtlvtochain8((aim_tlvlist_t**)&cur->data, 0x00ca, permdeny); | 934 /* Sync our local list with the server list */ |
1102 aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00cb, vismask); | 935 aim_ssi_sync(sess, conn); |
1103 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD); | |
1104 } | |
1105 | |
1106 /* Begin sending SSI SNACs */ | |
1107 aim_ssi_dispatch(sess, conn); | |
1108 | 936 |
1109 return 0; | 937 return 0; |
1110 } | 938 } |
1111 | 939 |
1112 /** | 940 /** |
1117 * @param presence I think it's a bitmask, but I only know what one of the bits is: | 945 * @param presence I think it's a bitmask, but I only know what one of the bits is: |
1118 * 0x00000400 - Allow others to see your idle time | 946 * 0x00000400 - Allow others to see your idle time |
1119 * @return Return 0 if no errors, otherwise return the error number. | 947 * @return Return 0 if no errors, otherwise return the error number. |
1120 */ | 948 */ |
1121 faim_export int aim_ssi_setpresence(aim_session_t *sess, aim_conn_t *conn, fu32_t presence) { | 949 faim_export int aim_ssi_setpresence(aim_session_t *sess, aim_conn_t *conn, fu32_t presence) { |
1122 struct aim_ssi_item *cur; | 950 struct aim_ssi_item *tmp; |
951 aim_tlvlist_t *data = NULL; | |
952 | |
953 if (!sess || !conn) | |
954 return -EINVAL; | |
955 | |
956 /* Need to add the x00c9 TLV to the TLV chain */ | |
957 aim_addtlvtochain32(&data, 0x00c9, presence); | |
958 | |
959 if ((tmp = aim_ssi_itemlist_finditem(sess->ssi.local, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS))) { | |
960 aim_freetlvchain(&tmp->data); | |
961 tmp->data = data; | |
962 } else { | |
963 tmp = aim_ssi_itemlist_add(&sess->ssi.local, NULL, 0x0000, 0xFFFF, AIM_SSI_TYPE_PRESENCEPREFS, data); | |
964 } | |
965 | |
966 /* Sync our local list with the server list */ | |
967 aim_ssi_sync(sess, conn); | |
968 | |
969 return 0; | |
970 } | |
971 | |
972 /* | |
973 * Subtype 0x0002 - Request SSI Rights. | |
974 */ | |
975 faim_export int aim_ssi_reqrights(aim_session_t *sess, aim_conn_t *conn) | |
976 { | |
977 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQRIGHTS); | |
978 } | |
979 | |
980 /* | |
981 * Subtype 0x0003 - SSI Rights Information. | |
982 */ | |
983 static int parserights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | |
984 { | |
985 int ret = 0, i; | |
986 aim_rxcallback_t userfunc; | |
987 aim_tlvlist_t *tlvlist; | |
1123 aim_tlv_t *tlv; | 988 aim_tlv_t *tlv; |
1124 | 989 aim_bstream_t bstream; |
1125 if (!sess || !conn) | 990 fu16_t *maxitems; |
1126 return -EINVAL; | 991 |
1127 | 992 /* This SNAC is made up of a bunch of TLVs */ |
1128 /* Look up the item */ | 993 tlvlist = aim_readtlvchain(bs); |
1129 cur = aim_ssi_itemlist_finditem(sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS); | 994 |
1130 | 995 /* TLV 0x0004 contains the maximum number of each item */ |
1131 if (cur) { | 996 if (!(tlv = aim_gettlv(tlvlist, 0x0004, 1))) { |
1132 /* The item exists */ | 997 aim_freetlvchain(&tlvlist); |
1133 if (cur->data && (tlv = aim_gettlv(cur->data, 0x00c9, 1))) { | 998 return 0; |
1134 /* Just change the value of the x00c9 TLV */ | 999 } |
1135 if (tlv->length != 4) { | 1000 |
1136 tlv->length = 4; | 1001 aim_bstream_init(&bstream, tlv->value, tlv->length); |
1137 free(tlv->value); | 1002 |
1138 tlv->value = (fu8_t *)malloc(4*sizeof(fu8_t)); | 1003 if (!(maxitems = (fu16_t *)malloc((tlv->length/2)*sizeof(fu16_t)))) { |
1139 } | 1004 aim_freetlvchain(&tlvlist); |
1140 aimutil_put32(tlv->value, presence); | 1005 return 0; |
1141 } else { | 1006 } |
1142 /* Need to add the x00c9 TLV to the TLV chain */ | 1007 |
1143 aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00c9, presence); | 1008 for (i=0; i<(tlv->length/2); i++) |
1144 } | 1009 maxitems[i] = aimbs_get16(&bstream); |
1145 | |
1146 /* Send the mod item SNAC */ | |
1147 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_MOD); | |
1148 } else { | |
1149 /* Need to add the item */ | |
1150 if (!(cur = aim_ssi_itemlist_add(&sess->ssi.items, NULL, NULL, AIM_SSI_TYPE_PRESENCEPREFS))) | |
1151 return -ENOMEM; | |
1152 aim_addtlvtochain32((aim_tlvlist_t**)&cur->data, 0x00c9, presence); | |
1153 aim_ssi_addmoddel(sess, conn, &cur, 1, AIM_CB_SSI_ADD); | |
1154 } | |
1155 | |
1156 /* Begin sending SSI SNACs */ | |
1157 aim_ssi_dispatch(sess, conn); | |
1158 | |
1159 return 0; | |
1160 } | |
1161 | |
1162 /* | |
1163 * Request SSI Rights. | |
1164 */ | |
1165 faim_export int aim_ssi_reqrights(aim_session_t *sess, aim_conn_t *conn) | |
1166 { | |
1167 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_REQRIGHTS); | |
1168 } | |
1169 | |
1170 /* | |
1171 * SSI Rights Information. | |
1172 */ | |
1173 static int parserights(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | |
1174 { | |
1175 int ret = 0; | |
1176 aim_rxcallback_t userfunc; | |
1177 | 1010 |
1178 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | 1011 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) |
1179 ret = userfunc(sess, rx); | 1012 ret = userfunc(sess, rx, tlv->length/2, maxitems); |
1013 | |
1014 aim_freetlvchain(&tlvlist); | |
1015 free(maxitems); | |
1180 | 1016 |
1181 return ret; | 1017 return ret; |
1182 } | 1018 } |
1183 | 1019 |
1184 /* | 1020 /* |
1185 * Request SSI Data. | 1021 * Subtype 0x0004 - Request SSI Data. |
1022 * XXX - If you don't a timestamp and revision number? | |
1023 * | |
1024 * Note that the client should never increment the revision, only the server. | |
1025 * | |
1026 */ | |
1027 | |
1028 | |
1029 /* | |
1030 * Subtype 0x0005 - Request SSI Data. | |
1031 * XXX - If you have a timestamp and revision number? | |
1186 * | 1032 * |
1187 * The data will only be sent if it is newer than the posted local | 1033 * The data will only be sent if it is newer than the posted local |
1188 * timestamp and revision. | 1034 * timestamp and revision. |
1189 * | 1035 * |
1190 * Note that the client should never increment the revision, only the server. | 1036 * Note that the client should never increment the revision, only the server. |
1207 aimbs_put32(&fr->data, localstamp); | 1053 aimbs_put32(&fr->data, localstamp); |
1208 aimbs_put16(&fr->data, localrev); | 1054 aimbs_put16(&fr->data, localrev); |
1209 | 1055 |
1210 aim_tx_enqueue(sess, fr); | 1056 aim_tx_enqueue(sess, fr); |
1211 | 1057 |
1212 return 0; | 1058 /* Free any current data, just in case */ |
1213 } | 1059 aim_ssi_freelist(sess); |
1214 | 1060 |
1215 /* | 1061 return 0; |
1216 * SSI Data. | 1062 } |
1063 | |
1064 /* | |
1065 * Subtype 0x0006 - SSI Data. | |
1217 */ | 1066 */ |
1218 static int parsedata(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | 1067 static int parsedata(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
1219 { | 1068 { |
1220 int ret = 0; | 1069 int ret = 0; |
1221 aim_rxcallback_t userfunc; | 1070 aim_rxcallback_t userfunc; |
1222 struct aim_ssi_item *cur = NULL; | 1071 struct aim_ssi_item *cur, *new; |
1223 fu8_t fmtver; /* guess */ | 1072 fu8_t fmtver; /* guess */ |
1224 fu16_t revision; | 1073 fu16_t numitems, namelen; |
1225 fu32_t timestamp; | 1074 fu32_t timestamp; |
1226 | 1075 |
1076 if (snac->flags & 0x0001) { | |
1077 /* XXX - Free all ssi data? */ | |
1078 } | |
1079 | |
1227 fmtver = aimbs_get8(bs); /* Version of ssi data. Should be 0x00 */ | 1080 fmtver = aimbs_get8(bs); /* Version of ssi data. Should be 0x00 */ |
1228 revision = aimbs_get16(bs); /* # of times ssi data has been modified */ | 1081 numitems = aimbs_get16(bs); /* # of times ssi data has been modified */ |
1229 if (revision != 0) | 1082 sess->ssi.numitems += numitems; |
1230 sess->ssi.revision = revision; | 1083 |
1231 | 1084 /* Read in the list */ |
1232 for (cur = sess->ssi.items; cur && cur->next; cur=cur->next) ; | 1085 /* If we already have a partial list, move cur to the end of it */ |
1233 | 1086 if (sess->ssi.official) |
1234 while (aim_bstream_empty(bs) > 4) { /* last four bytes are stamp */ | 1087 for (cur=sess->ssi.official; cur->next; cur=cur->next); |
1235 fu16_t namelen, tbslen; | 1088 while (aim_bstream_empty(bs) > 4) { /* last four bytes are timestamp */ |
1236 | 1089 if (!sess->ssi.official) { |
1237 if (!sess->ssi.items) { | 1090 if (!(sess->ssi.official = malloc(sizeof(struct aim_ssi_item)))) |
1238 if (!(sess->ssi.items = malloc(sizeof(struct aim_ssi_item)))) | |
1239 return -ENOMEM; | 1091 return -ENOMEM; |
1240 cur = sess->ssi.items; | 1092 cur = sess->ssi.official; |
1241 } else { | 1093 } else { |
1242 if (!(cur->next = malloc(sizeof(struct aim_ssi_item)))) | 1094 if (!(cur->next = malloc(sizeof(struct aim_ssi_item)))) |
1243 return -ENOMEM; | 1095 return -ENOMEM; |
1244 cur = cur->next; | 1096 cur = cur->next; |
1245 } | 1097 } |
1246 memset(cur, 0, sizeof(struct aim_ssi_item)); | |
1247 | |
1248 if ((namelen = aimbs_get16(bs))) | 1098 if ((namelen = aimbs_get16(bs))) |
1249 cur->name = aimbs_getstr(bs, namelen); | 1099 cur->name = aimbs_getstr(bs, namelen); |
1100 else | |
1101 cur->name = NULL; | |
1250 cur->gid = aimbs_get16(bs); | 1102 cur->gid = aimbs_get16(bs); |
1251 cur->bid = aimbs_get16(bs); | 1103 cur->bid = aimbs_get16(bs); |
1252 cur->type = aimbs_get16(bs); | 1104 cur->type = aimbs_get16(bs); |
1253 | 1105 cur->data = aim_readtlvchain_len(bs, aimbs_get16(bs)); |
1254 if ((tbslen = aimbs_get16(bs))) { | 1106 cur->next = NULL; |
1255 aim_bstream_t tbs; | 1107 } |
1256 | 1108 |
1257 aim_bstream_init(&tbs, bs->data + bs->offset /* XXX */, tbslen); | 1109 /* Read in the timestamp */ |
1258 cur->data = (void *)aim_readtlvchain(&tbs); | 1110 timestamp = aimbs_get32(bs); |
1259 aim_bstream_advance(bs, tbslen); | 1111 sess->ssi.timestamp = timestamp; |
1112 | |
1113 if (!(snac->flags & 0x0001)) { | |
1114 /* Make a copy of the list */ | |
1115 for (cur=sess->ssi.official; cur; cur=cur->next) { | |
1116 if (!sess->ssi.local) { | |
1117 if (!(sess->ssi.local = malloc(sizeof(struct aim_ssi_item)))) | |
1118 return -ENOMEM; | |
1119 new = sess->ssi.local; | |
1120 } else { | |
1121 if (!(new->next = malloc(sizeof(struct aim_ssi_item)))) | |
1122 return -ENOMEM; | |
1123 new = new->next; | |
1124 } | |
1125 if (cur->name) { | |
1126 new->name = (char *)malloc((strlen(cur->name)+1)*sizeof(char)); | |
1127 strcpy(new->name, cur->name); | |
1128 } else | |
1129 new->name = NULL; | |
1130 new->gid = cur->gid; | |
1131 new->bid = cur->bid; | |
1132 new->type = cur->type; | |
1133 new->data = aim_tlvlist_copy(cur->data); | |
1260 } | 1134 } |
1261 } | 1135 new->next = NULL; |
1262 | 1136 |
1263 timestamp = aimbs_get32(bs); | 1137 sess->ssi.received_data = 1; |
1264 if (timestamp != 0) | 1138 |
1265 sess->ssi.timestamp = timestamp; | 1139 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) |
1266 sess->ssi.received_data = 1; | 1140 ret = userfunc(sess, rx, fmtver, sess->ssi.numitems, sess->ssi.official, sess->ssi.timestamp); |
1267 | 1141 } |
1268 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
1269 ret = userfunc(sess, rx, fmtver, sess->ssi.revision, sess->ssi.timestamp, sess->ssi.items); | |
1270 | 1142 |
1271 return ret; | 1143 return ret; |
1272 } | 1144 } |
1273 | 1145 |
1274 /* | 1146 /* |
1275 * SSI Data Enable Presence. | 1147 * Subtype 0x0007 - SSI Activate Data. |
1276 * | 1148 * |
1277 * Should be sent after receiving 13/6 or 13/f to tell the server you | 1149 * Should be sent after receiving 13/6 or 13/f to tell the server you |
1278 * are ready to begin using the list. It will promptly give you the | 1150 * are ready to begin using the list. It will promptly give you the |
1279 * presence information for everyone in your list and put your permit/deny | 1151 * presence information for everyone in your list and put your permit/deny |
1280 * settings into effect. | 1152 * settings into effect. |
1284 { | 1156 { |
1285 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, 0x0007); | 1157 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, 0x0007); |
1286 } | 1158 } |
1287 | 1159 |
1288 /* | 1160 /* |
1289 * SSI Add/Mod/Del Item(s). | 1161 * Subtype 0x0008/0x0009/0x000a - SSI Add/Mod/Del Item(s). |
1290 * | 1162 * |
1291 * Sends the SNAC to add, modify, or delete an item from the server-stored | 1163 * Sends the SNAC to add, modify, or delete an item from the server-stored |
1292 * information. These 3 SNACs all have an identical structure. The only | 1164 * information. These 3 SNACs all have an identical structure. The only |
1293 * difference is the subtype that is set for the SNAC. | 1165 * difference is the subtype that is set for the SNAC. |
1294 * | 1166 * |
1295 */ | 1167 */ |
1296 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) | 1168 faim_export int aim_ssi_addmoddel(aim_session_t *sess, aim_conn_t *conn) |
1297 { | 1169 { |
1298 aim_frame_t *fr; | 1170 aim_frame_t *fr; |
1299 aim_snacid_t snacid; | 1171 aim_snacid_t snacid; |
1300 int i, snaclen; | 1172 int snaclen; |
1301 | 1173 struct aim_ssi_tmp *cur; |
1302 if (!sess || !conn || !items || !num) | 1174 |
1303 return -EINVAL; | 1175 if (!sess || !conn || !sess->ssi.pending || !sess->ssi.pending->item) |
1304 | 1176 return -EINVAL; |
1177 | |
1178 /* Calculate total SNAC size */ | |
1305 snaclen = 10; /* For family, subtype, flags, and SNAC ID */ | 1179 snaclen = 10; /* For family, subtype, flags, and SNAC ID */ |
1306 for (i=0; i<num; i++) { | 1180 for (cur=sess->ssi.pending; cur; cur=cur->next) { |
1307 snaclen += 10; /* For length, GID, BID, type, and length */ | 1181 snaclen += 10; /* For length, GID, BID, type, and length */ |
1308 if (items[i]->name) | 1182 if (cur->item->name) |
1309 snaclen += strlen(items[i]->name); | 1183 snaclen += strlen(cur->item->name); |
1310 if (items[i]->data) | 1184 if (cur->item->data) |
1311 snaclen += aim_sizetlvchain((aim_tlvlist_t **)&items[i]->data); | 1185 snaclen += aim_sizetlvchain(&cur->item->data); |
1312 } | 1186 } |
1313 | 1187 |
1314 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, snaclen))) | 1188 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, snaclen))) |
1315 return -ENOMEM; | 1189 return -ENOMEM; |
1316 | 1190 |
1317 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, subtype, 0x0000, NULL, 0); | 1191 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, sess->ssi.pending->action, 0x0000, NULL, 0); |
1318 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, subtype, 0x0000, snacid); | 1192 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, sess->ssi.pending->action, 0x0000, snacid); |
1319 | 1193 |
1320 for (i=0; i<num; i++) { | 1194 for (cur=sess->ssi.pending; cur; cur=cur->next) { |
1321 aimbs_put16(&fr->data, items[i]->name ? strlen(items[i]->name) : 0); | 1195 aimbs_put16(&fr->data, cur->item->name ? strlen(cur->item->name) : 0); |
1322 if (items[i]->name) | 1196 if (cur->item->name) |
1323 aimbs_putraw(&fr->data, items[i]->name, strlen(items[i]->name)); | 1197 aimbs_putraw(&fr->data, cur->item->name, strlen(cur->item->name)); |
1324 aimbs_put16(&fr->data, items[i]->gid); | 1198 aimbs_put16(&fr->data, cur->item->gid); |
1325 aimbs_put16(&fr->data, items[i]->bid); | 1199 aimbs_put16(&fr->data, cur->item->bid); |
1326 aimbs_put16(&fr->data, items[i]->type); | 1200 aimbs_put16(&fr->data, cur->item->type); |
1327 aimbs_put16(&fr->data, items[i]->data ? aim_sizetlvchain((aim_tlvlist_t **)&items[i]->data) : 0); | 1201 aimbs_put16(&fr->data, cur->item->data ? aim_sizetlvchain(&cur->item->data) : 0); |
1328 if (items[i]->data) | 1202 if (cur->item->data) |
1329 aim_writetlvchain(&fr->data, (aim_tlvlist_t **)&items[i]->data); | 1203 aim_writetlvchain(&fr->data, &cur->item->data); |
1330 } | 1204 } |
1331 | 1205 |
1332 aim_ssi_enqueue(sess, conn, fr); | 1206 aim_tx_enqueue(sess, fr); |
1333 | 1207 |
1334 return 0; | 1208 return 0; |
1335 } | 1209 } |
1336 | 1210 |
1337 /* | 1211 /* |
1338 * SSI Add/Mod/Del Ack. | 1212 * Subtype 0x0008 - Incoming SSI add. |
1339 * | 1213 * |
1340 * Response to add, modify, or delete SNAC (sent with aim_ssi_addmoddel). | 1214 * XXX - It would probably be good for the client to actually do something when it gets this. |
1341 * | 1215 */ |
1342 */ | 1216 static int parseadd(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
1343 static int parseack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | |
1344 { | 1217 { |
1345 int ret = 0; | 1218 int ret = 0; |
1346 aim_rxcallback_t userfunc; | 1219 aim_rxcallback_t userfunc; |
1347 | 1220 char *name; |
1348 sess->ssi.waiting_for_ack = 0; | 1221 fu16_t len, gid, bid, type; |
1349 aim_ssi_dispatch(sess, rx->conn); | 1222 aim_tlvlist_t *data; |
1223 | |
1224 while (aim_bstream_empty(bs)) { | |
1225 if ((len = aimbs_get16(bs))) | |
1226 name = aimbs_getstr(bs, len); | |
1227 else | |
1228 name = NULL; | |
1229 gid = aimbs_get16(bs); | |
1230 bid = aimbs_get16(bs); | |
1231 type = aimbs_get16(bs); | |
1232 if ((len = aimbs_get16(bs))) | |
1233 data = aim_readtlvchain_len(bs, len); | |
1234 else | |
1235 data = NULL; | |
1236 | |
1237 aim_ssi_itemlist_add(&sess->ssi.local, name, gid, bid, type, data); | |
1238 aim_ssi_itemlist_add(&sess->ssi.official, name, gid, bid, type, aim_tlvlist_copy(data)); | |
1239 | |
1240 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
1241 ret = userfunc(sess, rx); | |
1242 | |
1243 free(name); | |
1244 } | |
1245 | |
1246 return ret; | |
1247 } | |
1248 | |
1249 /* | |
1250 * Subtype 0x0009 - Incoming SSI mod. | |
1251 * | |
1252 * XXX - It would probably be good for the client to actually do something when it gets this. | |
1253 */ | |
1254 static int parsemod(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | |
1255 { | |
1256 int ret = 0; | |
1257 aim_rxcallback_t userfunc; | |
1258 char *name; | |
1259 fu16_t len, gid, bid, type; | |
1260 aim_tlvlist_t *data; | |
1261 struct aim_ssi_item *item; | |
1262 | |
1263 while (aim_bstream_empty(bs)) { | |
1264 if ((len = aimbs_get16(bs))) | |
1265 name = aimbs_getstr(bs, len); | |
1266 else | |
1267 name = NULL; | |
1268 gid = aimbs_get16(bs); | |
1269 bid = aimbs_get16(bs); | |
1270 type = aimbs_get16(bs); | |
1271 if ((len = aimbs_get16(bs))) | |
1272 data = aim_readtlvchain_len(bs, len); | |
1273 else | |
1274 data = NULL; | |
1275 | |
1276 /* Replace the 2 local items with the given one */ | |
1277 if ((item = aim_ssi_itemlist_find(sess->ssi.local, gid, bid))) { | |
1278 item->type = type; | |
1279 free(item->name); | |
1280 if (name) { | |
1281 item->name = (char *)malloc((strlen(name)+1)*sizeof(char)); | |
1282 strcpy(item->name, name); | |
1283 } else | |
1284 item->name = NULL; | |
1285 aim_freetlvchain(&item->data); | |
1286 item->data = data; | |
1287 } | |
1288 | |
1289 if ((item = aim_ssi_itemlist_find(sess->ssi.official, gid, bid))) { | |
1290 item->type = type; | |
1291 free(item->name); | |
1292 if (name) { | |
1293 item->name = (char *)malloc((strlen(name)+1)*sizeof(char)); | |
1294 strcpy(item->name, name); | |
1295 } else | |
1296 item->name = NULL; | |
1297 aim_freetlvchain(&item->data); | |
1298 item->data = data; | |
1299 } | |
1300 | |
1301 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
1302 ret = userfunc(sess, rx); | |
1303 | |
1304 free(name); | |
1305 } | |
1306 | |
1307 return ret; | |
1308 } | |
1309 | |
1310 /* | |
1311 * Subtype 0x000a - Incoming SSI del. | |
1312 * | |
1313 * XXX - It would probably be good for the client to actually do something when it gets this. | |
1314 */ | |
1315 static int parsedel(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | |
1316 { | |
1317 int ret = 0; | |
1318 aim_rxcallback_t userfunc; | |
1319 fu16_t gid, bid; | |
1320 struct aim_ssi_item *del; | |
1321 | |
1322 while (aim_bstream_empty(bs)) { | |
1323 aim_bstream_advance(bs, aimbs_get16(bs)); | |
1324 gid = aimbs_get16(bs); | |
1325 bid = aimbs_get16(bs); | |
1326 aimbs_get16(bs); | |
1327 aim_bstream_advance(bs, aimbs_get16(bs)); | |
1328 | |
1329 del = aim_ssi_itemlist_find(sess->ssi.local, gid, bid); | |
1330 aim_ssi_itemlist_del(&sess->ssi.local, del); | |
1331 del = aim_ssi_itemlist_find(sess->ssi.official, gid, bid); | |
1332 aim_ssi_itemlist_del(&sess->ssi.official, del); | |
1333 | |
1334 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
1335 ret = userfunc(sess, rx); | |
1336 } | |
1337 | |
1338 return ret; | |
1339 } | |
1340 | |
1341 /* | |
1342 * Subtype 0x000e - SSI Add/Mod/Del Ack. | |
1343 * | |
1344 * Response to add, modify, or delete SNAC (sent with aim_ssi_addmoddel). | |
1345 * | |
1346 */ | |
1347 static int parseack(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | |
1348 { | |
1349 int ret = 0; | |
1350 aim_rxcallback_t userfunc; | |
1351 struct aim_ssi_tmp *cur, *del; | |
1352 | |
1353 /* Read in the success/failure flags from the ack SNAC */ | |
1354 cur = sess->ssi.pending; | |
1355 while (cur && (aim_bstream_empty(bs)>0)) { | |
1356 cur->ack = aimbs_get16(bs); | |
1357 cur = cur->next; | |
1358 } | |
1359 | |
1360 /* | |
1361 * If outcome is 0, then add the item to the item list, or replace the other item, | |
1362 * or remove the old item. If outcome is non-zero, then remove the item from the | |
1363 * local list, or unmodify it, or add it. | |
1364 */ | |
1365 for (cur=sess->ssi.pending; (cur && (cur->ack != 0xffff)); cur=cur->next) { | |
1366 if (cur->item) { | |
1367 if (cur->ack) { | |
1368 /* Our action was unsuccessful, so change the local list back to how it was */ | |
1369 if (cur->action == AIM_CB_SSI_ADD) { | |
1370 /* Remove the item from the items list */ | |
1371 if (cur->item->name) { | |
1372 cur->name = (char *)malloc((strlen(cur->item->name)+1)*sizeof(char)); | |
1373 strcpy(cur->name, cur->item->name); | |
1374 } | |
1375 aim_ssi_itemlist_del(&sess->ssi.local, cur->item); | |
1376 cur->item = NULL; | |
1377 | |
1378 } else if (cur->action == AIM_CB_SSI_MOD) { | |
1379 /* Replace the new item with the old item in the items list */ | |
1380 struct aim_ssi_item *cur1; | |
1381 if ((cur1 = aim_ssi_itemlist_find(sess->ssi.local, cur->item->gid, cur->item->bid))) { | |
1382 free(cur1->name); | |
1383 if (cur->item->name) { | |
1384 cur1->name = (char *)malloc((strlen(cur->item->name)+1)*sizeof(char)); | |
1385 strcpy(cur1->name, cur->item->name); | |
1386 } else | |
1387 cur1->name = NULL; | |
1388 aim_freetlvchain(&cur1->data); | |
1389 cur1->data = aim_tlvlist_copy(cur->item->data); | |
1390 } | |
1391 | |
1392 } else if (cur->action == AIM_CB_SSI_DEL) { | |
1393 /* Add the item to the items list */ | |
1394 aim_tlvlist_t *data; | |
1395 data = aim_tlvlist_copy(cur->item->data); | |
1396 aim_ssi_itemlist_add(&sess->ssi.local, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, data); | |
1397 } | |
1398 | |
1399 } else { | |
1400 /* Do the exact opposite */ | |
1401 if (cur->action == AIM_CB_SSI_ADD) { | |
1402 /* Add the item to the items list */ | |
1403 aim_tlvlist_t *data; | |
1404 data = aim_tlvlist_copy(cur->item->data); | |
1405 aim_ssi_itemlist_add(&sess->ssi.official, cur->item->name, cur->item->gid, cur->item->bid, cur->item->type, data); | |
1406 | |
1407 } else if (cur->action == AIM_CB_SSI_MOD) { | |
1408 /* Replace the old item with the new item in the items list */ | |
1409 struct aim_ssi_item *cur1; | |
1410 if ((cur1 = aim_ssi_itemlist_find(sess->ssi.official, cur->item->gid, cur->item->bid))) { | |
1411 free(cur1->name); | |
1412 if (cur->item->name) { | |
1413 cur1->name = (char *)malloc((strlen(cur->item->name)+1)*sizeof(char)); | |
1414 strcpy(cur1->name, cur->item->name); | |
1415 } else | |
1416 cur1->name = NULL; | |
1417 aim_freetlvchain(&cur1->data); | |
1418 cur1->data = aim_tlvlist_copy(cur->item->data); | |
1419 } | |
1420 | |
1421 } else if (cur->action == AIM_CB_SSI_DEL) { | |
1422 /* Remove the item from the items list */ | |
1423 aim_ssi_itemlist_del(&sess->ssi.official, cur->item); | |
1424 cur->item = NULL; | |
1425 } | |
1426 | |
1427 } | |
1428 } /* End if (cur->item) */ | |
1429 } /* End for loop */ | |
1430 | |
1431 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
1432 ret = userfunc(sess, rx, sess->ssi.pending); | |
1433 | |
1434 /* Free all aim_ssi_tmp's with an outcome */ | |
1435 cur = sess->ssi.pending; | |
1436 while (cur && (cur->ack != 0xffff)) { | |
1437 del = cur; | |
1438 cur = cur->next; | |
1439 free(del->name); | |
1440 free(del); | |
1441 } | |
1442 sess->ssi.pending = cur; | |
1443 | |
1444 /* If we're not waiting for any more acks, then send more SNACs */ | |
1445 if (!sess->ssi.pending) { | |
1446 sess->ssi.pending = NULL; | |
1447 sess->ssi.waiting_for_ack = 0; | |
1448 aim_ssi_sync(sess, rx->conn); | |
1449 } | |
1450 | |
1451 return ret; | |
1452 } | |
1453 | |
1454 /* | |
1455 * Subtype 0x000f - SSI Data Unchanged. | |
1456 * | |
1457 * Response to aim_ssi_reqdata() if the server-side data is not newer than | |
1458 * posted local stamp/revision. | |
1459 * | |
1460 */ | |
1461 static int parsedataunchanged(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | |
1462 { | |
1463 int ret = 0; | |
1464 aim_rxcallback_t userfunc; | |
1465 | |
1466 sess->ssi.received_data = 1; | |
1350 | 1467 |
1351 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | 1468 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) |
1352 ret = userfunc(sess, rx); | 1469 ret = userfunc(sess, rx); |
1353 | 1470 |
1354 return ret; | 1471 return ret; |
1355 } | 1472 } |
1356 | 1473 |
1357 /* | 1474 /* |
1358 * SSI Begin Data Modification. | 1475 * Subtype 0x0011 - SSI Begin Data Modification. |
1359 * | 1476 * |
1360 * Tells the server you're going to start modifying data. | 1477 * Tells the server you're going to start modifying data. |
1361 * | 1478 * |
1362 */ | 1479 */ |
1363 faim_export int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn) | 1480 faim_export int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn) |
1364 { | 1481 { |
1365 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTART); | 1482 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTART); |
1366 } | 1483 } |
1367 | 1484 |
1368 /* | 1485 /* |
1369 * SSI End Data Modification. | 1486 * Subtype 0x0012 - SSI End Data Modification. |
1370 * | 1487 * |
1371 * Tells the server you're done modifying data. | 1488 * Tells the server you're finished modifying data. |
1372 * | 1489 * |
1373 */ | 1490 */ |
1374 faim_export int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn) | 1491 faim_export int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn) |
1375 { | 1492 { |
1376 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTOP); | 1493 return aim_genericreq_n(sess, conn, AIM_CB_FAM_SSI, AIM_CB_SSI_EDITSTOP); |
1377 } | 1494 } |
1378 | 1495 |
1379 /* | 1496 /* |
1380 * SSI Data Unchanged. | 1497 * Subtype 0x0014 - Grant authorization |
1381 * | 1498 * |
1382 * Response to aim_ssi_reqdata() if the server-side data is not newer than | 1499 * Authorizes a contact so they can add you to their contact list. |
1383 * posted local stamp/revision. | 1500 * |
1384 * | 1501 */ |
1385 */ | 1502 faim_export int aim_ssi_sendauth(aim_session_t *sess, aim_conn_t *conn, char *sn, char *msg) |
1386 static int parsedataunchanged(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | 1503 { |
1504 aim_frame_t *fr; | |
1505 aim_snacid_t snacid; | |
1506 | |
1507 if (!sess || !conn || !sn) | |
1508 return -EINVAL; | |
1509 | |
1510 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2))) | |
1511 return -ENOMEM; | |
1512 | |
1513 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTH, 0x0000, NULL, 0); | |
1514 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTH, 0x0000, snacid); | |
1515 | |
1516 /* Screen name */ | |
1517 aimbs_put8(&fr->data, strlen(sn)); | |
1518 aimbs_putraw(&fr->data, sn, strlen(sn)); | |
1519 | |
1520 /* Message (null terminated) */ | |
1521 aimbs_put16(&fr->data, msg ? strlen(msg) : 0); | |
1522 if (msg) { | |
1523 aimbs_putraw(&fr->data, msg, strlen(msg)); | |
1524 aimbs_put8(&fr->data, 0x00); | |
1525 } | |
1526 | |
1527 /* Unknown */ | |
1528 aimbs_put16(&fr->data, 0x0000); | |
1529 | |
1530 aim_tx_enqueue(sess, fr); | |
1531 | |
1532 return 0; | |
1533 } | |
1534 | |
1535 /* | |
1536 * Subtype 0x0015 - Receive an authorization grant | |
1537 */ | |
1538 static int receiveauthgrant(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | |
1387 { | 1539 { |
1388 int ret = 0; | 1540 int ret = 0; |
1389 aim_rxcallback_t userfunc; | 1541 aim_rxcallback_t userfunc; |
1390 | 1542 fu16_t tmp; |
1391 sess->ssi.received_data = 1; | 1543 char *sn, *msg; |
1544 | |
1545 /* Read screen name */ | |
1546 if ((tmp = aimbs_get8(bs))) | |
1547 sn = aimbs_getstr(bs, tmp); | |
1548 else | |
1549 sn = NULL; | |
1550 | |
1551 /* Read message (null terminated) */ | |
1552 if ((tmp = aimbs_get16(bs))) | |
1553 msg = aimbs_getstr(bs, tmp); | |
1554 else | |
1555 msg = NULL; | |
1556 | |
1557 /* Unknown */ | |
1558 tmp = aimbs_get16(bs); | |
1392 | 1559 |
1393 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | 1560 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) |
1394 ret = userfunc(sess, rx); | 1561 ret = userfunc(sess, rx, sn, msg); |
1562 | |
1563 free(sn); | |
1564 free(msg); | |
1565 | |
1566 return ret; | |
1567 } | |
1568 | |
1569 /* | |
1570 * Subtype 0x0018 - Send authorization request | |
1571 * | |
1572 * Sends a request for authorization to the given contact. The request will either be | |
1573 * granted, denied, or dropped. | |
1574 * | |
1575 */ | |
1576 faim_export int aim_ssi_sendauthrequest(aim_session_t *sess, aim_conn_t *conn, char *sn, char *msg) | |
1577 { | |
1578 aim_frame_t *fr; | |
1579 aim_snacid_t snacid; | |
1580 | |
1581 if (!sess || !conn || !sn) | |
1582 return -EINVAL; | |
1583 | |
1584 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2))) | |
1585 return -ENOMEM; | |
1586 | |
1587 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREQ, 0x0000, NULL, 0); | |
1588 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREQ, 0x0000, snacid); | |
1589 | |
1590 /* Screen name */ | |
1591 aimbs_put8(&fr->data, strlen(sn)); | |
1592 aimbs_putraw(&fr->data, sn, strlen(sn)); | |
1593 | |
1594 /* Message (null terminated) */ | |
1595 aimbs_put16(&fr->data, msg ? strlen(msg) : 0); | |
1596 if (msg) { | |
1597 aimbs_putraw(&fr->data, msg, strlen(msg)); | |
1598 aimbs_put8(&fr->data, 0x00); | |
1599 } | |
1600 | |
1601 /* Unknown */ | |
1602 aimbs_put16(&fr->data, 0x0000); | |
1603 | |
1604 aim_tx_enqueue(sess, fr); | |
1605 | |
1606 return 0; | |
1607 } | |
1608 | |
1609 /* | |
1610 * Subtype 0x0019 - Receive an authorization request | |
1611 */ | |
1612 static int receiveauthrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | |
1613 { | |
1614 int ret = 0; | |
1615 aim_rxcallback_t userfunc; | |
1616 fu16_t tmp; | |
1617 char *sn, *msg; | |
1618 | |
1619 /* Read screen name */ | |
1620 if ((tmp = aimbs_get8(bs))) | |
1621 sn = aimbs_getstr(bs, tmp); | |
1622 else | |
1623 sn = NULL; | |
1624 | |
1625 /* Read message (null terminated) */ | |
1626 if ((tmp = aimbs_get16(bs))) | |
1627 msg = aimbs_getstr(bs, tmp); | |
1628 else | |
1629 msg = NULL; | |
1630 | |
1631 /* Unknown */ | |
1632 tmp = aimbs_get16(bs); | |
1633 | |
1634 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
1635 ret = userfunc(sess, rx, sn, msg); | |
1636 | |
1637 free(sn); | |
1638 free(msg); | |
1639 | |
1640 return ret; | |
1641 } | |
1642 | |
1643 /* | |
1644 * Subtype 0x001a - Send authorization reply | |
1645 * | |
1646 * Sends a reply to a request for authorization. The reply can either | |
1647 * grant authorization or deny authorization. | |
1648 * | |
1649 * if reply=0x00 then deny | |
1650 * if reply=0x01 then grant | |
1651 * | |
1652 */ | |
1653 faim_export int aim_ssi_sendauthreply(aim_session_t *sess, aim_conn_t *conn, char *sn, fu8_t reply, char *msg) | |
1654 { | |
1655 aim_frame_t *fr; | |
1656 aim_snacid_t snacid; | |
1657 | |
1658 if (!sess || !conn || !sn) | |
1659 return -EINVAL; | |
1660 | |
1661 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 1+strlen(sn) + 1 + 2+(msg ? strlen(msg)+1 : 0) + 2))) | |
1662 return -ENOMEM; | |
1663 | |
1664 snacid = aim_cachesnac(sess, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREP, 0x0000, NULL, 0); | |
1665 aim_putsnac(&fr->data, AIM_CB_FAM_SSI, AIM_CB_SSI_SENDAUTHREP, 0x0000, snacid); | |
1666 | |
1667 /* Screen name */ | |
1668 aimbs_put8(&fr->data, strlen(sn)); | |
1669 aimbs_putraw(&fr->data, sn, strlen(sn)); | |
1670 | |
1671 /* Grant or deny */ | |
1672 aimbs_put8(&fr->data, reply); | |
1673 | |
1674 /* Message (null terminated) */ | |
1675 aimbs_put16(&fr->data, msg ? (strlen(msg)+1) : 0); | |
1676 if (msg) { | |
1677 aimbs_putraw(&fr->data, msg, strlen(msg)); | |
1678 aimbs_put8(&fr->data, 0x00); | |
1679 } | |
1680 | |
1681 /* Unknown */ | |
1682 aimbs_put16(&fr->data, 0x0000); | |
1683 | |
1684 aim_tx_enqueue(sess, fr); | |
1685 | |
1686 return 0; | |
1687 } | |
1688 | |
1689 /* | |
1690 * Subtype 0x001b - Receive an authorization reply | |
1691 * You get this bad boy when other people respond to the authorization | |
1692 * request that you have previously sent them. | |
1693 */ | |
1694 static int receiveauthreply(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | |
1695 { | |
1696 int ret = 0; | |
1697 aim_rxcallback_t userfunc; | |
1698 fu16_t tmp; | |
1699 fu8_t reply; | |
1700 char *sn, *msg; | |
1701 | |
1702 /* Read screen name */ | |
1703 if ((tmp = aimbs_get8(bs))) | |
1704 sn = aimbs_getstr(bs, tmp); | |
1705 else | |
1706 sn = NULL; | |
1707 | |
1708 /* Read reply */ | |
1709 reply = aimbs_get8(bs); | |
1710 | |
1711 /* Read message (null terminated) */ | |
1712 if ((tmp = aimbs_get16(bs))) | |
1713 msg = aimbs_getstr(bs, tmp); | |
1714 else | |
1715 msg = NULL; | |
1716 | |
1717 /* Unknown */ | |
1718 tmp = aimbs_get16(bs); | |
1719 | |
1720 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
1721 ret = userfunc(sess, rx, sn, reply, msg); | |
1722 | |
1723 free(sn); | |
1724 free(msg); | |
1725 | |
1726 return ret; | |
1727 } | |
1728 | |
1729 /* | |
1730 * Subtype 0x001c - Receive a message telling you someone added you to their list. | |
1731 */ | |
1732 static int receiveadded(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | |
1733 { | |
1734 int ret = 0; | |
1735 aim_rxcallback_t userfunc; | |
1736 fu16_t tmp; | |
1737 char *sn; | |
1738 | |
1739 /* Read screen name */ | |
1740 if ((tmp = aimbs_get8(bs))) | |
1741 sn = aimbs_getstr(bs, tmp); | |
1742 else | |
1743 sn = NULL; | |
1744 | |
1745 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
1746 ret = userfunc(sess, rx, sn); | |
1747 | |
1748 free(sn); | |
1395 | 1749 |
1396 return ret; | 1750 return ret; |
1397 } | 1751 } |
1398 | 1752 |
1399 static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | 1753 static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
1401 | 1755 |
1402 if (snac->subtype == AIM_CB_SSI_RIGHTSINFO) | 1756 if (snac->subtype == AIM_CB_SSI_RIGHTSINFO) |
1403 return parserights(sess, mod, rx, snac, bs); | 1757 return parserights(sess, mod, rx, snac, bs); |
1404 else if (snac->subtype == AIM_CB_SSI_LIST) | 1758 else if (snac->subtype == AIM_CB_SSI_LIST) |
1405 return parsedata(sess, mod, rx, snac, bs); | 1759 return parsedata(sess, mod, rx, snac, bs); |
1760 else if (snac->subtype == AIM_CB_SSI_ADD) | |
1761 return parseadd(sess, mod, rx, snac, bs); | |
1762 else if (snac->subtype == AIM_CB_SSI_MOD) | |
1763 return parsemod(sess, mod, rx, snac, bs); | |
1764 else if (snac->subtype == AIM_CB_SSI_DEL) | |
1765 return parsedel(sess, mod, rx, snac, bs); | |
1406 else if (snac->subtype == AIM_CB_SSI_SRVACK) | 1766 else if (snac->subtype == AIM_CB_SSI_SRVACK) |
1407 return parseack(sess, mod, rx, snac, bs); | 1767 return parseack(sess, mod, rx, snac, bs); |
1408 else if (snac->subtype == AIM_CB_SSI_NOLIST) | 1768 else if (snac->subtype == AIM_CB_SSI_NOLIST) |
1409 return parsedataunchanged(sess, mod, rx, snac, bs); | 1769 return parsedataunchanged(sess, mod, rx, snac, bs); |
1770 else if (snac->subtype == AIM_CB_SSI_RECVAUTH) | |
1771 return receiveauthgrant(sess, mod, rx, snac, bs); | |
1772 else if (snac->subtype == AIM_CB_SSI_RECVAUTHREQ) | |
1773 return receiveauthrequest(sess, mod, rx, snac, bs); | |
1774 else if (snac->subtype == AIM_CB_SSI_RECVAUTHREP) | |
1775 return receiveauthreply(sess, mod, rx, snac, bs); | |
1776 else if (snac->subtype == AIM_CB_SSI_ADDED) | |
1777 return receiveadded(sess, mod, rx, snac, bs); | |
1410 | 1778 |
1411 return 0; | 1779 return 0; |
1412 } | 1780 } |
1413 | 1781 |
1414 static void ssi_shutdown(aim_session_t *sess, aim_module_t *mod) | 1782 static void ssi_shutdown(aim_session_t *sess, aim_module_t *mod) |
1420 | 1788 |
1421 faim_internal int ssi_modfirst(aim_session_t *sess, aim_module_t *mod) | 1789 faim_internal int ssi_modfirst(aim_session_t *sess, aim_module_t *mod) |
1422 { | 1790 { |
1423 | 1791 |
1424 mod->family = AIM_CB_FAM_SSI; | 1792 mod->family = AIM_CB_FAM_SSI; |
1425 mod->version = 0x0003; | 1793 mod->version = 0x0004; |
1426 mod->toolid = 0x0110; | 1794 mod->toolid = 0x0110; |
1427 mod->toolversion = 0x0629; | 1795 mod->toolversion = 0x0629; |
1428 mod->flags = 0; | 1796 mod->flags = 0; |
1429 strncpy(mod->name, "ssi", sizeof(mod->name)); | 1797 strncpy(mod->name, "ssi", sizeof(mod->name)); |
1430 mod->snachandler = snachandler; | 1798 mod->snachandler = snachandler; |