]> andersk Git - libfaim.git/blob - aim_rxhandlers.c
Added some debugging printfs to help track down the SNAC userinf problem.
[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 #if debug > 0
197   printf("aim_conn_addhandler: adding for %04x/%04x\n", family, type);
198 #endif
199
200   new = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t));
201   new->family = family;
202   new->type = type;
203   new->flags = flags;
204   if (!newhandler)
205     new->handler = &bleck;
206   else
207     new->handler = newhandler;
208   new->next = NULL;
209   
210   cur = conn->handlerlist;
211   if (!cur)
212     conn->handlerlist = new;
213   else 
214     {
215       while (cur->next)
216         cur = cur->next;
217       cur->next = new;
218     }
219
220   return 0;
221 }
222
223 int aim_clearhandlers(struct aim_conn_t *conn)
224 {
225  struct aim_rxcblist_t *cur,*tmp;
226  if (!conn)
227    return -1;
228
229  cur = conn->handlerlist;
230  while(cur)
231    {
232      tmp = cur->next;
233      free(cur);
234      cur = tmp;
235    }
236  return 0;
237 }
238
239 rxcallback_t aim_callhandler(struct aim_conn_t *conn,
240                     u_short family,
241                     u_short type)
242 {
243   struct aim_rxcblist_t *cur;
244
245   if (!conn)
246     return NULL;
247
248 #if debug > 0
249   printf("aim_callhandler: calling for %04x/%04x\n", family, type);
250 #endif
251   
252   cur = conn->handlerlist;
253   while(cur)
254     {
255       if ( (cur->family == family) && (cur->type == type) )
256         return cur->handler;
257       cur = cur->next;
258     }
259
260   if (type==0xffff)
261     return NULL;
262   return aim_callhandler(conn, family, 0xffff);
263 }
264
265 int aim_callhandler_noparam(struct aim_session_t *sess,
266                             struct aim_conn_t *conn,
267                             u_short family,
268                             u_short type,
269                             struct command_rx_struct *ptr)
270 {
271   rxcallback_t userfunc = NULL;
272   userfunc = aim_callhandler(conn, family, type);
273   if (userfunc)
274     return userfunc(sess, ptr);
275   return 0;
276 }
277
278 /*
279   aim_rxdispatch()
280
281   Basically, heres what this should do:
282     1) Determine correct packet handler for this packet
283     2) Mark the packet handled (so it can be dequeued in purge_queue())
284     3) Send the packet to the packet handler
285     4) Go to next packet in the queue and start over
286     5) When done, run purge_queue() to purge handled commands
287
288   Note that any unhandlable packets should probably be left in the
289   queue.  This is the best way to prevent data loss.  This means
290   that a single packet may get looked at by this function multiple
291   times.  This is more good than bad!  This behavior may change.
292
293   Aren't queue's fun? 
294
295   TODO: Get rid of all the ugly if's.
296   TODO: Clean up.
297   TODO: More support for mid-level handlers.
298   TODO: Allow for NULL handlers.
299   
300  */
301 int aim_rxdispatch(struct aim_session_t *sess)
302 {
303   int i = 0;
304   struct command_rx_struct *workingPtr = NULL;
305   
306   if (sess->queue_incoming == NULL)
307     /* this shouldn't really happen, unless the main loop's select is broke  */
308     printf("parse_generic: incoming packet queue empty.\n");
309   else
310     {
311       workingPtr = sess->queue_incoming;
312       for (i = 0; workingPtr != NULL; i++)
313         {
314           switch(workingPtr->conn->type)
315             {
316             case AIM_CONN_TYPE_AUTH:
317               {
318                 u_long head;
319
320                 head = aimutil_get32(workingPtr->data);
321                 if (head == 0x00000001)
322                   {
323 #if debug > 0
324                     printf("got connection ack on auth line\n");
325 #endif
326                     workingPtr->handled = 1;
327                   }
328                 else
329                   {
330                     u_short family,subtype;
331
332                     family = aimutil_get16(workingPtr->data);
333                     subtype = aimutil_get16(workingPtr->data+2);
334                     
335                     switch (family)
336                       {
337                         /* New login protocol */
338 #ifdef SNACLOGIN
339                       case 0x0017:
340                         if (subtype == 0x0001)
341                           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr);
342                         else if (subtype == 0x0003)
343                           workingPtr->handled = aim_authparse(sess, workingPtr);
344                         else if (subtype == 0x0007)
345                           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0007, workingPtr);
346                         else
347                           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
348                         break;
349 #else
350                         /* XXX: this isnt foolproof */
351                       case 0x0001:
352                         if (subtype == 0x0003)
353                           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, workingPtr);
354                         else
355                           workingPtr->handled = aim_authparse(sess, workingPtr);
356                         break;
357                       case 0x0007:
358                         if (subtype == 0x0005)
359                           workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr);
360                         break;
361                       default:
362                         /* Old login protocol */
363                         /* any user callbacks will be called from here */
364                         workingPtr->handled = aim_authparse(sess, workingPtr);
365 #endif
366                       }
367                   }
368               }
369               break;
370             case AIM_CONN_TYPE_BOS:
371               {
372                 u_short family;
373                 u_short subtype;
374
375                 family = aimutil_get16(workingPtr->data);
376                 subtype = aimutil_get16(workingPtr->data+2);
377
378                 switch (family)
379                   {
380                   case 0x0000: /* not really a family, but it works */
381                     if (subtype == 0x0001)
382                       workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
383                     else
384                       workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
385                     break;
386                   case 0x0001: /* Family: General */
387                     switch (subtype)
388                       {
389                       case 0x0001:
390                         workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
391                         break;
392                       case 0x0003:
393                         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
394                         break;
395                       case 0x0005:
396                         workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
397                         break;
398                       case 0x0007:
399                         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
400                         break;
401                       case 0x000a:
402                         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000a, workingPtr);
403                         break;
404                       case 0x000f:
405                         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
406                         break;
407                       case 0x0013:
408                         workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
409                         break;
410                       default:
411                         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
412                       }
413                     break;
414                   case 0x0002: /* Family: Location */
415                     switch (subtype)
416                       {
417                       case 0x0001:
418                         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0001, workingPtr);
419                         break;
420                       case 0x0003:
421                         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
422                         break;
423                       case 0x0006:
424                         workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
425                         break;
426                       default:
427                         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
428                       }
429                     break;
430                   case 0x0003: /* Family: Buddy List */
431                     switch (subtype)
432                       {
433                       case 0x0001:
434                         workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
435                         break;
436                       case 0x0003:
437                         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0003, 0x0003, workingPtr);
438                         break;
439                       case 0x000b: /* oncoming buddy */
440                         workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
441                         break;
442                       case 0x000c: /* offgoing buddy */
443                         workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
444                         break;
445                       default:
446                         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
447                       }
448                     break;
449                   case 0x0004: /* Family: Messeging */
450                     switch (subtype)
451                       {
452                       case 0x0001:
453                         workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
454                         break;
455                       case 0x0005:
456                         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
457                         break;
458                       case 0x0007:
459                         workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
460                         break;
461                       case 0x000a:
462                         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x000a, workingPtr);
463                         break;
464                       default:
465                         workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
466                       }
467                     break;
468                   case 0x0009:
469                     if (subtype == 0x0001)
470                       workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
471                     else if (subtype == 0x0003)
472                       workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0009, 0x0003, workingPtr);
473                     else
474                       workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
475                     break;
476                   case 0x000a:  /* Family: User lookup */
477                     switch (subtype)
478                       {
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               }
502               break;
503             case AIM_CONN_TYPE_CHATNAV:
504               {
505                 u_short family;
506                 u_short subtype;
507                 family = aimutil_get16(workingPtr->data);
508                 subtype= aimutil_get16(workingPtr->data+2);
509
510                 if ((family == 0x0002) && (subtype == 0x0006))
511                   {
512                     workingPtr->handled = 1;
513                     aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
514                   }
515                 else if ((family == 0x000d) && (subtype == 0x0009))
516                   workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
517                 else
518                   {
519                     workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
520                   }
521               }
522               break;
523             case AIM_CONN_TYPE_CHAT:
524               {
525                 u_short family, subtype;
526
527                 family = aimutil_get16(workingPtr->data);
528                 subtype= aimutil_get16(workingPtr->data+2);
529                 
530                 if ((family == 0x0000) && (subtype == 0x00001))
531                   workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
532                 else if (family == 0x0001)
533                   {
534                     if (subtype == 0x0001)
535                       workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr);
536                     else if (subtype == 0x0003)
537                       workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
538                     else if (subtype == 0x0007)
539                       workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
540                     else
541                       printf("Chat: unknown snac %04x/%04x\n", family, subtype);
542                   }
543                 else if (family == 0x000e)
544                   {
545                     if (subtype == 0x0002)
546                       workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
547                     else if (subtype == 0x0003)
548                       workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);    
549                     else if (subtype == 0x0004)
550                       workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);     
551                     else if (subtype == 0x0006)
552                       workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
553                     else        
554                       printf("Chat: unknown snac %04x/%04x\n", family, subtype); 
555                   }
556                 else
557                   {
558                     printf("Chat: unknown snac %04x/%04x\n", family, subtype);
559                     workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
560                   }
561               }
562               break;
563             default:
564               printf("\nAHHHHH! UNKNOWN CONNECTION TYPE! (0x%02x)\n\n", workingPtr->conn->type);
565               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
566               break;
567             }
568           /* move to next command */
569           workingPtr = workingPtr->next;
570         }
571     }
572
573   sess->queue_incoming = aim_purge_rxqueue(sess->queue_incoming);
574   
575   return 0;
576 }
577
578 int aim_parsemotd_middle(struct aim_session_t *sess,
579                               struct command_rx_struct *command, ...)
580 {
581   rxcallback_t userfunc = NULL;
582   char *msg;
583   int ret=1;
584   struct aim_tlvlist_t *tlvlist;
585   u_short id;
586
587   /*
588    * Dunno.
589    */
590   id = aimutil_get16(command->data+10);
591
592   /* 
593    * TLVs follow 
594    */
595   tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12);
596   
597   msg = aim_gettlv_str(tlvlist, 0x000b, 1);
598   
599   userfunc = aim_callhandler(command->conn, 0x0001, 0x0013);
600   if (userfunc)
601     ret =  userfunc(sess, command, id, msg);
602
603   aim_freetlvchain(&tlvlist);
604
605   return ret;
606   
607 }
608
609 int aim_handleredirect_middle(struct aim_session_t *sess,
610                               struct command_rx_struct *command, ...)
611 {
612   struct aim_tlv_t *tmptlv = NULL;
613   int serviceid = 0x00;
614   char cookie[AIM_COOKIELEN];
615   char *ip = NULL;
616   rxcallback_t userfunc = NULL;
617   struct aim_tlvlist_t *tlvlist;
618   int ret = 1;
619   
620   tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10);
621   
622   tmptlv = aim_gettlv(tlvlist, 0x000d, 1);
623   serviceid = aimutil_get16(tmptlv->value);
624
625   ip = aim_gettlv_str(tlvlist, 0x0005, 1);
626   
627   tmptlv = aim_gettlv(tlvlist, 0x0006, 1);
628   memcpy(cookie, tmptlv->value, AIM_COOKIELEN);
629
630   if (serviceid == AIM_CONN_TYPE_CHAT)
631     {
632       /*
633        * Chat hack.
634        *
635        */
636       userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
637       if (userfunc)
638         ret =  userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin);
639       free(sess->pendingjoin);
640       sess->pendingjoin = NULL;
641     }
642   else
643     {
644       userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
645       if (userfunc)
646         ret =  userfunc(sess, command, serviceid, ip, cookie);
647     }
648   aim_freetlvchain(&tlvlist);
649
650   return ret;
651 }
652
653 int aim_parse_unknown(struct aim_session_t *sess,
654                       struct command_rx_struct *command, ...)
655 {
656   u_int i = 0;
657
658   printf("\nRecieved unknown packet:");
659
660   for (i = 0; i < command->commandlen; i++)
661     {
662       if ((i % 8) == 0)
663         printf("\n\t");
664
665       printf("0x%2x ", command->data[i]);
666     }
667   
668   printf("\n\n");
669
670   return 1;
671 }
672
673
674 /*
675  * aim_parse_generalerrs()
676  *
677  * Middle handler for 0x0001 snac of each family.
678  *
679  */
680 int aim_parse_generalerrs(struct aim_session_t *sess,
681                           struct command_rx_struct *command, ...)
682 {
683   u_short family;
684   u_short subtype;
685   
686   family = aimutil_get16(command->data+0);
687   subtype= aimutil_get16(command->data+2);
688   
689   switch(family)
690     {
691     default:
692       /* Unknown family */
693       return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);
694     }
695
696   return 1;
697 }
698
699
700
This page took 0.094844 seconds and 5 git commands to generate.