]> andersk Git - libfaim.git/blob - aim_rxhandlers.c
- Fri Jun 2 23:27:28 UTC 2000
[libfaim.git] / aim_rxhandlers.c
1 /*
2  * aim_rxhandlers.c
3  *
4  * This file contains most all of the incoming packet handlers, along
5  * with aim_rxdispatch(), the Rx dispatcher.  Queue/list management is
6  * actually done in aim_rxqueue.c.
7  *
8  */
9
10 #include <faim/aim.h>
11
12 /*
13  * Bleck functions get called when there's no non-bleck functions
14  * around to cleanup the mess...
15  */
16 int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...)
17 {
18   u_short family;
19   u_short subtype;
20
21   u_short maxf;
22   u_short maxs;
23
24   /* XXX: this is ugly. and big just for debugging. */
25   char *literals[14][25] = {
26     {"Invalid", 
27      NULL
28     },
29     {"General", 
30      "Invalid",
31      "Error",
32      "Client Ready",
33      "Server Ready",
34      "Service Request",
35      "Redirect",
36      "Rate Information Request",
37      "Rate Information",
38      "Rate Information Ack",
39      NULL,
40      "Rate Information Change",
41      "Server Pause",
42      NULL,
43      "Server Resume",
44      "Request Personal User Information",
45      "Personal User Information",
46      "Evil Notification",
47      NULL,
48      "Migration notice",
49      "Message of the Day",
50      "Set Privacy Flags",
51      "Well Known URL",
52      "NOP"
53     },
54     {"Location", 
55       "Invalid",
56       "Error",
57       "Request Rights",
58       "Rights Information", 
59       "Set user information", 
60       "Request User Information", 
61       "User Information", 
62       "Watcher Sub Request",
63       "Watcher Notification"
64     },
65     {"Buddy List Management", 
66       "Invalid", 
67       "Error", 
68       "Request Rights",
69       "Rights Information",
70       "Add Buddy", 
71       "Remove Buddy", 
72       "Watcher List Query", 
73       "Watcher List Response", 
74       "Watcher SubRequest", 
75       "Watcher Notification", 
76       "Reject Notification", 
77       "Oncoming Buddy", 
78       "Offgoing Buddy"
79     },
80     {"Messeging", 
81       "Invalid",
82       "Error", 
83       "Add ICBM Parameter",
84       "Remove ICBM Parameter", 
85       "Request Parameter Information",
86       "Parameter Information",
87       "Outgoing Message", 
88       "Incoming Message",
89       "Evil Request",
90       "Evil Reply", 
91       "Missed Calls",
92       "Message Error", 
93       "Host Ack"
94     },
95     {"Advertisements", 
96       "Invalid", 
97       "Error", 
98       "Request Ad",
99       "Ad Data (GIFs)"
100     },
101     {"Invitation / Client-to-Client", 
102      "Invalid",
103      "Error",
104      "Invite a Friend",
105      "Invitation Ack"
106     },
107     {"Administrative", 
108       "Invalid",
109       "Error",
110       "Information Request",
111       "Information Reply",
112       "Information Change Request",
113       "Information Chat Reply",
114       "Account Confirm Request",
115       "Account Confirm Reply",
116       "Account Delete Request",
117       "Account Delete Reply"
118     },
119     {"Popups", 
120       "Invalid",
121       "Error",
122       "Display Popup"
123     },
124     {"BOS", 
125       "Invalid",
126       "Error",
127       "Request Rights",
128       "Rights Response",
129       "Set group permission mask",
130       "Add permission list entries",
131       "Delete permission list entries",
132       "Add deny list entries",
133       "Delete deny list entries",
134       "Server Error"
135     },
136     {"User Lookup", 
137       "Invalid",
138       "Error",
139       "Search Request",
140       "Search Response"
141     },
142     {"Stats", 
143       "Invalid",
144       "Error",
145       "Set minimum report interval",
146       "Report Events"
147     },
148     {"Translate", 
149       "Invalid",
150       "Error",
151       "Translate Request",
152       "Translate Reply",
153     },
154     {"Chat Navigation", 
155       "Invalid",
156       "Error",
157       "Request rights",
158       "Request Exchange Information",
159       "Request Room Information",
160       "Request Occupant List",
161       "Search for Room",
162       "Outgoing Message", 
163       "Incoming Message",
164       "Evil Request", 
165       "Evil Reply", 
166       "Chat Error",
167     }
168   };
169
170   maxf = sizeof(literals) / sizeof(literals[0]);
171   maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
172
173   family = aimutil_get16(workingPtr->data+0);
174   subtype= aimutil_get16(workingPtr->data+2);
175
176   if((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
177     printf("bleck: null handler for %04x/%04x (%s)\n", family, subtype, literals[family][subtype+1]);
178   else
179     printf("bleck: null handler for %04x/%04x (no literal)\n",family,subtype);
180
181   return 1;
182 }
183
184 int aim_conn_addhandler(struct aim_session_t *sess,
185                         struct aim_conn_t *conn,
186                         u_short family,
187                         u_short type,
188                         rxcallback_t newhandler,
189                         u_short flags)
190 {
191   struct aim_rxcblist_t *new,*cur;
192
193   if (!conn)
194     return -1;
195
196   faimdprintf(1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
197
198   new = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t));
199   new->family = family;
200   new->type = type;
201   new->flags = flags;
202   if (!newhandler)
203     new->handler = &bleck;
204   else
205     new->handler = newhandler;
206   new->next = NULL;
207   
208   cur = conn->handlerlist;
209   if (!cur)
210     conn->handlerlist = new;
211   else 
212     {
213       while (cur->next)
214         cur = cur->next;
215       cur->next = new;
216     }
217
218   return 0;
219 }
220
221 int aim_clearhandlers(struct aim_conn_t *conn)
222 {
223  struct aim_rxcblist_t *cur,*tmp;
224  if (!conn)
225    return -1;
226
227  cur = conn->handlerlist;
228  while(cur)
229    {
230      tmp = cur->next;
231      free(cur);
232      cur = tmp;
233    }
234  return 0;
235 }
236
237 rxcallback_t aim_callhandler(struct aim_conn_t *conn,
238                     u_short family,
239                     u_short type)
240 {
241   struct aim_rxcblist_t *cur;
242
243   if (!conn)
244     return NULL;
245
246   faimdprintf(1, "aim_callhandler: calling for %04x/%04x\n", family, type);
247   
248   cur = conn->handlerlist;
249   while(cur)
250     {
251       if ( (cur->family == family) && (cur->type == type) )
252         return cur->handler;
253       cur = cur->next;
254     }
255
256   if (type==0xffff)
257     return NULL;
258   return aim_callhandler(conn, family, 0xffff);
259 }
260
261 int aim_callhandler_noparam(struct aim_session_t *sess,
262                             struct aim_conn_t *conn,
263                             u_short family,
264                             u_short type,
265                             struct command_rx_struct *ptr)
266 {
267   rxcallback_t userfunc = NULL;
268   userfunc = aim_callhandler(conn, family, type);
269   if (userfunc)
270     return userfunc(sess, ptr);
271   return 1; /* XXX */
272 }
273
274 /*
275   aim_rxdispatch()
276
277   Basically, heres what this should do:
278     1) Determine correct packet handler for this packet
279     2) Mark the packet handled (so it can be dequeued in purge_queue())
280     3) Send the packet to the packet handler
281     4) Go to next packet in the queue and start over
282     5) When done, run purge_queue() to purge handled commands
283
284   Note that any unhandlable packets should probably be left in the
285   queue.  This is the best way to prevent data loss.  This means
286   that a single packet may get looked at by this function multiple
287   times.  This is more good than bad!  This behavior may change.
288
289   Aren't queue's fun? 
290
291   TODO: Get rid of all the ugly if's.
292   TODO: Clean up.
293   TODO: More support for mid-level handlers.
294   TODO: Allow for NULL handlers.
295   
296  */
297 int aim_rxdispatch(struct aim_session_t *sess)
298 {
299   int i = 0;
300   struct command_rx_struct *workingPtr = NULL;
301   
302   if (sess->queue_incoming == NULL) {
303     faimdprintf(1, "parse_generic: incoming packet queue empty.\n");
304     return 0;
305   } else {
306     workingPtr = sess->queue_incoming;
307     for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) {
308       /*
309        * XXX: This is still fairly ugly.
310        */
311       if (workingPtr->handled)
312         continue;
313
314       switch(workingPtr->conn->type) {
315       case -1:
316         /*
317          * This can happen if we have a queued command
318          * that was recieved after a connection has 
319          * been terminated.  In which case, the handler
320          * list has been cleared, and there's nothing we
321          * can do for it.  We can only cancel it.
322          */
323         workingPtr->handled = 1;
324         break;
325       case AIM_CONN_TYPE_AUTH: {
326         u_long head;
327         
328         head = aimutil_get32(workingPtr->data);
329         if (head == 0x00000001) {
330           faimdprintf(1, "got connection ack on auth line\n");
331           workingPtr->handled = 1;
332         } else {
333           u_short family,subtype;
334           
335           family = aimutil_get16(workingPtr->data);
336           subtype = aimutil_get16(workingPtr->data+2);
337           
338           switch (family) {
339             /* New login protocol */
340 #ifdef SNACLOGIN
341           case 0x0017:
342             if (subtype == 0x0001)
343               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr);
344             else if (subtype == 0x0003)
345               workingPtr->handled = aim_authparse(sess, workingPtr);
346             else if (subtype == 0x0007)
347               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0007, workingPtr);
348             else
349               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
350             break;
351 #else   
352             /* XXX: this isnt foolproof */
353           case 0x0001:
354             if (subtype == 0x0003)
355               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, workingPtr);
356             else
357               workingPtr->handled = aim_authparse(sess, workingPtr);
358             break;
359           case 0x0007:
360             if (subtype == 0x0005)
361               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr);
362             break;
363           default:
364             /* Old login protocol */
365             /* any user callbacks will be called from here */
366             workingPtr->handled = aim_authparse(sess, workingPtr);
367 #endif
368           }
369         }
370         break;
371       }
372       case AIM_CONN_TYPE_BOS: {
373         u_short family;
374         u_short subtype;
375
376         if (workingPtr->type == 0x04) {
377           workingPtr->handled = aim_negchan_middle(sess, workingPtr);
378           break;
379         }
380
381         family = aimutil_get16(workingPtr->data);
382         subtype = aimutil_get16(workingPtr->data+2);
383         
384         switch (family) {
385         case 0x0000: /* not really a family, but it works */
386           if (subtype == 0x0001)
387             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
388           else
389             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
390           break;
391         case 0x0001: /* Family: General */
392           switch (subtype) {
393           case 0x0001:
394             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
395             break;
396           case 0x0003:
397             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
398             break;
399           case 0x0005:
400             workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
401             break;
402           case 0x0007:
403             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
404             break;
405           case 0x000a:
406             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000a, workingPtr);
407             break;
408           case 0x000f:
409             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
410             break;
411           case 0x0013:
412             workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
413             break;
414           default:
415             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
416             break;
417           }
418         case 0x0002: /* Family: Location */
419           switch (subtype) {
420           case 0x0001:
421             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0001, workingPtr);
422             break;
423           case 0x0003:
424             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
425             break;
426           case 0x0006:
427             workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
428             break;
429           default:
430             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
431             break;
432           }
433         case 0x0003: /* Family: Buddy List */
434           switch (subtype) {
435           case 0x0001:
436             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
437             break;
438           case 0x0003:
439             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0003, 0x0003, workingPtr);
440             break;
441           case 0x000b: /* oncoming buddy */
442             workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
443             break;
444           case 0x000c: /* offgoing buddy */
445             workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
446             break;
447           default:
448             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
449           }
450           break;
451         case 0x0004: /* Family: Messeging */
452           switch (subtype) {
453           case 0x0001:
454             workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
455             break;
456           case 0x0005:
457             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
458             break;
459           case 0x0007:
460             workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
461             break;
462           case 0x000a:
463             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x000a, workingPtr);
464             break;
465           default:
466             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
467           }
468           break;
469         case 0x0009:
470           if (subtype == 0x0001)
471             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
472           else if (subtype == 0x0003)
473             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0009, 0x0003, workingPtr);
474           else
475             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
476           break;
477         case 0x000a:  /* Family: User lookup */
478           switch (subtype) {
479           case 0x0001:
480             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr);
481             break;
482           case 0x0003:
483             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, workingPtr);
484             break;
485           default:
486             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
487           }
488           break;
489         case 0x000b:
490           if (subtype == 0x0001)
491             workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
492           else if (subtype == 0x0002)
493             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr);
494           else
495             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
496           break;
497         default:
498           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
499           break;
500         }
501         break;
502       }
503       case AIM_CONN_TYPE_CHATNAV: {
504         u_short family;
505         u_short subtype;
506         family = aimutil_get16(workingPtr->data);
507         subtype= aimutil_get16(workingPtr->data+2);
508         
509         if ((family == 0x0002) && (subtype == 0x0006)) {
510           workingPtr->handled = 1;
511           aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
512         } else if ((family == 0x000d) && (subtype == 0x0009)) {
513           workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
514         } else {
515           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
516         }
517         break;
518       }
519       case AIM_CONN_TYPE_CHAT: {
520         u_short family, subtype;
521         
522         family = aimutil_get16(workingPtr->data);
523         subtype= aimutil_get16(workingPtr->data+2);
524         
525         if ((family == 0x0000) && (subtype == 0x00001))
526           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
527         else if (family == 0x0001) {
528           if (subtype == 0x0001)
529             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr);
530           else if (subtype == 0x0003)
531             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
532           else if (subtype == 0x0007)
533             workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
534           else
535             printf("Chat: unknown snac %04x/%04x\n", family, subtype);
536         } else if (family == 0x000e) {
537           if (subtype == 0x0002)
538             workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
539           else if (subtype == 0x0003)
540             workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);      
541           else if (subtype == 0x0004)
542             workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);       
543           else if (subtype == 0x0006)
544             workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
545           else  
546             printf("Chat: unknown snac %04x/%04x\n", family, subtype); 
547         } else {
548           printf("Chat: unknown snac %04x/%04x\n", family, subtype);
549           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
550         }
551         break;
552       }
553       default:
554         printf("\ninternal error: unknown connection type (very bad.) (type = %d, fd = %d, channel = %02x, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->type, workingPtr->commandlen);
555         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
556         break;
557       } 
558     }
559   }
560
561   /* 
562    * This doesn't have to be called here.  It could easily be done
563    * by a seperate thread or something. It's an administrative operation,
564    * and can take a while. Though the less you call it the less memory
565    * you'll have :)
566    */
567   aim_purge_rxqueue(sess);
568   
569   return 0;
570 }
571
572 int aim_parsemotd_middle(struct aim_session_t *sess,
573                               struct command_rx_struct *command, ...)
574 {
575   rxcallback_t userfunc = NULL;
576   char *msg;
577   int ret=1;
578   struct aim_tlvlist_t *tlvlist;
579   u_short id;
580
581   /*
582    * Dunno.
583    */
584   id = aimutil_get16(command->data+10);
585
586   /* 
587    * TLVs follow 
588    */
589   tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12);
590   
591   msg = aim_gettlv_str(tlvlist, 0x000b, 1);
592   
593   userfunc = aim_callhandler(command->conn, 0x0001, 0x0013);
594   if (userfunc)
595     ret =  userfunc(sess, command, id, msg);
596
597   aim_freetlvchain(&tlvlist);
598
599   return ret;
600   
601 }
602
603 int aim_handleredirect_middle(struct aim_session_t *sess,
604                               struct command_rx_struct *command, ...)
605 {
606   struct aim_tlv_t *tmptlv = NULL;
607   int serviceid = 0x00;
608   char cookie[AIM_COOKIELEN];
609   char *ip = NULL;
610   rxcallback_t userfunc = NULL;
611   struct aim_tlvlist_t *tlvlist;
612   int ret = 1;
613   
614   if (!(tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10)))
615     {
616       printf("libfaim: major bug: unable to read tlvchain from redirect\n");
617       return ret;
618     }
619   
620   if (!(tmptlv = aim_gettlv(tlvlist, 0x000d, 1))) 
621     {
622       printf("libfaim: major bug: no service ID in tlvchain from redirect\n");
623       aim_freetlvchain(&tlvlist);
624       return ret;
625     }
626   serviceid = aimutil_get16(tmptlv->value);
627
628   if (!(ip = aim_gettlv_str(tlvlist, 0x0005, 1))) 
629     {
630       printf("libfaim: major bug: no IP in tlvchain from redirect (service 0x%02x)\n", serviceid);
631       aim_freetlvchain(&tlvlist);
632       return ret;
633     }
634   
635   if (!(tmptlv = aim_gettlv(tlvlist, 0x0006, 1)))
636     {
637       printf("libfaim: major bug: no cookie in tlvchain from redirect (service 0x%02x)\n", serviceid);
638       aim_freetlvchain(&tlvlist);
639       return ret;
640     }
641   memcpy(cookie, tmptlv->value, AIM_COOKIELEN);
642
643   if (serviceid == AIM_CONN_TYPE_CHAT)
644     {
645       /*
646        * Chat hack.
647        *
648        */
649       userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
650       if (userfunc)
651         ret =  userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin);
652       free(sess->pendingjoin);
653       sess->pendingjoin = NULL;
654     }
655   else
656     {
657       userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
658       if (userfunc)
659         ret =  userfunc(sess, command, serviceid, ip, cookie);
660     }
661
662   /*
663    * XXX: Is there a leak here?  Where does IP get freed?
664    */
665   aim_freetlvchain(&tlvlist);
666
667   return ret;
668 }
669
670 int aim_parse_unknown(struct aim_session_t *sess,
671                       struct command_rx_struct *command, ...)
672 {
673   u_int i = 0;
674
675   faimdprintf(1, "\nRecieved unknown packet:");
676
677   for (i = 0; i < command->commandlen; i++)
678     {
679       if ((i % 8) == 0)
680         printf("\n\t");
681
682       printf("0x%2x ", command->data[i]);
683     }
684   
685   printf("\n\n");
686
687   return 1;
688 }
689
690
691 int aim_negchan_middle(struct aim_session_t *sess,
692                        struct command_rx_struct *command)
693 {
694   struct aim_tlvlist_t *tlvlist;
695   char *msg = NULL;
696   unsigned short code = 0;
697   struct aim_tlv_t *tmptlv;
698   rxcallback_t userfunc = NULL;
699   int ret = 1;
700
701   tlvlist = aim_readtlvchain(command->data, command->commandlen);
702
703   if ((tmptlv = aim_gettlv(tlvlist, 0x0009, 1)))
704     code = aimutil_get16(tmptlv->value);
705
706   if ((tmptlv = aim_gettlv(tlvlist, 0x000b, 1)))
707     msg = aim_gettlv_str(tlvlist, 0x000b, 1);
708
709   userfunc = aim_callhandler(command->conn, 
710                              AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR);
711   if (userfunc)
712     ret =  userfunc(sess, command, code, msg);
713
714   aim_freetlvchain(&tlvlist);
715   free(msg);
716
717   return ret;
718 }
719
720 /*
721  * aim_parse_generalerrs()
722  *
723  * Middle handler for 0x0001 snac of each family.
724  *
725  */
726 int aim_parse_generalerrs(struct aim_session_t *sess,
727                           struct command_rx_struct *command, ...)
728 {
729   u_short family;
730   u_short subtype;
731   
732   family = aimutil_get16(command->data+0);
733   subtype= aimutil_get16(command->data+2);
734   
735   switch(family)
736     {
737     default:
738       /* Unknown family */
739       return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);
740     }
741
742   return 1;
743 }
744
745
746
This page took 0.091066 seconds and 5 git commands to generate.