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