Mercurial > pidgin.yaz
annotate src/protocols/oscar/service.c @ 4829:e7e45cee4265
[gaim-migrate @ 5154]
This does 3 things:
1) Removes the "Get Capabilities" option which I re-added a few hours
ago. We decided that it's pointless, since caps are in the tooltips.
It also needlessly complicates things.
2) Adds an "unable to add this buddy because you are over the limit"
message that is currently commented out. We have some sort of a
message like this right now, but it's less good. If you really want
to know why, ask me.
3) Adds a workaround for the bug where some users tooltips do not
show capabilities sometimes. This is really an AIM bug, honest.
Gaim is getting status updates for people that don't contain their
capabilities. I guess it's probably intentional. I imagine it
saves a bit o' bandwidth, since each capability is 16 bytes.
[Insert humorous phrase or catch song lyric here]
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Wed, 19 Mar 2003 02:52:42 +0000 |
parents | 051265d35a36 |
children | 0b64f386a7b8 |
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 { | |
395 aim_rxcallback_t userfunc; | |
396 fu16_t code, rateclass; | |
397 fu32_t currentavg, maxavg, windowsize, clear, alert, limit, disconnect; | |
398 | |
399 code = aimbs_get16(bs); | |
400 rateclass = aimbs_get16(bs); | |
401 | |
402 windowsize = aimbs_get32(bs); | |
403 clear = aimbs_get32(bs); | |
404 alert = aimbs_get32(bs); | |
405 limit = aimbs_get32(bs); | |
406 disconnect = aimbs_get32(bs); | |
407 currentavg = aimbs_get32(bs); | |
408 maxavg = aimbs_get32(bs); | |
409 | |
410 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
411 return userfunc(sess, rx, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg); | |
412 | |
413 return 0; | |
414 } | |
415 | |
416 /* | |
3952 | 417 * How Migrations work. |
2703 | 418 * |
419 * The server sends a Server Pause message, which the client should respond to | |
420 * with a Server Pause Ack, which contains the families it needs on this | |
421 * connection. The server will send a Migration Notice with an IP address, and | |
422 * then disconnect. Next the client should open the connection and send the | |
423 * cookie. Repeat the normal login process and pretend this never happened. | |
424 * | |
425 * The Server Pause contains no data. | |
426 * | |
427 */ | |
428 | |
3952 | 429 /* Subtype 0x000b - Service Pause */ |
2703 | 430 static int serverpause(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
431 { | |
432 aim_rxcallback_t userfunc; | |
433 | |
434 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
435 return userfunc(sess, rx); | |
436 | |
437 return 0; | |
438 } | |
439 | |
440 /* | |
3952 | 441 * Subtype 0x000c - Service Pause Acknowledgement |
2703 | 442 * |
443 * It is rather important that aim_sendpauseack() gets called for the exact | |
444 * same connection that the Server Pause callback was called for, since | |
445 * libfaim extracts the data for the SNAC from the connection structure. | |
446 * | |
447 * Of course, if you don't do that, more bad things happen than just what | |
448 * libfaim can cause. | |
449 * | |
450 */ | |
451 faim_export int aim_sendpauseack(aim_session_t *sess, aim_conn_t *conn) | |
452 { | |
453 aim_frame_t *fr; | |
454 aim_snacid_t snacid; | |
455 aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside; | |
456 struct snacgroup *sg; | |
457 | |
458 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1024))) | |
459 return -ENOMEM; | |
460 | |
461 snacid = aim_cachesnac(sess, 0x0001, 0x000c, 0x0000, NULL, 0); | |
462 aim_putsnac(&fr->data, 0x0001, 0x000c, 0x0000, snacid); | |
463 | |
464 /* | |
465 * This list should have all the groups that the original | |
466 * Host Online / Server Ready said this host supports. And | |
467 * we want them all back after the migration. | |
468 */ | |
469 for (sg = ins->groups; sg; sg = sg->next) | |
470 aimbs_put16(&fr->data, sg->group); | |
471 | |
472 aim_tx_enqueue(sess, fr); | |
473 | |
474 return 0; | |
475 } | |
476 | |
3952 | 477 /* Subtype 0x000d - Service Resume */ |
2703 | 478 static int serverresume(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
479 { | |
480 aim_rxcallback_t userfunc; | |
481 | |
482 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
483 return userfunc(sess, rx); | |
484 | |
485 return 0; | |
486 } | |
487 | |
3952 | 488 /* Subtype 0x000e - Request self-info */ |
2703 | 489 faim_export int aim_reqpersonalinfo(aim_session_t *sess, aim_conn_t *conn) |
490 { | |
491 return aim_genericreq_n(sess, conn, 0x0001, 0x000e); | |
492 } | |
493 | |
3952 | 494 /* Subtype 0x000f - Self User Info */ |
2703 | 495 static int selfinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
496 { | |
497 aim_rxcallback_t userfunc; | |
498 aim_userinfo_t userinfo; | |
499 | |
500 aim_extractuserinfo(sess, bs, &userinfo); | |
501 | |
502 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
503 return userfunc(sess, rx, &userinfo); | |
504 | |
505 return 0; | |
506 } | |
507 | |
3952 | 508 /* Subtype 0x0010 - Evil Notification */ |
2703 | 509 static int evilnotify(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
510 { | |
511 aim_rxcallback_t userfunc; | |
512 fu16_t newevil; | |
513 aim_userinfo_t userinfo; | |
514 | |
515 memset(&userinfo, 0, sizeof(aim_userinfo_t)); | |
516 | |
517 newevil = aimbs_get16(bs); | |
518 | |
519 if (aim_bstream_empty(bs)) | |
520 aim_extractuserinfo(sess, bs, &userinfo); | |
521 | |
522 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
523 return userfunc(sess, rx, newevil, &userinfo); | |
524 | |
525 return 0; | |
526 } | |
527 | |
528 /* | |
3952 | 529 * Subtype 0x0011 - Idle Notification |
2703 | 530 * |
531 * Should set your current idle time in seconds. Note that this should | |
532 * never be called consecutively with a non-zero idle time. That makes | |
533 * OSCAR do funny things. Instead, just set it once you go idle, and then | |
534 * call it again with zero when you're back. | |
535 * | |
536 */ | |
537 faim_export int aim_bos_setidle(aim_session_t *sess, aim_conn_t *conn, fu32_t idletime) | |
538 { | |
539 return aim_genericreq_l(sess, conn, 0x0001, 0x0011, &idletime); | |
540 } | |
541 | |
542 /* | |
3952 | 543 * Subtype 0x0012 - Service Migrate |
2703 | 544 * |
545 * This is the final SNAC sent on the original connection during a migration. | |
546 * It contains the IP and cookie used to connect to the new server, and | |
547 * optionally a list of the SNAC groups being migrated. | |
548 * | |
549 */ | |
550 static int migrate(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | |
551 { | |
552 aim_rxcallback_t userfunc; | |
553 int ret = 0; | |
554 fu16_t groupcount, i; | |
555 aim_tlvlist_t *tl; | |
556 char *ip = NULL; | |
557 aim_tlv_t *cktlv; | |
558 | |
559 /* | |
560 * Apparently there's some fun stuff that can happen right here. The | |
561 * migration can actually be quite selective about what groups it | |
562 * moves to the new server. When not all the groups for a connection | |
563 * are migrated, or they are all migrated but some groups are moved | |
564 * to a different server than others, it is called a bifurcated | |
565 * migration. | |
566 * | |
567 * Let's play dumb and not support that. | |
568 * | |
569 */ | |
570 groupcount = aimbs_get16(bs); | |
571 for (i = 0; i < groupcount; i++) { | |
572 fu16_t group; | |
573 | |
574 group = aimbs_get16(bs); | |
575 | |
576 faimdprintf(sess, 0, "bifurcated migration unsupported -- group 0x%04x\n", group); | |
577 } | |
578 | |
579 tl = aim_readtlvchain(bs); | |
580 | |
581 if (aim_gettlv(tl, 0x0005, 1)) | |
582 ip = aim_gettlv_str(tl, 0x0005, 1); | |
583 | |
584 cktlv = aim_gettlv(tl, 0x0006, 1); | |
585 | |
586 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
587 ret = userfunc(sess, rx, ip, cktlv ? cktlv->value : NULL); | |
588 | |
589 aim_freetlvchain(&tl); | |
590 free(ip); | |
591 | |
592 return ret; | |
593 } | |
594 | |
3952 | 595 /* Subtype 0x0013 - Message of the Day */ |
2703 | 596 static int motd(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
597 { | |
598 aim_rxcallback_t userfunc; | |
599 char *msg = NULL; | |
600 int ret = 0; | |
601 aim_tlvlist_t *tlvlist; | |
602 fu16_t id; | |
603 | |
604 /* | |
605 * Code. | |
606 * | |
607 * Valid values: | |
608 * 1 Mandatory upgrade | |
609 * 2 Advisory upgrade | |
610 * 3 System bulletin | |
611 * 4 Nothing's wrong ("top o the world" -- normal) | |
612 * 5 Lets-break-something. | |
613 * | |
614 */ | |
615 id = aimbs_get16(bs); | |
616 | |
617 /* | |
618 * TLVs follow | |
619 */ | |
620 tlvlist = aim_readtlvchain(bs); | |
621 | |
622 msg = aim_gettlv_str(tlvlist, 0x000b, 1); | |
623 | |
624 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
625 ret = userfunc(sess, rx, id, msg); | |
626 | |
627 free(msg); | |
628 | |
629 aim_freetlvchain(&tlvlist); | |
630 | |
631 return ret; | |
632 } | |
633 | |
634 /* | |
3952 | 635 * Subtype 0x0014 - Set privacy flags |
2703 | 636 * |
637 * Normally 0x03. | |
638 * | |
639 * Bit 1: Allows other AIM users to see how long you've been idle. | |
640 * Bit 2: Allows other AIM users to see how long you've been a member. | |
641 * | |
642 */ | |
643 faim_export int aim_bos_setprivacyflags(aim_session_t *sess, aim_conn_t *conn, fu32_t flags) | |
644 { | |
645 return aim_genericreq_l(sess, conn, 0x0001, 0x0014, &flags); | |
646 } | |
647 | |
648 /* | |
3952 | 649 * Subtype 0x0016 - No-op |
2703 | 650 * |
651 * WinAIM sends these every 4min or so to keep the connection alive. Its not | |
3952 | 652 * really necessary. |
2703 | 653 * |
654 */ | |
655 faim_export int aim_nop(aim_session_t *sess, aim_conn_t *conn) | |
656 { | |
657 return aim_genericreq_n(sess, conn, 0x0001, 0x0016); | |
658 } | |
659 | |
660 /* | |
3952 | 661 * Subtype 0x0017 - Set client versions |
2703 | 662 * |
663 * If you've seen the clientonline/clientready SNAC you're probably | |
664 * wondering what the point of this one is. And that point seems to be | |
665 * that the versions in the client online SNAC are sent too late for the | |
666 * server to be able to use them to change the protocol for the earlier | |
667 * login packets (client versions are sent right after Host Online is | |
668 * received, but client online versions aren't sent until quite a bit later). | |
669 * We can see them already making use of this by changing the format of | |
670 * the rate information based on what version of group 1 we advertise here. | |
671 * | |
672 */ | |
673 faim_internal int aim_setversions(aim_session_t *sess, aim_conn_t *conn) | |
674 { | |
675 aim_conn_inside_t *ins = (aim_conn_inside_t *)conn->inside; | |
676 struct snacgroup *sg; | |
677 aim_frame_t *fr; | |
678 aim_snacid_t snacid; | |
679 | |
680 if (!ins) | |
681 return -EINVAL; | |
682 | |
683 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) | |
684 return -ENOMEM; | |
685 | |
686 snacid = aim_cachesnac(sess, 0x0001, 0x0017, 0x0000, NULL, 0); | |
687 aim_putsnac(&fr->data, 0x0001, 0x0017, 0x0000, snacid); | |
688 | |
689 /* | |
690 * Send only the versions that the server cares about (that it | |
691 * marked as supporting in the server ready SNAC). | |
692 */ | |
693 for (sg = ins->groups; sg; sg = sg->next) { | |
694 aim_module_t *mod; | |
695 | |
696 if ((mod = aim__findmodulebygroup(sess, sg->group))) { | |
697 aimbs_put16(&fr->data, mod->family); | |
698 aimbs_put16(&fr->data, mod->version); | |
699 } else | |
700 faimdprintf(sess, 1, "aim_setversions: server supports group 0x%04x but we don't!\n", sg->group); | |
701 } | |
702 | |
703 aim_tx_enqueue(sess, fr); | |
704 | |
705 return 0; | |
706 } | |
707 | |
3952 | 708 /* Subtype 0x0018 - Host versions */ |
2703 | 709 static int hostversions(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
710 { | |
711 int vercount; | |
712 fu8_t *versions; | |
713 | |
714 /* This is frivolous. (Thank you SmarterChild.) */ | |
715 vercount = aim_bstream_empty(bs)/4; | |
716 versions = aimbs_getraw(bs, aim_bstream_empty(bs)); | |
717 free(versions); | |
718 | |
719 /* | |
720 * Now request rates. | |
721 */ | |
722 aim_reqrates(sess, rx->conn); | |
723 | |
724 return 1; | |
725 } | |
726 | |
727 /* | |
3952 | 728 * Subtype 0x001e - Set Extended Status |
2703 | 729 * |
730 * Currently only works if using ICQ. | |
731 * | |
4342 | 732 * These are the same TLVs seen in user info. You can |
733 * also set 0x0008 and 0x000c. | |
2703 | 734 */ |
2866
6d62d4520460
[gaim-migrate @ 2879]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2821
diff
changeset
|
735 faim_export int aim_setextstatus(aim_session_t *sess, aim_conn_t *conn, fu32_t status) |
2703 | 736 { |
737 aim_frame_t *fr; | |
738 aim_snacid_t snacid; | |
739 aim_tlvlist_t *tl = NULL; | |
740 fu32_t data; | |
741 | |
4342 | 742 data = AIM_ICQ_STATE_HIDEIP | AIM_ICQ_STATE_WEBAWARE | status; /* yay for error checking ;^) */ |
2703 | 743 |
744 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 8))) | |
745 return -ENOMEM; | |
746 | |
747 snacid = aim_cachesnac(sess, 0x0001, 0x001e, 0x0000, NULL, 0); | |
748 aim_putsnac(&fr->data, 0x0001, 0x001e, 0x0000, snacid); | |
749 | |
750 aim_addtlvtochain32(&tl, 0x0006, data); | |
751 aim_writetlvchain(&fr->data, &tl); | |
752 aim_freetlvchain(&tl); | |
753 | |
754 aim_tx_enqueue(sess, fr); | |
755 | |
756 return 0; | |
757 } | |
758 | |
759 /* | |
760 * Starting this past week (26 Mar 2001, say), AOL has started sending | |
761 * this nice little extra SNAC. AFAIK, it has never been used until now. | |
762 * | |
763 * The request contains eight bytes. The first four are an offset, the | |
764 * second four are a length. | |
765 * | |
766 * The offset is an offset into aim.exe when it is mapped during execution | |
767 * on Win32. So far, AOL has only been requesting bytes in static regions | |
768 * of memory. (I won't put it past them to start requesting data in | |
769 * less static regions -- regions that are initialized at run time, but still | |
770 * before the client recieves this request.) | |
771 * | |
772 * When the client recieves the request, it adds it to the current ds | |
773 * (0x00400000) and dereferences it, copying the data into a buffer which | |
774 * it then runs directly through the MD5 hasher. The 16 byte output of | |
775 * the hash is then sent back to the server. | |
776 * | |
777 * If the client does not send any data back, or the data does not match | |
778 * the data that the specific client should have, the client will get the | |
779 * following message from "AOL Instant Messenger": | |
780 * "You have been disconnected from the AOL Instant Message Service (SM) | |
781 * for accessing the AOL network using unauthorized software. You can | |
782 * download a FREE, fully featured, and authorized client, here | |
783 * http://www.aol.com/aim/download2.html" | |
784 * The connection is then closed, recieving disconnect code 1, URL | |
785 * http://www.aim.aol.com/errors/USER_LOGGED_OFF_NEW_LOGIN.html. | |
786 * | |
787 * Note, however, that numerous inconsistencies can cause the above error, | |
788 * not just sending back a bad hash. Do not immediatly suspect this code | |
789 * if you get disconnected. AOL and the open/free software community have | |
790 * played this game for a couple years now, generating the above message | |
791 * on numerous ocassions. | |
792 * | |
793 * Anyway, neener. We win again. | |
794 * | |
795 */ | |
3952 | 796 /* Subtype 0x001f - Client verification */ |
2703 | 797 static int memrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) |
798 { | |
799 aim_rxcallback_t userfunc; | |
800 fu32_t offset, len; | |
801 aim_tlvlist_t *list; | |
802 char *modname; | |
803 | |
804 offset = aimbs_get32(bs); | |
805 len = aimbs_get32(bs); | |
806 list = aim_readtlvchain(bs); | |
807 | |
808 modname = aim_gettlv_str(list, 0x0001, 1); | |
809 | |
810 faimdprintf(sess, 1, "data at 0x%08lx (%d bytes) of requested\n", offset, len, modname ? modname : "aim.exe"); | |
811 | |
812 if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) | |
813 return userfunc(sess, rx, offset, len, modname); | |
814 | |
815 free(modname); | |
816 aim_freetlvchain(&list); | |
817 | |
818 return 0; | |
819 } | |
820 | |
821 #if 0 | |
822 static void dumpbox(aim_session_t *sess, unsigned char *buf, int len) | |
823 { | |
824 int i; | |
825 | |
826 if (!sess || !buf || !len) | |
827 return; | |
828 | |
829 faimdprintf(sess, 1, "\nDump of %d bytes at %p:", len, buf); | |
830 | |
831 for (i = 0; i < len; i++) { | |
832 if ((i % 8) == 0) | |
833 faimdprintf(sess, 1, "\n\t"); | |
834 | |
835 faimdprintf(sess, 1, "0x%2x ", buf[i]); | |
836 } | |
837 | |
838 faimdprintf(sess, 1, "\n\n"); | |
839 | |
840 return; | |
841 } | |
842 #endif | |
843 | |
3952 | 844 /* Subtype 0x0020 - Client verification reply */ |
2703 | 845 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) |
846 { | |
847 aim_frame_t *fr; | |
848 aim_snacid_t snacid; | |
849 | |
850 if (!sess || !conn) | |
851 return -EINVAL; | |
852 | |
853 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+16))) | |
854 return -ENOMEM; | |
855 | |
856 snacid = aim_cachesnac(sess, 0x0001, 0x0020, 0x0000, NULL, 0); | |
857 | |
858 aim_putsnac(&fr->data, 0x0001, 0x0020, 0x0000, snacid); | |
859 aimbs_put16(&fr->data, 0x0010); /* md5 is always 16 bytes */ | |
860 | |
861 if ((flag == AIM_SENDMEMBLOCK_FLAG_ISHASH) && buf && (len == 0x10)) { /* we're getting a hash */ | |
862 | |
863 aimbs_putraw(&fr->data, buf, 0x10); | |
864 | |
865 } else if (buf && (len > 0)) { /* use input buffer */ | |
866 md5_state_t state; | |
867 md5_byte_t digest[0x10]; | |
868 | |
869 md5_init(&state); | |
870 md5_append(&state, (const md5_byte_t *)buf, len); | |
871 md5_finish(&state, digest); | |
872 | |
873 aimbs_putraw(&fr->data, (fu8_t *)digest, 0x10); | |
874 | |
875 } else if (len == 0) { /* no length, just hash NULL (buf is optional) */ | |
876 md5_state_t state; | |
877 fu8_t nil = '\0'; | |
878 md5_byte_t digest[0x10]; | |
879 | |
880 /* | |
881 * These MD5 routines are stupid in that you have to have | |
882 * at least one append. So thats why this doesn't look | |
883 * real logical. | |
884 */ | |
885 md5_init(&state); | |
886 md5_append(&state, (const md5_byte_t *)&nil, 0); | |
887 md5_finish(&state, digest); | |
888 | |
889 aimbs_putraw(&fr->data, (fu8_t *)digest, 0x10); | |
890 | |
891 } else { | |
892 | |
893 /* | |
894 * This data is correct for AIM 3.5.1670. | |
895 * | |
896 * Using these blocks is as close to "legal" as you can get | |
897 * without using an AIM binary. | |
898 * | |
899 */ | |
900 if ((offset == 0x03ffffff) && (len == 0x03ffffff)) { | |
901 | |
902 #if 1 /* with "AnrbnrAqhfzcd" */ | |
903 aimbs_put32(&fr->data, 0x44a95d26); | |
904 aimbs_put32(&fr->data, 0xd2490423); | |
905 aimbs_put32(&fr->data, 0x93b8821f); | |
906 aimbs_put32(&fr->data, 0x51c54b01); | |
907 #else /* no filename */ | |
908 aimbs_put32(&fr->data, 0x1df8cbae); | |
909 aimbs_put32(&fr->data, 0x5523b839); | |
910 aimbs_put32(&fr->data, 0xa0e10db3); | |
911 aimbs_put32(&fr->data, 0xa46d3b39); | |
912 #endif | |
913 | |
914 } else if ((offset == 0x00001000) && (len == 0x00000000)) { | |
915 | |
916 aimbs_put32(&fr->data, 0xd41d8cd9); | |
917 aimbs_put32(&fr->data, 0x8f00b204); | |
918 aimbs_put32(&fr->data, 0xe9800998); | |
919 aimbs_put32(&fr->data, 0xecf8427e); | |
920 | |
921 } else | |
922 faimdprintf(sess, 0, "sendmemblock: WARNING: unknown hash request\n"); | |
923 | |
924 } | |
925 | |
926 aim_tx_enqueue(sess, fr); | |
927 | |
928 return 0; | |
929 } | |
930 | |
931 static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) | |
932 { | |
933 | |
934 if (snac->subtype == 0x0003) | |
935 return hostonline(sess, mod, rx, snac, bs); | |
936 else if (snac->subtype == 0x0005) | |
937 return redirect(sess, mod, rx, snac, bs); | |
938 else if (snac->subtype == 0x0007) | |
939 return rateresp(sess, mod, rx, snac, bs); | |
940 else if (snac->subtype == 0x000a) | |
941 return ratechange(sess, mod, rx, snac, bs); | |
942 else if (snac->subtype == 0x000b) | |
943 return serverpause(sess, mod, rx, snac, bs); | |
944 else if (snac->subtype == 0x000d) | |
945 return serverresume(sess, mod, rx, snac, bs); | |
946 else if (snac->subtype == 0x000f) | |
947 return selfinfo(sess, mod, rx, snac, bs); | |
948 else if (snac->subtype == 0x0010) | |
949 return evilnotify(sess, mod, rx, snac, bs); | |
950 else if (snac->subtype == 0x0012) | |
951 return migrate(sess, mod, rx, snac, bs); | |
952 else if (snac->subtype == 0x0013) | |
953 return motd(sess, mod, rx, snac, bs); | |
954 else if (snac->subtype == 0x0018) | |
955 return hostversions(sess, mod, rx, snac, bs); | |
956 else if (snac->subtype == 0x001f) | |
957 return memrequest(sess, mod, rx, snac, bs); | |
958 | |
959 return 0; | |
960 } | |
961 | |
962 faim_internal int general_modfirst(aim_session_t *sess, aim_module_t *mod) | |
963 { | |
964 | |
965 mod->family = 0x0001; | |
966 mod->version = 0x0003; | |
967 mod->toolid = 0x0110; | |
4071 | 968 mod->toolversion = 0x0629; |
2703 | 969 mod->flags = 0; |
970 strncpy(mod->name, "general", sizeof(mod->name)); | |
971 mod->snachandler = snachandler; | |
972 | |
973 return 0; | |
974 } |