comparison src/protocols/oscar/rxhandlers.c @ 13592:6519aeb66b31

[gaim-migrate @ 15978] Holy cow this is crazy. 34 files changed, 5760 insertions(+), 8517 deletions(-) * Non-blocking I/O for all of oscar. That includes normal FLAP connections as well as file transfers and direct IM. * Kick-ass file transfer and direct IM. Either party can request the connection. Gaim will try both the "public" IP and the "client" IP. It'll fall back to transferring through a proxy if that fails. Should be relatively few memleaks (I didn't have a lot of confidence in the non-memleakiness of the old code). And the code is reasonably generic, so it shouldn't be too much work to add voice chat. This might still be a LITTLE buggy, but it shouldn't be too bad. If anything, file transfer will be more buggy than direct IM. And sending a file will be more buggy than receiving a file. Bug reports with a series of steps to reproduce are welcome. * I merged OscarData and aim_session_t * Somewhere between 50 and 100 hours of work. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Fri, 07 Apr 2006 05:10:56 +0000
parents e9802db22b06
children
comparison
equal deleted inserted replaced
13591:dcfda39ad547 13592:6519aeb66b31
16 * You should have received a copy of the GNU Lesser General Public 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 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 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21 /*
22 * rxhandlers.c
23 *
24 * This file contains most all of the incoming packet handlers, along
25 * with aim_rxdispatch(), the Rx dispatcher. Queue/list management is
26 * actually done in aim_rxqueue.c.
27 *
28 */
29
30 #include "oscar.h" 21 #include "oscar.h"
31 #include "peer.h" 22 #include "peer.h"
32 23
33 struct aim_rxcblist_s { 24 aim_module_t *aim__findmodulebygroup(OscarData *od, guint16 group)
34 guint16 family;
35 guint16 type;
36 aim_rxcallback_t handler;
37 guint16 flags;
38 struct aim_rxcblist_s *next;
39 };
40
41 faim_internal aim_module_t *aim__findmodulebygroup(OscarSession *sess, guint16 group)
42 { 25 {
43 aim_module_t *cur; 26 aim_module_t *cur;
44 27
45 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { 28 for (cur = (aim_module_t *)od->modlistv; cur; cur = cur->next) {
46 if (cur->family == group) 29 if (cur->family == group)
47 return cur; 30 return cur;
48 } 31 }
49 32
50 return NULL; 33 return NULL;
51 } 34 }
52 35
53 faim_internal aim_module_t *aim__findmodule(OscarSession *sess, const char *name) 36 aim_module_t *aim__findmodule(OscarData *od, const char *name)
54 { 37 {
55 aim_module_t *cur; 38 aim_module_t *cur;
56 39
57 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { 40 for (cur = (aim_module_t *)od->modlistv; cur; cur = cur->next) {
58 if (strcmp(name, cur->name) == 0) 41 if (strcmp(name, cur->name) == 0)
59 return cur; 42 return cur;
60 } 43 }
61 44
62 return NULL; 45 return NULL;
63 } 46 }
64 47
65 faim_internal int aim__registermodule(OscarSession *sess, int (*modfirst)(OscarSession *, aim_module_t *)) 48 int aim__registermodule(OscarData *od, int (*modfirst)(OscarData *, aim_module_t *))
66 { 49 {
67 aim_module_t *mod; 50 aim_module_t *mod;
68 51
69 if (!sess || !modfirst) 52 if (!od || !modfirst)
70 return -1; 53 return -1;
71 54
72 if (!(mod = malloc(sizeof(aim_module_t)))) 55 mod = g_new0(aim_module_t, 1);
73 return -1; 56
74 memset(mod, 0, sizeof(aim_module_t)); 57 if (modfirst(od, mod) == -1) {
75
76 if (modfirst(sess, mod) == -1) {
77 free(mod); 58 free(mod);
78 return -1; 59 return -1;
79 } 60 }
80 61
81 if (aim__findmodule(sess, mod->name)) { 62 if (aim__findmodule(od, mod->name)) {
82 if (mod->shutdown) 63 if (mod->shutdown)
83 mod->shutdown(sess, mod); 64 mod->shutdown(od, mod);
84 free(mod); 65 free(mod);
85 return -1; 66 return -1;
86 } 67 }
87 68
88 mod->next = (aim_module_t *)sess->modlistv; 69 mod->next = (aim_module_t *)od->modlistv;
89 sess->modlistv = mod; 70 od->modlistv = mod;
90 71
91 gaim_debug_misc("oscar", "registered module %s (family 0x%04x, version = 0x%04x, tool 0x%04x, tool version 0x%04x)\n", mod->name, mod->family, mod->version, mod->toolid, mod->toolversion); 72 gaim_debug_misc("oscar", "registered module %s (family 0x%04x, version = 0x%04x, tool 0x%04x, tool version 0x%04x)\n", mod->name, mod->family, mod->version, mod->toolid, mod->toolversion);
92 73
93 return 0; 74 return 0;
94 } 75 }
95 76
96 faim_internal void aim__shutdownmodules(OscarSession *sess) 77 void aim__shutdownmodules(OscarData *od)
97 { 78 {
98 aim_module_t *cur; 79 aim_module_t *cur;
99 80
100 for (cur = (aim_module_t *)sess->modlistv; cur; ) { 81 for (cur = (aim_module_t *)od->modlistv; cur; ) {
101 aim_module_t *tmp; 82 aim_module_t *tmp;
102 83
103 tmp = cur->next; 84 tmp = cur->next;
104 85
105 if (cur->shutdown) 86 if (cur->shutdown)
106 cur->shutdown(sess, cur); 87 cur->shutdown(od, cur);
107 88
108 free(cur); 89 free(cur);
109 90
110 cur = tmp; 91 cur = tmp;
111 } 92 }
112 93
113 sess->modlistv = NULL; 94 od->modlistv = NULL;
114 95
115 return; 96 return;
116 } 97 }
117 98
118 static int consumesnac(OscarSession *sess, FlapFrame *rx) 99 #if 0
119 {
120 aim_module_t *cur;
121 aim_modsnac_t snac;
122
123 if (aim_bstream_empty(&rx->data) < 10)
124 return 0;
125
126 snac.family = aimbs_get16(&rx->data);
127 snac.subtype = aimbs_get16(&rx->data);
128 snac.flags = aimbs_get16(&rx->data);
129 snac.id = aimbs_get32(&rx->data);
130
131 /* SNAC flags are apparently uniform across all SNACs, so we handle them here */
132 if (snac.flags & 0x0001) {
133 /*
134 * This means the SNAC will be followed by another SNAC with
135 * related information. We don't need to do anything about
136 * this here.
137 */
138 }
139 if (snac.flags & 0x8000) {
140 /*
141 * This packet contains the version of the family that this SNAC is
142 * in. You get this when your SSI module is version 2 or higher.
143 * For now we have no need for this, but you could always save
144 * it as a part of aim_modnsac_t, or something. The format is...
145 * 2 byte length of total mini-header (which is 6 bytes), then TLV
146 * of type 0x0001, length 0x0002, value is the 2 byte version
147 * number
148 */
149 aim_bstream_advance(&rx->data, aimbs_get16(&rx->data));
150 }
151
152 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
153
154 if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
155 (cur->family != snac.family))
156 continue;
157
158 if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
159 return 1;
160
161 }
162
163 return 0;
164 }
165
166 static int consumenonsnac(OscarSession *sess, FlapFrame *rx, guint16 family, guint16 subtype)
167 {
168 aim_module_t *cur;
169 aim_modsnac_t snac;
170
171 snac.family = family;
172 snac.subtype = subtype;
173 snac.flags = snac.id = 0;
174
175 for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) {
176
177 if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) &&
178 (cur->family != snac.family))
179 continue;
180
181 if (cur->snachandler(sess, cur, rx, &snac, &rx->data))
182 return 1;
183
184 }
185
186 return 0;
187 }
188
189 static int negchan_middle(OscarSession *sess, FlapFrame *fr)
190 {
191 aim_tlvlist_t *tlvlist;
192 char *msg = NULL;
193 guint16 code = 0;
194 aim_rxcallback_t userfunc;
195 int ret = 1;
196
197 if (aim_bstream_empty(&fr->data) == 0) {
198 /* XXX should do something with this */
199 return 1;
200 }
201
202 /* Used only by the older login protocol */
203 /* XXX remove this special case? */
204 if (fr->conn->type == AIM_CONN_TYPE_AUTH)
205 return consumenonsnac(sess, fr, 0x0017, 0x0003);
206
207 tlvlist = aim_tlvlist_read(&fr->data);
208
209 if (aim_tlv_gettlv(tlvlist, 0x0009, 1))
210 code = aim_tlv_get16(tlvlist, 0x0009, 1);
211
212 if (aim_tlv_gettlv(tlvlist, 0x000b, 1))
213 msg = aim_tlv_getstr(tlvlist, 0x000b, 1);
214
215 if ((userfunc = aim_callhandler(sess, fr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR)))
216 ret = userfunc(sess, fr, code, msg);
217
218 aim_tlvlist_free(&tlvlist);
219
220 free(msg);
221
222 return ret;
223 }
224
225 /* 100 /*
226 * Bleck functions get called when there's no non-bleck functions 101 * Bleck functions get called when there's no non-bleck functions
227 * around to cleanup the mess... 102 * around to cleanup the mess...
228 */ 103 */
229 static int bleck(OscarSession *sess, FlapFrame *frame, ...) 104 static int bleck(OscarData *od, FlapFrame *frame, ...)
230 { 105 {
231 guint16 family, subtype; 106 guint16 family, subtype;
232 guint16 maxf, maxs; 107 guint16 maxf, maxs;
233 108
234 static const char *channels[6] = { 109 static const char *channels[6] = {
238 "Invalid (3)", 113 "Invalid (3)",
239 "Negotiation", 114 "Negotiation",
240 "FLAP NOP" 115 "FLAP NOP"
241 }; 116 };
242 static const int maxchannels = 5; 117 static const int maxchannels = 5;
243 118
244 /* XXX: this is ugly. and big just for debugging. */ 119 /* XXX: this is ugly. and big just for debugging. */
245 static const char *literals[14][25] = { 120 static const char *literals[14][25] = {
246 {"Invalid", 121 {"Invalid",
247 NULL 122 NULL
248 }, 123 },
249 {"General", 124 {"General",
250 "Invalid", 125 "Invalid",
251 "Error", 126 "Error",
252 "Client Ready", 127 "Client Ready",
253 "Server Ready", 128 "Server Ready",
254 "Service Request", 129 "Service Request",
269 "Message of the Day", 144 "Message of the Day",
270 "Set Privacy Flags", 145 "Set Privacy Flags",
271 "Well Known URL", 146 "Well Known URL",
272 "NOP" 147 "NOP"
273 }, 148 },
274 {"Location", 149 {"Location",
275 "Invalid", 150 "Invalid",
276 "Error", 151 "Error",
277 "Request Rights", 152 "Request Rights",
278 "Rights Information", 153 "Rights Information",
279 "Set user information", 154 "Set user information",
280 "Request User Information", 155 "Request User Information",
281 "User Information", 156 "User Information",
282 "Watcher Sub Request", 157 "Watcher Sub Request",
283 "Watcher Notification" 158 "Watcher Notification"
284 }, 159 },
285 {"Buddy List Management", 160 {"Buddy List Management",
286 "Invalid", 161 "Invalid",
287 "Error", 162 "Error",
288 "Request Rights", 163 "Request Rights",
289 "Rights Information", 164 "Rights Information",
290 "Add Buddy", 165 "Add Buddy",
291 "Remove Buddy", 166 "Remove Buddy",
292 "Watcher List Query", 167 "Watcher List Query",
293 "Watcher List Response", 168 "Watcher List Response",
294 "Watcher SubRequest", 169 "Watcher SubRequest",
295 "Watcher Notification", 170 "Watcher Notification",
296 "Reject Notification", 171 "Reject Notification",
297 "Oncoming Buddy", 172 "Oncoming Buddy",
298 "Offgoing Buddy" 173 "Offgoing Buddy"
299 }, 174 },
300 {"Messeging", 175 {"Messeging",
301 "Invalid", 176 "Invalid",
302 "Error", 177 "Error",
303 "Add ICBM Parameter", 178 "Add ICBM Parameter",
304 "Remove ICBM Parameter", 179 "Remove ICBM Parameter",
305 "Request Parameter Information", 180 "Request Parameter Information",
306 "Parameter Information", 181 "Parameter Information",
307 "Outgoing Message", 182 "Outgoing Message",
308 "Incoming Message", 183 "Incoming Message",
309 "Evil Request", 184 "Evil Request",
310 "Evil Reply", 185 "Evil Reply",
311 "Missed Calls", 186 "Missed Calls",
312 "Message Error", 187 "Message Error",
313 "Host Ack" 188 "Host Ack"
314 }, 189 },
315 {"Advertisements", 190 {"Advertisements",
316 "Invalid", 191 "Invalid",
317 "Error", 192 "Error",
318 "Request Ad", 193 "Request Ad",
319 "Ad Data (GIFs)" 194 "Ad Data (GIFs)"
320 }, 195 },
321 {"Invitation / Client-to-Client", 196 {"Invitation / Client-to-Client",
322 "Invalid", 197 "Invalid",
323 "Error", 198 "Error",
324 "Invite a Friend", 199 "Invite a Friend",
325 "Invitation Ack" 200 "Invitation Ack"
326 }, 201 },
327 {"Administrative", 202 {"Administrative",
328 "Invalid", 203 "Invalid",
329 "Error", 204 "Error",
330 "Information Request", 205 "Information Request",
331 "Information Reply", 206 "Information Reply",
332 "Information Change Request", 207 "Information Change Request",
334 "Account Confirm Request", 209 "Account Confirm Request",
335 "Account Confirm Reply", 210 "Account Confirm Reply",
336 "Account Delete Request", 211 "Account Delete Request",
337 "Account Delete Reply" 212 "Account Delete Reply"
338 }, 213 },
339 {"Popups", 214 {"Popups",
340 "Invalid", 215 "Invalid",
341 "Error", 216 "Error",
342 "Display Popup" 217 "Display Popup"
343 }, 218 },
344 {"BOS", 219 {"BOS",
345 "Invalid", 220 "Invalid",
346 "Error", 221 "Error",
347 "Request Rights", 222 "Request Rights",
348 "Rights Response", 223 "Rights Response",
349 "Set group permission mask", 224 "Set group permission mask",
351 "Delete permission list entries", 226 "Delete permission list entries",
352 "Add deny list entries", 227 "Add deny list entries",
353 "Delete deny list entries", 228 "Delete deny list entries",
354 "Server Error" 229 "Server Error"
355 }, 230 },
356 {"User Lookup", 231 {"User Lookup",
357 "Invalid", 232 "Invalid",
358 "Error", 233 "Error",
359 "Search Request", 234 "Search Request",
360 "Search Response" 235 "Search Response"
361 }, 236 },
362 {"Stats", 237 {"Stats",
363 "Invalid", 238 "Invalid",
364 "Error", 239 "Error",
365 "Set minimum report interval", 240 "Set minimum report interval",
366 "Report Events" 241 "Report Events"
367 }, 242 },
368 {"Translate", 243 {"Translate",
369 "Invalid", 244 "Invalid",
370 "Error", 245 "Error",
371 "Translate Request", 246 "Translate Request",
372 "Translate Reply", 247 "Translate Reply",
373 }, 248 },
374 {"Chat Navigation", 249 {"Chat Navigation",
375 "Invalid", 250 "Invalid",
376 "Error", 251 "Error",
377 "Request rights", 252 "Request rights",
378 "Request Exchange Information", 253 "Request Exchange Information",
379 "Request Room Information", 254 "Request Room Information",
380 "Request Occupant List", 255 "Request Occupant List",
381 "Search for Room", 256 "Search for Room",
382 "Outgoing Message", 257 "Outgoing Message",
383 "Incoming Message", 258 "Incoming Message",
384 "Evil Request", 259 "Evil Request",
385 "Evil Reply", 260 "Evil Reply",
386 "Chat Error", 261 "Chat Error",
387 } 262 }
388 }; 263 };
389 264
390 maxf = sizeof(literals) / sizeof(literals[0]); 265 maxf = sizeof(literals) / sizeof(literals[0]);
391 maxs = sizeof(literals[0]) / sizeof(literals[0][0]); 266 maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
392 267
393 if (frame->hdr.flap.channel == 0x02) { 268 if (frame->channel == 0x02) {
394 269
395 family = aimbs_get16(&frame->data); 270 family = byte_stream_get16(&frame->data);
396 subtype = aimbs_get16(&frame->data); 271 subtype = byte_stream_get16(&frame->data);
397 272
398 if ((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL)) 273 if ((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
399 gaim_debug_misc("oscar", "bleck: channel %s: null handler for %04x/%04x (%s)\n", channels[frame->hdr.flap.channel], family, subtype, literals[family][subtype+1]); 274 gaim_debug_misc("oscar", "bleck: channel %s: null handler for %04x/%04x (%s)\n", channels[frame->channel], family, subtype, literals[family][subtype+1]);
400 else 275 else
401 gaim_debug_misc("oscar", "bleck: channel %s: null handler for %04x/%04x (no literal)\n", channels[frame->hdr.flap.channel], family, subtype); 276 gaim_debug_misc("oscar", "bleck: channel %s: null handler for %04x/%04x (no literal)\n", channels[frame->channel], family, subtype);
402 } else { 277 } else {
403 278
404 if (frame->hdr.flap.channel <= maxchannels) 279 if (frame->channel <= maxchannels)
405 gaim_debug_misc("oscar", "bleck: channel %s (0x%02x)\n", channels[frame->hdr.flap.channel], frame->hdr.flap.channel); 280 gaim_debug_misc("oscar", "bleck: channel %s (0x%02x)\n", channels[frame->channel], frame->channel);
406 else 281 else
407 gaim_debug_misc("oscar", "bleck: unknown channel 0x%02x\n", frame->hdr.flap.channel); 282 gaim_debug_misc("oscar", "bleck: unknown channel 0x%02x\n", frame->channel);
408 283
409 } 284 }
410 285
411 return 1; 286 return 1;
412 } 287 }
413 288 #endif
414 faim_export int aim_conn_addhandler(OscarSession *sess, OscarConnection *conn, guint16 family, guint16 type, aim_rxcallback_t newhandler, guint16 flags)
415 {
416 struct aim_rxcblist_s *newcb;
417
418 if (!conn)
419 return -1;
420
421 gaim_debug_misc("oscar", "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
422
423 if (!(newcb = (struct aim_rxcblist_s *)calloc(1, sizeof(struct aim_rxcblist_s))))
424 return -1;
425
426 newcb->family = family;
427 newcb->type = type;
428 newcb->flags = flags;
429 newcb->handler = newhandler ? newhandler : bleck;
430 newcb->next = NULL;
431
432 if (!conn->handlerlist)
433 conn->handlerlist = (void *)newcb;
434 else {
435 struct aim_rxcblist_s *cur;
436
437 for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur->next; cur = cur->next)
438 ;
439 cur->next = newcb;
440 }
441
442 return 0;
443 }
444
445 faim_export int aim_clearhandlers(OscarConnection *conn)
446 {
447 struct aim_rxcblist_s *cur;
448
449 if (!conn)
450 return -1;
451
452 for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; ) {
453 struct aim_rxcblist_s *tmp;
454
455 tmp = cur->next;
456 free(cur);
457 cur = tmp;
458 }
459 conn->handlerlist = NULL;
460
461 return 0;
462 }
463
464 faim_internal aim_rxcallback_t aim_callhandler(OscarSession *sess, OscarConnection *conn, guint16 family, guint16 type)
465 {
466 struct aim_rxcblist_s *cur;
467
468 if (!conn)
469 return NULL;
470
471 /* gaim_debug_misc("oscar", "aim_callhandler: calling for %04x/%04x\n", family, type); */
472
473 for (cur = (struct aim_rxcblist_s *)conn->handlerlist; cur; cur = cur->next) {
474 if ((cur->family == family) && (cur->type == type))
475 return cur->handler;
476 }
477
478 return NULL;
479 }
480
481 faim_internal void aim_clonehandlers(OscarSession *sess, OscarConnection *dest, OscarConnection *src)
482 {
483 struct aim_rxcblist_s *cur;
484
485 for (cur = (struct aim_rxcblist_s *)src->handlerlist; cur; cur = cur->next) {
486 aim_conn_addhandler(sess, dest, cur->family, cur->type,
487 cur->handler, cur->flags);
488 }
489
490 return;
491 }
492
493 faim_internal int aim_callhandler_noparam(OscarSession *sess, OscarConnection *conn,guint16 family, guint16 type, FlapFrame *ptr)
494 {
495 aim_rxcallback_t userfunc;
496
497 if ((userfunc = aim_callhandler(sess, conn, family, type)))
498 return userfunc(sess, ptr);
499
500 return 1; /* XXX */
501 }
502
503 /*
504 * aim_rxdispatch()
505 *
506 * Basically, heres what this should do:
507 * 1) Determine correct packet handler for this packet
508 * 2) Mark the packet handled (so it can be dequeued in purge_queue())
509 * 3) Send the packet to the packet handler
510 * 4) Go to next packet in the queue and start over
511 * 5) When done, run purge_queue() to purge handled commands
512 *
513 * TODO: Clean up.
514 * TODO: More support for mid-level handlers.
515 * TODO: Allow for NULL handlers.
516 *
517 */
518 faim_export void aim_rxdispatch(OscarSession *sess)
519 {
520 int i;
521 FlapFrame *cur;
522
523 for (cur = sess->queue_incoming, i = 0; cur; cur = cur->next, i++) {
524
525 /*
526 * XXX: This is still fairly ugly.
527 */
528
529 if (cur->handled)
530 continue;
531
532 if (cur->hdrtype == AIM_FRAMETYPE_FLAP) {
533 if (cur->hdr.flap.channel == 0x01) {
534 cur->handled = aim_callhandler_noparam(sess, cur->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, cur); /* XXX use consumenonsnac */
535 continue;
536
537 } else if (cur->hdr.flap.channel == 0x02) {
538 if ((cur->handled = consumesnac(sess, cur)))
539 continue;
540
541 } else if (cur->hdr.flap.channel == 0x04) {
542 cur->handled = negchan_middle(sess, cur);
543 continue;
544
545 } else if (cur->hdr.flap.channel == 0x05) {
546
547 }
548
549 } else if (cur->hdrtype == AIM_FRAMETYPE_OFT) {
550 if (cur->conn->type == AIM_CONN_TYPE_RENDEZVOUS) {
551 aim_rxdispatch_rendezvous(sess, cur);
552 cur->handled = 1;
553 continue;
554
555 } else if (cur->conn->type == AIM_CONN_TYPE_LISTENER) {
556 /* not possible */
557 gaim_debug_misc("oscar", "rxdispatch called on LISTENER connection!\n");
558 cur->handled = 1;
559 continue;
560 }
561 }
562
563 if (!cur->handled) {
564 consumenonsnac(sess, cur, 0xffff, 0xffff); /* last chance! */
565 cur->handled = 1;
566 }
567 }
568
569 /*
570 * This doesn't have to be called here. It could easily be done
571 * by a separate thread or something. It's an administrative operation,
572 * and can take a while. Though the less you call it the less memory
573 * you'll have :)
574 */
575 aim_purge_rxqueue(sess);
576
577 return;
578 }
579
580 faim_internal int aim_parse_unknown(OscarSession *sess, FlapFrame *frame, ...)
581 {
582 int i;
583
584 gaim_debug_misc("oscar", "\nRecieved unknown packet:");
585
586 for (i = 0; aim_bstream_empty(&frame->data); i++) {
587 if ((i % 8) == 0)
588 gaim_debug_misc("oscar", "\n\t");
589
590 gaim_debug_misc("oscar", "0x%2x ", aimbs_get8(&frame->data));
591 }
592
593 gaim_debug_misc("oscar", "\n\n");
594
595 return 1;
596 }