Mercurial > pidgin
annotate src/protocols/oscar/service.c @ 6101:e4a5085fb870
[gaim-migrate @ 6560]
This should fix some icon uploading looping.
Sean, the problem was that, when adding the md5 sum to ssi, the code was
checking if it existed by looking for an item named "0", but it was
actually adding an item named "1." So for accounts with no icon info yet,
Gaim would end up getting in a loop and spiraling into oblivion, only far
less dramatic.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Sat, 12 Jul 2003 19:08:19 +0000 |
parents | 1bebb8345bde |
children | af8ac078d4c2 |
rev | line source |
---|---|
2703 | 1 /* |
3952 | 2 * Family 0x0001 - This is a very special group. All connections support |
2703 | 3 * this group, as it does some particularly good things (like rate limiting). |
4 */ | |
5 | |
6 #define FAIM_INTERNAL | |
2734
9fc65bb80596
[gaim-migrate @ 2747]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2703
diff
changeset
|
7 #define FAIM_NEED_CONN_INTERNAL |
2703 | 8 #include <aim.h> |
9 | |
10 #include "md5.h" | |
11 | |
3952 | 12 /* Subtype 0x0002 - Client Online */ |
2703 | 13 faim_export int aim_clientready(aim_session_t *sess, aim_conn_t *conn) |
14 { | |
15 aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside; | |
16 struct snacgroup *sg; | |
17 aim_frame_t *fr; | |
18 aim_snacid_t snacid; | |
19 | |
20 if (!ins) | |
21 return -EINVAL; | |
22 | |
23 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) | |
24 return -ENOMEM; | |
25 | |
26 snacid = aim_cachesnac(sess, 0x0001, 0x0002, 0x0000, NULL, 0); | |
27 aim_putsnac(&fr->data, 0x0001, 0x0002, 0x0000, snacid); | |
28 | |
29 /* | |
30 * Send only the tool versions that the server cares about (that it | |
31 * marked as supporting in the server ready SNAC). | |
32 */ | |
33 for (sg = ins->groups; sg; sg = sg->next) { | |
34 aim_module_t *mod; | |
35 | |
36 if ((mod = aim__findmodulebygroup(sess, sg->group))) { | |
37 aimbs_put16(&fr->data, mod->family); | |
38 aimbs_put16(&fr->data, mod->version); | |
39 aimbs_put16(&fr->data, mod->toolid); | |
40 aimbs_put16(&fr->data, mod->toolversion); | |
41 } else | |
42 faimdprintf(sess, 1, "aim_clientready: server supports group 0x%04x but we don't!\n", sg->group); | |
43 } | |
44 | |
45 aim_tx_enqueue(sess, fr); | |
46 | |
47 return 0; | |
48 } | |
49 | |
50 /* | |
3952 | 51 * Subtype 0x0003 - Host Online |
2703 | 52 * |
53 * See comments in conn.c about how the group associations are supposed | |
54 * to work, and how they really work. | |
55 * | |
56 * This info probably doesn't even need to make it to the client. | |
57 * | |
58 * We don't actually call the client here. This starts off the connection | |
59 * initialization routine required by all AIM connections. The next time | |
60 * the client is called is the CONNINITDONE callback, which should be | |
61 * shortly after the rate information is acknowledged. | |
62 * | |
63 */ | |
64 static int hostonline(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | |
65 { | |
66 fu16_t *families; | |
67 int famcount; | |
68 | |
69 | |
70 if (!(families = malloc(aim_bstream_empty(bs)))) | |
71 return 0; | |
72 | |
73 for (famcount = 0; aim_bstream_empty(bs); famcount++) { | |
74 families[famcount] = aimbs_get16(bs); | |
75 aim_conn_addgroup(rx->conn, families[famcount]); | |
76 } | |
77 | |
78 free(families); | |
79 | |
80 | |
81 /* | |
82 * Next step is in the Host Versions handler. | |
83 * | |
84 * Note that we must send this before we request rates, since | |
85 * the format of the rate information depends on the versions we | |
86 * give it. | |
87 * | |
88 */ | |
89 aim_setversions(sess, rx->conn); | |
90 | |
91 return 1; | |
92 } | |
93 | |
3952 | 94 /* Subtype 0x0004 - Service request */ |
2703 | 95 faim_export int aim_reqservice(aim_session_t *sess, aim_conn_t *conn, fu16_t serviceid) |
96 { | |
97 return aim_genericreq_s(sess, conn, 0x0001, 0x0004, &serviceid); | |
98 } | |
99 | |
3952 | 100 /* Subtype 0x0005 - Redirect */ |
2703 | 101 static int redirect(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
102 { | |
2821
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
103 struct aim_redirect_data redir; |
2703 | 104 aim_rxcallback_t userfunc; |
105 aim_tlvlist_t *tlvlist; | |
2821
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
106 aim_snac_t *origsnac = NULL; |
2703 | 107 int ret = 0; |
108 | |
2821
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
109 memset(&redir, 0, sizeof(redir)); |
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
110 |
2703 | 111 tlvlist = aim_readtlvchain(bs); |
112 | |
113 if (!aim_gettlv(tlvlist, 0x000d, 1) || | |
114 !aim_gettlv(tlvlist, 0x0005, 1) || | |
115 !aim_gettlv(tlvlist, 0x0006, 1)) { | |
116 aim_freetlvchain(&tlvlist); | |
117 return 0; | |
118 } | |
119 | |
2821
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
120 redir.group = aim_gettlv16(tlvlist, 0x000d, 1); |
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
121 redir.ip = aim_gettlv_str(tlvlist, 0x0005, 1); |
4293 | 122 redir.cookielen = aim_gettlv(tlvlist, 0x0006, 1)->length; |
2821
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
123 redir.cookie = aim_gettlv_str(tlvlist, 0x0006, 1); |
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
124 |
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
125 /* Fetch original SNAC so we can get csi if needed */ |
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
126 origsnac = aim_remsnac(sess, snac->id); |
2703 | 127 |
2821
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
128 if ((redir.group == AIM_CONN_TYPE_CHAT) && origsnac) { |
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
129 struct chatsnacinfo *csi = (struct chatsnacinfo *)origsnac->data; |
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
130 |
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
131 redir.chat.exchange = csi->exchange; |
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
132 redir.chat.room = csi->name; |
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
133 redir.chat.instance = csi->instance; |
2703 | 134 } |
135 | |
136 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
2821
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
137 ret = userfunc(sess, rx, &redir); |
2703 | 138 |
2821
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
139 free((void *)redir.ip); |
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
140 free((void *)redir.cookie); |
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
141 |
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
142 if (origsnac) |
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
143 free(origsnac->data); |
9467e4ee81be
[gaim-migrate @ 2834]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2734
diff
changeset
|
144 free(origsnac); |
2703 | 145 |
146 aim_freetlvchain(&tlvlist); | |
147 | |
148 return ret; | |
149 } | |
150 | |
3952 | 151 /* Subtype 0x0006 - Request Rate Information. */ |
2703 | 152 faim_internal int aim_reqrates(aim_session_t *sess, aim_conn_t *conn) |
153 { | |
154 return aim_genericreq_n(sess, conn, 0x0001, 0x0006); | |
155 } | |
156 | |
157 /* | |
158 * OSCAR defines several 'rate classes'. Each class has seperate | |
159 * rate limiting properties (limit level, alert level, disconnect | |
160 * level, etc), and a set of SNAC family/type pairs associated with | |
161 * it. The rate classes, their limiting properties, and the definitions | |
162 * of which SNACs are belong to which class, are defined in the | |
163 * Rate Response packet at login to each host. | |
164 * | |
165 * Logically, all rate offenses within one class count against further | |
166 * offenses for other SNACs in the same class (ie, sending messages | |
167 * too fast will limit the number of user info requests you can send, | |
168 * since those two SNACs are in the same rate class). | |
169 * | |
170 * Since the rate classes are defined dynamically at login, the values | |
171 * below may change. But they seem to be fairly constant. | |
172 * | |
173 * Currently, BOS defines five rate classes, with the commonly used | |
174 * members as follows... | |
175 * | |
176 * Rate class 0x0001: | |
177 * - Everything thats not in any of the other classes | |
178 * | |
179 * Rate class 0x0002: | |
180 * - Buddy list add/remove | |
181 * - Permit list add/remove | |
182 * - Deny list add/remove | |
183 * | |
184 * Rate class 0x0003: | |
185 * - User information requests | |
186 * - Outgoing ICBMs | |
187 * | |
188 * Rate class 0x0004: | |
189 * - A few unknowns: 2/9, 2/b, and f/2 | |
190 * | |
191 * Rate class 0x0005: | |
192 * - Chat room create | |
193 * - Outgoing chat ICBMs | |
194 * | |
195 * The only other thing of note is that class 5 (chat) has slightly looser | |
196 * limiting properties than class 3 (normal messages). But thats just a | |
197 * small bit of trivia for you. | |
198 * | |
199 * The last thing that needs to be learned about the rate limiting | |
200 * system is how the actual numbers relate to the passing of time. This | |
201 * seems to be a big mystery. | |
202 * | |
203 */ | |
204 | |
205 static void rc_addclass(struct rateclass **head, struct rateclass *inrc) | |
206 { | |
207 struct rateclass *rc, *rc2; | |
208 | |
209 if (!(rc = malloc(sizeof(struct rateclass)))) | |
210 return; | |
211 | |
212 memcpy(rc, inrc, sizeof(struct rateclass)); | |
213 rc->next = NULL; | |
214 | |
215 for (rc2 = *head; rc2 && rc2->next; rc2 = rc2->next) | |
216 ; | |
217 | |
218 if (!rc2) | |
219 *head = rc; | |
220 else | |
221 rc2->next = rc; | |
222 | |
223 return; | |
224 } | |
225 | |
226 static struct rateclass *rc_findclass(struct rateclass **head, fu16_t id) | |
227 { | |
228 struct rateclass *rc; | |
229 | |
230 for (rc = *head; rc; rc = rc->next) { | |
231 if (rc->classid == id) | |
232 return rc; | |
233 } | |
234 | |
235 return NULL; | |
236 } | |
237 | |
238 static void rc_addpair(struct rateclass *rc, fu16_t group, fu16_t type) | |
239 { | |
240 struct snacpair *sp, *sp2; | |
241 | |
242 if (!(sp = malloc(sizeof(struct snacpair)))) | |
243 return; | |
244 memset(sp, 0, sizeof(struct snacpair)); | |
245 | |
246 sp->group = group; | |
247 sp->subtype = type; | |
248 sp->next = NULL; | |
249 | |
250 for (sp2 = rc->members; sp2 && sp2->next; sp2 = sp2->next) | |
251 ; | |
252 | |
253 if (!sp2) | |
254 rc->members = sp; | |
255 else | |
256 sp2->next = sp; | |
257 | |
258 return; | |
259 } | |
260 | |
3952 | 261 /* Subtype 0x0007 - Rate Parameters */ |
2703 | 262 static int rateresp(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
263 { | |
264 aim_conn_inside_t *ins = (aim_conn_inside_t *)rx->conn->inside; | |
265 fu16_t numclasses, i; | |
266 aim_rxcallback_t userfunc; | |
267 | |
268 | |
269 /* | |
270 * First are the parameters for each rate class. | |
271 */ | |
272 numclasses = aimbs_get16(bs); | |
273 for (i = 0; i < numclasses; i++) { | |
274 struct rateclass rc; | |
275 | |
276 memset(&rc, 0, sizeof(struct rateclass)); | |
277 | |
278 rc.classid = aimbs_get16(bs); | |
279 rc.windowsize = aimbs_get32(bs); | |
280 rc.clear = aimbs_get32(bs); | |
281 rc.alert = aimbs_get32(bs); | |
282 rc.limit = aimbs_get32(bs); | |
283 rc.disconnect = aimbs_get32(bs); | |
284 rc.current = aimbs_get32(bs); | |
285 rc.max = aimbs_get32(bs); | |
286 | |
287 /* | |
288 * The server will send an extra five bytes of parameters | |
289 * depending on the version we advertised in 1/17. If we | |
290 * didn't send 1/17 (evil!), then this will crash and you | |
291 * die, as it will default to the old version but we have | |
292 * the new version hardcoded here. | |
293 */ | |
294 if (mod->version >= 3) | |
295 aimbs_getrawbuf(bs, rc.unknown, sizeof(rc.unknown)); | |
296 | |
2734
9fc65bb80596
[gaim-migrate @ 2747]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2703
diff
changeset
|
297 faimdprintf(sess, 1, "--- Adding rate class %d to connection type %d: window size = %ld, clear = %ld, alert = %ld, limit = %ld, disconnect = %ld, current = %ld, max = %ld\n", rx->conn->type, rc.classid, rc.windowsize, rc.clear, rc.alert, rc.limit, rc.disconnect, rc.current, rc.max); |
9fc65bb80596
[gaim-migrate @ 2747]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2703
diff
changeset
|
298 |
2703 | 299 rc_addclass(&ins->rates, &rc); |
300 } | |
301 | |
302 /* | |
303 * Then the members of each class. | |
304 */ | |
305 for (i = 0; i < numclasses; i++) { | |
306 fu16_t classid, count; | |
307 struct rateclass *rc; | |
308 int j; | |
309 | |
310 classid = aimbs_get16(bs); | |
311 count = aimbs_get16(bs); | |
312 | |
313 rc = rc_findclass(&ins->rates, classid); | |
314 | |
315 for (j = 0; j < count; j++) { | |
316 fu16_t group, subtype; | |
317 | |
318 group = aimbs_get16(bs); | |
319 subtype = aimbs_get16(bs); | |
320 | |
321 if (rc) | |
322 rc_addpair(rc, group, subtype); | |
323 } | |
324 } | |
325 | |
326 /* | |
327 * We don't pass the rate information up to the client, as it really | |
328 * doesn't care. The information is stored in the connection, however | |
329 * so that we can do more fun stuff later (not really). | |
330 */ | |
331 | |
332 /* | |
333 * Last step in the conn init procedure is to acknowledge that we | |
334 * agree to these draconian limitations. | |
335 */ | |
336 aim_rates_addparam(sess, rx->conn); | |
337 | |
338 /* | |
339 * Finally, tell the client it's ready to go... | |
340 */ | |
341 if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE))) | |
342 userfunc(sess, rx); | |
343 | |
344 | |
345 return 1; | |
346 } | |
347 | |
3952 | 348 /* Subtype 0x0008 - Add Rate Parameter */ |
2703 | 349 faim_internal int aim_rates_addparam(aim_session_t *sess, aim_conn_t *conn) |
350 { | |
351 aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside; | |
352 aim_frame_t *fr; | |
353 aim_snacid_t snacid; | |
354 struct rateclass *rc; | |
355 | |
356 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 512))) | |
357 return -ENOMEM; | |
358 | |
359 snacid = aim_cachesnac(sess, 0x0001, 0x0008, 0x0000, NULL, 0); | |
360 aim_putsnac(&fr->data, 0x0001, 0x0008, 0x0000, snacid); | |
361 | |
362 for (rc = ins->rates; rc; rc = rc->next) | |
363 aimbs_put16(&fr->data, rc->classid); | |
364 | |
365 aim_tx_enqueue(sess, fr); | |
366 | |
367 return 0; | |
368 } | |
369 | |
3952 | 370 /* Subtype 0x0009 - Delete Rate Parameter */ |
2703 | 371 faim_internal int aim_rates_delparam(aim_session_t *sess, aim_conn_t *conn) |
372 { | |
373 aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside; | |
374 aim_frame_t *fr; | |
375 aim_snacid_t snacid; | |
376 struct rateclass *rc; | |
377 | |
378 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 512))) | |
379 return -ENOMEM; | |
380 | |
381 snacid = aim_cachesnac(sess, 0x0001, 0x0009, 0x0000, NULL, 0); | |
382 aim_putsnac(&fr->data, 0x0001, 0x0009, 0x0000, snacid); | |
383 | |
384 for (rc = ins->rates; rc; rc = rc->next) | |
385 aimbs_put16(&fr->data, rc->classid); | |
386 | |
387 aim_tx_enqueue(sess, fr); | |
388 | |
389 return 0; | |
390 } | |
391 | |
3952 | 392 /* Subtype 0x000a - Rate Change */ |
2703 | 393 static int ratechange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
394 { | |
4871 | 395 int ret = 0; |
2703 | 396 aim_rxcallback_t userfunc; |
397 fu16_t code, rateclass; | |
398 fu32_t currentavg, maxavg, windowsize, clear, alert, limit, disconnect; | |
399 | |
400 code = aimbs_get16(bs); | |
401 rateclass = aimbs_get16(bs); | |
402 | |
403 windowsize = aimbs_get32(bs); | |
404 clear = aimbs_get32(bs); | |
405 alert = aimbs_get32(bs); | |
406 limit = aimbs_get32(bs); | |
407 disconnect = aimbs_get32(bs); | |
408 currentavg = aimbs_get32(bs); | |
409 maxavg = aimbs_get32(bs); | |
410 | |
411 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
4871 | 412 ret = userfunc(sess, rx, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg); |
2703 | 413 |
4871 | 414 return ret; |
2703 | 415 } |
416 | |
417 /* | |
3952 | 418 * How Migrations work. |
2703 | 419 * |
420 * The server sends a Server Pause message, which the client should respond to | |
421 * with a Server Pause Ack, which contains the families it needs on this | |
422 * connection. The server will send a Migration Notice with an IP address, and | |
423 * then disconnect. Next the client should open the connection and send the | |
424 * cookie. Repeat the normal login process and pretend this never happened. | |
425 * | |
426 * The Server Pause contains no data. | |
427 * | |
428 */ | |
429 | |
3952 | 430 /* Subtype 0x000b - Service Pause */ |
2703 | 431 static int serverpause(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
432 { | |
4871 | 433 int ret = 0; |
2703 | 434 aim_rxcallback_t userfunc; |
435 | |
436 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
4871 | 437 ret = userfunc(sess, rx); |
2703 | 438 |
4871 | 439 return ret; |
2703 | 440 } |
441 | |
442 /* | |
3952 | 443 * Subtype 0x000c - Service Pause Acknowledgement |
2703 | 444 * |
445 * It is rather important that aim_sendpauseack() gets called for the exact | |
446 * same connection that the Server Pause callback was called for, since | |
447 * libfaim extracts the data for the SNAC from the connection structure. | |
448 * | |
449 * Of course, if you don't do that, more bad things happen than just what | |
450 * libfaim can cause. | |
451 * | |
452 */ | |
453 faim_export int aim_sendpauseack(aim_session_t *sess, aim_conn_t *conn) | |
454 { | |
455 aim_frame_t *fr; | |
456 aim_snacid_t snacid; | |
457 aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside; | |
458 struct snacgroup *sg; | |
459 | |
460 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1024))) | |
461 return -ENOMEM; | |
462 | |
463 snacid = aim_cachesnac(sess, 0x0001, 0x000c, 0x0000, NULL, 0); | |
464 aim_putsnac(&fr->data, 0x0001, 0x000c, 0x0000, snacid); | |
465 | |
466 /* | |
467 * This list should have all the groups that the original | |
468 * Host Online / Server Ready said this host supports. And | |
469 * we want them all back after the migration. | |
470 */ | |
471 for (sg = ins->groups; sg; sg = sg->next) | |
472 aimbs_put16(&fr->data, sg->group); | |
473 | |
474 aim_tx_enqueue(sess, fr); | |
475 | |
476 return 0; | |
477 } | |
478 | |
3952 | 479 /* Subtype 0x000d - Service Resume */ |
2703 | 480 static int serverresume(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
481 { | |
4871 | 482 int ret = 0; |
2703 | 483 aim_rxcallback_t userfunc; |
484 | |
485 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
4871 | 486 ret = userfunc(sess, rx); |
2703 | 487 |
4871 | 488 return ret; |
2703 | 489 } |
490 | |
3952 | 491 /* Subtype 0x000e - Request self-info */ |
2703 | 492 faim_export int aim_reqpersonalinfo(aim_session_t *sess, aim_conn_t *conn) |
493 { | |
494 return aim_genericreq_n(sess, conn, 0x0001, 0x000e); | |
495 } | |
496 | |
3952 | 497 /* Subtype 0x000f - Self User Info */ |
2703 | 498 static int selfinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
499 { | |
4871 | 500 int ret = 0; |
2703 | 501 aim_rxcallback_t userfunc; |
502 aim_userinfo_t userinfo; | |
503 | |
5836 | 504 aim_info_extract(sess, bs, &userinfo); |
2703 | 505 |
506 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
4871 | 507 ret = userfunc(sess, rx, &userinfo); |
2703 | 508 |
5836 | 509 aim_info_free(&userinfo); |
510 | |
4871 | 511 return ret; |
2703 | 512 } |
513 | |
3952 | 514 /* Subtype 0x0010 - Evil Notification */ |
2703 | 515 static int evilnotify(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
516 { | |
4871 | 517 int ret = 0; |
2703 | 518 aim_rxcallback_t userfunc; |
519 fu16_t newevil; | |
520 aim_userinfo_t userinfo; | |
521 | |
522 memset(&userinfo, 0, sizeof(aim_userinfo_t)); | |
523 | |
524 newevil = aimbs_get16(bs); | |
525 | |
526 if (aim_bstream_empty(bs)) | |
5836 | 527 aim_info_extract(sess, bs, &userinfo); |
2703 | 528 |
529 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
4871 | 530 ret = userfunc(sess, rx, newevil, &userinfo); |
2703 | 531 |
5836 | 532 aim_info_free(&userinfo); |
533 | |
4871 | 534 return ret; |
2703 | 535 } |
536 | |
537 /* | |
3952 | 538 * Subtype 0x0011 - Idle Notification |
2703 | 539 * |
540 * Should set your current idle time in seconds. Note that this should | |
541 * never be called consecutively with a non-zero idle time. That makes | |
542 * OSCAR do funny things. Instead, just set it once you go idle, and then | |
543 * call it again with zero when you're back. | |
544 * | |
545 */ | |
546 faim_export int aim_bos_setidle(aim_session_t *sess, aim_conn_t *conn, fu32_t idletime) | |
547 { | |
548 return aim_genericreq_l(sess, conn, 0x0001, 0x0011, &idletime); | |
549 } | |
550 | |
551 /* | |
3952 | 552 * Subtype 0x0012 - Service Migrate |
2703 | 553 * |
554 * This is the final SNAC sent on the original connection during a migration. | |
555 * It contains the IP and cookie used to connect to the new server, and | |
556 * optionally a list of the SNAC groups being migrated. | |
557 * | |
558 */ | |
559 static int migrate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | |
560 { | |
561 aim_rxcallback_t userfunc; | |
562 int ret = 0; | |
563 fu16_t groupcount, i; | |
564 aim_tlvlist_t *tl; | |
565 char *ip = NULL; | |
566 aim_tlv_t *cktlv; | |
567 | |
568 /* | |
569 * Apparently there's some fun stuff that can happen right here. The | |
570 * migration can actually be quite selective about what groups it | |
571 * moves to the new server. When not all the groups for a connection | |
572 * are migrated, or they are all migrated but some groups are moved | |
573 * to a different server than others, it is called a bifurcated | |
574 * migration. | |
575 * | |
576 * Let's play dumb and not support that. | |
577 * | |
578 */ | |
579 groupcount = aimbs_get16(bs); | |
580 for (i = 0; i < groupcount; i++) { | |
581 fu16_t group; | |
582 | |
583 group = aimbs_get16(bs); | |
584 | |
585 faimdprintf(sess, 0, "bifurcated migration unsupported -- group 0x%04x\n", group); | |
586 } | |
587 | |
588 tl = aim_readtlvchain(bs); | |
589 | |
590 if (aim_gettlv(tl, 0x0005, 1)) | |
591 ip = aim_gettlv_str(tl, 0x0005, 1); | |
592 | |
593 cktlv = aim_gettlv(tl, 0x0006, 1); | |
594 | |
595 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
596 ret = userfunc(sess, rx, ip, cktlv ? cktlv->value : NULL); | |
597 | |
598 aim_freetlvchain(&tl); | |
599 free(ip); | |
600 | |
601 return ret; | |
602 } | |
603 | |
3952 | 604 /* Subtype 0x0013 - Message of the Day */ |
2703 | 605 static int motd(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
606 { | |
607 aim_rxcallback_t userfunc; | |
608 char *msg = NULL; | |
609 int ret = 0; | |
610 aim_tlvlist_t *tlvlist; | |
611 fu16_t id; | |
612 | |
613 /* | |
614 * Code. | |
615 * | |
616 * Valid values: | |
617 * 1 Mandatory upgrade | |
618 * 2 Advisory upgrade | |
619 * 3 System bulletin | |
620 * 4 Nothing's wrong ("top o the world" -- normal) | |
621 * 5 Lets-break-something. | |
622 * | |
623 */ | |
624 id = aimbs_get16(bs); | |
625 | |
626 /* | |
627 * TLVs follow | |
628 */ | |
629 tlvlist = aim_readtlvchain(bs); | |
630 | |
631 msg = aim_gettlv_str(tlvlist, 0x000b, 1); | |
632 | |
633 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
634 ret = userfunc(sess, rx, id, msg); | |
635 | |
636 free(msg); | |
637 | |
638 aim_freetlvchain(&tlvlist); | |
639 | |
640 return ret; | |
641 } | |
642 | |
643 /* | |
3952 | 644 * Subtype 0x0014 - Set privacy flags |
2703 | 645 * |
646 * Normally 0x03. | |
647 * | |
648 * Bit 1: Allows other AIM users to see how long you've been idle. | |
649 * Bit 2: Allows other AIM users to see how long you've been a member. | |
650 * | |
651 */ | |
652 faim_export int aim_bos_setprivacyflags(aim_session_t *sess, aim_conn_t *conn, fu32_t flags) | |
653 { | |
654 return aim_genericreq_l(sess, conn, 0x0001, 0x0014, &flags); | |
655 } | |
656 | |
657 /* | |
3952 | 658 * Subtype 0x0016 - No-op |
2703 | 659 * |
660 * WinAIM sends these every 4min or so to keep the connection alive. Its not | |
3952 | 661 * really necessary. |
2703 | 662 * |
663 */ | |
664 faim_export int aim_nop(aim_session_t *sess, aim_conn_t *conn) | |
665 { | |
666 return aim_genericreq_n(sess, conn, 0x0001, 0x0016); | |
667 } | |
668 | |
669 /* | |
3952 | 670 * Subtype 0x0017 - Set client versions |
2703 | 671 * |
672 * If you've seen the clientonline/clientready SNAC you're probably | |
673 * wondering what the point of this one is. And that point seems to be | |
674 * that the versions in the client online SNAC are sent too late for the | |
675 * server to be able to use them to change the protocol for the earlier | |
676 * login packets (client versions are sent right after Host Online is | |
677 * received, but client online versions aren't sent until quite a bit later). | |
678 * We can see them already making use of this by changing the format of | |
679 * the rate information based on what version of group 1 we advertise here. | |
680 * | |
681 */ | |
682 faim_internal int aim_setversions(aim_session_t *sess, aim_conn_t *conn) | |
683 { | |
684 aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside; | |
685 struct snacgroup *sg; | |
686 aim_frame_t *fr; | |
687 aim_snacid_t snacid; | |
688 | |
689 if (!ins) | |
690 return -EINVAL; | |
691 | |
692 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) | |
693 return -ENOMEM; | |
694 | |
695 snacid = aim_cachesnac(sess, 0x0001, 0x0017, 0x0000, NULL, 0); | |
696 aim_putsnac(&fr->data, 0x0001, 0x0017, 0x0000, snacid); | |
697 | |
698 /* | |
699 * Send only the versions that the server cares about (that it | |
700 * marked as supporting in the server ready SNAC). | |
701 */ | |
702 for (sg = ins->groups; sg; sg = sg->next) { | |
703 aim_module_t *mod; | |
704 | |
705 if ((mod = aim__findmodulebygroup(sess, sg->group))) { | |
706 aimbs_put16(&fr->data, mod->family); | |
707 aimbs_put16(&fr->data, mod->version); | |
708 } else | |
709 faimdprintf(sess, 1, "aim_setversions: server supports group 0x%04x but we don't!\n", sg->group); | |
710 } | |
711 | |
712 aim_tx_enqueue(sess, fr); | |
713 | |
714 return 0; | |
715 } | |
716 | |
3952 | 717 /* Subtype 0x0018 - Host versions */ |
2703 | 718 static int hostversions(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
719 { | |
720 int vercount; | |
721 fu8_t *versions; | |
722 | |
723 /* This is frivolous. (Thank you SmarterChild.) */ | |
724 vercount = aim_bstream_empty(bs)/4; | |
725 versions = aimbs_getraw(bs, aim_bstream_empty(bs)); | |
726 free(versions); | |
727 | |
728 /* | |
729 * Now request rates. | |
730 */ | |
731 aim_reqrates(sess, rx->conn); | |
732 | |
733 return 1; | |
734 } | |
735 | |
736 /* | |
5917 | 737 * Subtype 0x001e - Extended Status |
2703 | 738 * |
5917 | 739 * Sets your ICQ status (available, away, do not disturb, etc.) |
2703 | 740 * |
4342 | 741 * These are the same TLVs seen in user info. You can |
742 * also set 0x0008 and 0x000c. | |
2703 | 743 */ |
4901 | 744 faim_export int aim_setextstatus(aim_session_t *sess, fu32_t status) |
2703 | 745 { |
4901 | 746 aim_conn_t *conn; |
2703 | 747 aim_frame_t *fr; |
748 aim_snacid_t snacid; | |
749 aim_tlvlist_t *tl = NULL; | |
750 fu32_t data; | |
751 | |
4901 | 752 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) |
753 return -EINVAL; | |
754 | |
4342 | 755 data = AIM_ICQ_STATE_HIDEIP | AIM_ICQ_STATE_WEBAWARE | status; /* yay for error checking ;^) */ |
2703 | 756 |
757 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 8))) | |
758 return -ENOMEM; | |
759 | |
760 snacid = aim_cachesnac(sess, 0x0001, 0x001e, 0x0000, NULL, 0); | |
761 aim_putsnac(&fr->data, 0x0001, 0x001e, 0x0000, snacid); | |
762 | |
763 aim_addtlvtochain32(&tl, 0x0006, data); | |
764 aim_writetlvchain(&fr->data, &tl); | |
765 aim_freetlvchain(&tl); | |
766 | |
767 aim_tx_enqueue(sess, fr); | |
768 | |
769 return 0; | |
770 } | |
771 | |
5917 | 772 /* |
773 * Subtype 0x001e - Extended Status. | |
774 * | |
775 * Sets your "available" message. This is currently only supported by iChat | |
776 * and Gaim. | |
777 * | |
778 * These are the same TLVs seen in user info. You can | |
779 * also set 0x0008 and 0x000c. | |
780 */ | |
781 faim_export int aim_srv_setavailmsg(aim_session_t *sess, char *msg) | |
782 { | |
783 aim_conn_t *conn; | |
784 aim_frame_t *fr; | |
785 aim_snacid_t snacid; | |
786 | |
787 if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0001))) | |
788 return -EINVAL; | |
789 | |
790 if (msg) { | |
5948 | 791 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + strlen(msg) + 8))) |
5917 | 792 return -ENOMEM; |
793 | |
794 snacid = aim_cachesnac(sess, 0x0001, 0x001e, 0x0000, NULL, 0); | |
795 aim_putsnac(&fr->data, 0x0001, 0x001e, 0x0000, snacid); | |
796 | |
797 aimbs_put16(&fr->data, 0x001d); | |
5948 | 798 aimbs_put16(&fr->data, strlen(msg)+8); |
799 aimbs_put16(&fr->data, 0x0002); | |
800 aimbs_put8(&fr->data, 0x04); | |
801 aimbs_put8(&fr->data, strlen(msg)+4); | |
802 aimbs_put16(&fr->data, strlen(msg)); | |
5917 | 803 aimbs_putraw(&fr->data, msg, strlen(msg)); |
804 aimbs_put16(&fr->data, 0x0000); | |
805 } else { | |
806 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + 8))) | |
807 return -ENOMEM; | |
808 | |
809 snacid = aim_cachesnac(sess, 0x0001, 0x001e, 0x0000, NULL, 0); | |
810 aim_putsnac(&fr->data, 0x0001, 0x001e, 0x0000, snacid); | |
811 | |
812 aimbs_put16(&fr->data, 0x001d); | |
813 aimbs_put16(&fr->data, 0x0008); | |
814 aimbs_put16(&fr->data, 0x0002); | |
815 aimbs_put16(&fr->data, 0x0404); | |
816 aimbs_put16(&fr->data, 0x0000); | |
817 aimbs_put16(&fr->data, 0x0000); | |
818 } | |
819 | |
820 aim_tx_enqueue(sess, fr); | |
821 | |
822 return 0; | |
823 } | |
824 | |
2703 | 825 /* |
826 * Starting this past week (26 Mar 2001, say), AOL has started sending | |
827 * this nice little extra SNAC. AFAIK, it has never been used until now. | |
828 * | |
829 * The request contains eight bytes. The first four are an offset, the | |
830 * second four are a length. | |
831 * | |
832 * The offset is an offset into aim.exe when it is mapped during execution | |
833 * on Win32. So far, AOL has only been requesting bytes in static regions | |
834 * of memory. (I won't put it past them to start requesting data in | |
835 * less static regions -- regions that are initialized at run time, but still | |
836 * before the client recieves this request.) | |
837 * | |
838 * When the client recieves the request, it adds it to the current ds | |
839 * (0x00400000) and dereferences it, copying the data into a buffer which | |
840 * it then runs directly through the MD5 hasher. The 16 byte output of | |
841 * the hash is then sent back to the server. | |
842 * | |
843 * If the client does not send any data back, or the data does not match | |
844 * the data that the specific client should have, the client will get the | |
845 * following message from "AOL Instant Messenger": | |
846 * "You have been disconnected from the AOL Instant Message Service (SM) | |
847 * for accessing the AOL network using unauthorized software. You can | |
848 * download a FREE, fully featured, and authorized client, here | |
849 * http://www.aol.com/aim/download2.html" | |
850 * The connection is then closed, recieving disconnect code 1, URL | |
851 * http://www.aim.aol.com/errors/USER_LOGGED_OFF_NEW_LOGIN.html. | |
852 * | |
853 * Note, however, that numerous inconsistencies can cause the above error, | |
854 * not just sending back a bad hash. Do not immediatly suspect this code | |
855 * if you get disconnected. AOL and the open/free software community have | |
856 * played this game for a couple years now, generating the above message | |
857 * on numerous ocassions. | |
858 * | |
859 * Anyway, neener. We win again. | |
860 * | |
861 */ | |
3952 | 862 /* Subtype 0x001f - Client verification */ |
2703 | 863 static int memrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
864 { | |
4871 | 865 int ret = 0; |
2703 | 866 aim_rxcallback_t userfunc; |
867 fu32_t offset, len; | |
868 aim_tlvlist_t *list; | |
869 char *modname; | |
870 | |
871 offset = aimbs_get32(bs); | |
872 len = aimbs_get32(bs); | |
873 list = aim_readtlvchain(bs); | |
874 | |
875 modname = aim_gettlv_str(list, 0x0001, 1); | |
876 | |
877 faimdprintf(sess, 1, "data at 0x%08lx (%d bytes) of requested\n", offset, len, modname ? modname : "aim.exe"); | |
878 | |
879 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
4871 | 880 ret = userfunc(sess, rx, offset, len, modname); |
2703 | 881 |
882 free(modname); | |
883 aim_freetlvchain(&list); | |
884 | |
4871 | 885 return ret; |
2703 | 886 } |
887 | |
888 #if 0 | |
889 static void dumpbox(aim_session_t *sess, unsigned char *buf, int len) | |
890 { | |
891 int i; | |
892 | |
893 if (!sess || !buf || !len) | |
894 return; | |
895 | |
896 faimdprintf(sess, 1, "\nDump of %d bytes at %p:", len, buf); | |
897 | |
898 for (i = 0; i < len; i++) { | |
899 if ((i % 8) == 0) | |
900 faimdprintf(sess, 1, "\n\t"); | |
901 | |
902 faimdprintf(sess, 1, "0x%2x ", buf[i]); | |
903 } | |
904 | |
905 faimdprintf(sess, 1, "\n\n"); | |
906 | |
907 return; | |
908 } | |
909 #endif | |
910 | |
3952 | 911 /* Subtype 0x0020 - Client verification reply */ |
2703 | 912 faim_export int aim_sendmemblock(aim_session_t *sess, aim_conn_t *conn, fu32_t offset, fu32_t len, const fu8_t *buf, fu8_t flag) |
913 { | |
914 aim_frame_t *fr; | |
915 aim_snacid_t snacid; | |
916 | |
917 if (!sess || !conn) | |
918 return -EINVAL; | |
919 | |
920 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+16))) | |
921 return -ENOMEM; | |
922 | |
923 snacid = aim_cachesnac(sess, 0x0001, 0x0020, 0x0000, NULL, 0); | |
924 | |
925 aim_putsnac(&fr->data, 0x0001, 0x0020, 0x0000, snacid); | |
926 aimbs_put16(&fr->data, 0x0010); /* md5 is always 16 bytes */ | |
927 | |
928 if ((flag == AIM_SENDMEMBLOCK_FLAG_ISHASH) && buf && (len == 0x10)) { /* we're getting a hash */ | |
929 | |
930 aimbs_putraw(&fr->data, buf, 0x10); | |
931 | |
932 } else if (buf && (len > 0)) { /* use input buffer */ | |
933 md5_state_t state; | |
934 md5_byte_t digest[0x10]; | |
935 | |
936 md5_init(&state); | |
937 md5_append(&state, (const md5_byte_t *)buf, len); | |
938 md5_finish(&state, digest); | |
939 | |
940 aimbs_putraw(&fr->data, (fu8_t *)digest, 0x10); | |
941 | |
942 } else if (len == 0) { /* no length, just hash NULL (buf is optional) */ | |
943 md5_state_t state; | |
944 fu8_t nil = '\0'; | |
945 md5_byte_t digest[0x10]; | |
946 | |
947 /* | |
948 * These MD5 routines are stupid in that you have to have | |
949 * at least one append. So thats why this doesn't look | |
950 * real logical. | |
951 */ | |
952 md5_init(&state); | |
953 md5_append(&state, (const md5_byte_t *)&nil, 0); | |
954 md5_finish(&state, digest); | |
955 | |
956 aimbs_putraw(&fr->data, (fu8_t *)digest, 0x10); | |
957 | |
958 } else { | |
959 | |
960 /* | |
961 * This data is correct for AIM 3.5.1670. | |
962 * | |
963 * Using these blocks is as close to "legal" as you can get | |
964 * without using an AIM binary. | |
965 * | |
966 */ | |
967 if ((offset == 0x03ffffff) && (len == 0x03ffffff)) { | |
968 | |
969 #if 1 /* with "AnrbnrAqhfzcd" */ | |
970 aimbs_put32(&fr->data, 0x44a95d26); | |
971 aimbs_put32(&fr->data, 0xd2490423); | |
972 aimbs_put32(&fr->data, 0x93b8821f); | |
973 aimbs_put32(&fr->data, 0x51c54b01); | |
974 #else /* no filename */ | |
975 aimbs_put32(&fr->data, 0x1df8cbae); | |
976 aimbs_put32(&fr->data, 0x5523b839); | |
977 aimbs_put32(&fr->data, 0xa0e10db3); | |
978 aimbs_put32(&fr->data, 0xa46d3b39); | |
979 #endif | |
980 | |
981 } else if ((offset == 0x00001000) && (len == 0x00000000)) { | |
982 | |
983 aimbs_put32(&fr->data, 0xd41d8cd9); | |
984 aimbs_put32(&fr->data, 0x8f00b204); | |
985 aimbs_put32(&fr->data, 0xe9800998); | |
986 aimbs_put32(&fr->data, 0xecf8427e); | |
987 | |
988 } else | |
989 faimdprintf(sess, 0, "sendmemblock: WARNING: unknown hash request\n"); | |
990 | |
991 } | |
992 | |
993 aim_tx_enqueue(sess, fr); | |
994 | |
995 return 0; | |
996 } | |
997 | |
5836 | 998 /* |
999 * Subtype 0x0021 - Receive our extended status | |
1000 * | |
5892 | 1001 * This is used for iChat's "available" messages, and maybe ICQ extended |
1002 * status messages? It's also used to tell the client whether or not it | |
1003 * needs to upload an SSI buddy icon... who engineers this stuff, anyway? | |
5836 | 1004 */ |
1005 static int aim_parse_extstatus(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | |
1006 { | |
5892 | 1007 int ret = 0; |
5836 | 1008 aim_rxcallback_t userfunc; |
5837 | 1009 fu16_t type; |
5892 | 1010 fu8_t flags, length; |
5836 | 1011 |
5842 | 1012 type = aimbs_get16(bs); |
5892 | 1013 flags = aimbs_get8(bs); |
1014 length = aimbs_get8(bs); | |
1015 | |
5842 | 1016 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) { |
1017 switch (type) { | |
5892 | 1018 case 0x0000: |
6101 | 1019 case 0x0001: { /* buddy icon checksum */ |
1020 /* not sure what the difference between 1 and 0 is */ | |
5892 | 1021 fu8_t *md5 = aimbs_getraw(bs, length); |
1022 ret = userfunc(sess, rx, type, flags, length, md5); | |
5842 | 1023 free(md5); |
5892 | 1024 } break; |
6101 | 1025 case 0x0002: { /* available message */ |
5892 | 1026 /* there is a second length that is just for the message */ |
1027 char *msg = aimbs_getstr(bs, aimbs_get16(bs)); | |
5842 | 1028 ret = userfunc(sess, rx, msg); |
1029 free(msg); | |
5892 | 1030 } break; |
5842 | 1031 } |
5871 | 1032 } |
5917 | 1033 |
1034 return ret; | |
5836 | 1035 } |
1036 | |
2703 | 1037 static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
1038 { | |
1039 | |
1040 if (snac->subtype == 0x0003) | |
1041 return hostonline(sess, mod, rx, snac, bs); | |
1042 else if (snac->subtype == 0x0005) | |
1043 return redirect(sess, mod, rx, snac, bs); | |
1044 else if (snac->subtype == 0x0007) | |
1045 return rateresp(sess, mod, rx, snac, bs); | |
1046 else if (snac->subtype == 0x000a) | |
1047 return ratechange(sess, mod, rx, snac, bs); | |
1048 else if (snac->subtype == 0x000b) | |
1049 return serverpause(sess, mod, rx, snac, bs); | |
1050 else if (snac->subtype == 0x000d) | |
1051 return serverresume(sess, mod, rx, snac, bs); | |
1052 else if (snac->subtype == 0x000f) | |
1053 return selfinfo(sess, mod, rx, snac, bs); | |
1054 else if (snac->subtype == 0x0010) | |
1055 return evilnotify(sess, mod, rx, snac, bs); | |
1056 else if (snac->subtype == 0x0012) | |
1057 return migrate(sess, mod, rx, snac, bs); | |
1058 else if (snac->subtype == 0x0013) | |
1059 return motd(sess, mod, rx, snac, bs); | |
1060 else if (snac->subtype == 0x0018) | |
1061 return hostversions(sess, mod, rx, snac, bs); | |
1062 else if (snac->subtype == 0x001f) | |
1063 return memrequest(sess, mod, rx, snac, bs); | |
5836 | 1064 else if (snac->subtype == 0x0021) |
1065 return aim_parse_extstatus(sess, mod, rx, snac, bs); | |
2703 | 1066 |
1067 return 0; | |
1068 } | |
1069 | |
1070 faim_internal int general_modfirst(aim_session_t *sess, aim_module_t *mod) | |
1071 { | |
1072 | |
1073 mod->family = 0x0001; | |
1074 mod->version = 0x0003; | |
1075 mod->toolid = 0x0110; | |
4071 | 1076 mod->toolversion = 0x0629; |
2703 | 1077 mod->flags = 0; |
1078 strncpy(mod->name, "general", sizeof(mod->name)); | |
1079 mod->snachandler = snachandler; | |
1080 | |
1081 return 0; | |
1082 } |