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