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