]> andersk Git - libfaim.git/blob - aim_rxhandlers.c
Last few changes left in my inbox.
[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 <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 command_rx_struct *workingPtr, ...)
17 {
18   u_short family;
19   u_short subtype;
20   family = (workingPtr->data[0] << 8) + workingPtr->data[1];
21   subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
22   printf("bleck: null handler for %04x/%04x\n", family, subtype);
23   return 1;
24 }
25
26 int aim_conn_addhandler(struct aim_conn_t *conn,
27                         u_short family,
28                         u_short type,
29                         rxcallback_t newhandler,
30                         u_short flags)
31 {
32   struct aim_rxcblist_t *new,*cur;
33
34   if (!conn)
35     return -1;
36
37 #if debug > 0
38   printf("aim_conn_addhandler: adding for %04x/%04x\n", family, type);
39 #endif
40
41   new = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t));
42   new->family = family;
43   new->type = type;
44   new->flags = flags;
45   if (!newhandler)
46     new->handler = &bleck;
47   else
48     new->handler = newhandler;
49   new->next = NULL;
50   
51   cur = conn->handlerlist;
52   if (!cur)
53     conn->handlerlist = new;
54   else 
55     {
56       while (cur->next)
57         cur = cur->next;
58       cur->next = new;
59     }
60
61   return 0;
62 }
63
64 int aim_clearhandlers(struct aim_conn_t *conn)
65 {
66  struct aim_rxcblist_t *cur,*tmp;
67  if (!conn)
68    return -1;
69
70  cur = conn->handlerlist;
71  while(cur)
72    {
73      tmp = cur->next;
74      free(cur);
75      cur = tmp;
76    }
77  return 0;
78 }
79
80 rxcallback_t aim_callhandler(struct aim_conn_t *conn,
81                     u_short family,
82                     u_short type)
83 {
84   struct aim_rxcblist_t *cur;
85
86   if (!conn)
87     return NULL;
88
89 #if debug > 0
90   printf("aim_callhandler: calling for %04x/%04x\n", family, type);
91 #endif
92   
93   cur = conn->handlerlist;
94   while(cur)
95     {
96       if ( (cur->family == family) && (cur->type == type) )
97         return cur->handler;
98       cur = cur->next;
99     }
100
101   if (type==0xffff)
102     return NULL;
103   return aim_callhandler(conn, family, 0xffff);
104 }
105
106 int aim_callhandler_noparam(struct aim_conn_t *conn,
107                             u_short family,
108                             u_short type,
109                             struct command_rx_struct *ptr)
110 {
111   rxcallback_t userfunc = NULL;
112   userfunc = aim_callhandler(conn, family, type);
113   if (userfunc)
114     return userfunc(ptr);
115   return 0;
116 }
117
118 /*
119   aim_rxdispatch()
120
121   Basically, heres what this should do:
122     1) Determine correct packet handler for this packet
123     2) Mark the packet handled (so it can be dequeued in purge_queue())
124     3) Send the packet to the packet handler
125     4) Go to next packet in the queue and start over
126     5) When done, run purge_queue() to purge handled commands
127
128   Note that any unhandlable packets should probably be left in the
129   queue.  This is the best way to prevent data loss.  This means
130   that a single packet may get looked at by this function multiple
131   times.  This is more good than bad!  This behavior may change.
132
133   Aren't queue's fun? 
134
135   TODO: Get rid of all the ugly if's.
136   TODO: Clean up.
137   TODO: More support for mid-level handlers.
138   TODO: Allow for NULL handlers.
139   
140  */
141 int aim_rxdispatch(void)
142 {
143   int i = 0;
144   struct command_rx_struct *workingPtr = NULL;
145   
146   if (aim_queue_incoming == NULL)
147     /* this shouldn't really happen, unless the main loop's select is broke  */
148     printf("parse_generic: incoming packet queue empty.\n");
149   else
150     {
151       workingPtr = aim_queue_incoming;
152       for (i = 0; workingPtr != NULL; i++)
153         {
154           switch(workingPtr->conn->type)
155             {
156             case AIM_CONN_TYPE_AUTH:
157               if ( (workingPtr->data[0] == 0x00) && 
158                    (workingPtr->data[1] == 0x00) &&
159                    (workingPtr->data[2] == 0x00) &&
160                    (workingPtr->data[3] == 0x01) )
161                 {
162 #if debug > 0
163                   printf("got connection ack on auth line\n");
164 #endif
165                   workingPtr->handled = 1;
166                 }
167               else
168                 {
169                   /* any user callbacks will be called from here */
170                   workingPtr->handled = aim_authparse(workingPtr);
171                 }
172               break;
173             case AIM_CONN_TYPE_BOS:
174               {
175                 u_short family;
176                 u_short subtype;
177                 family = (workingPtr->data[0] << 8) + workingPtr->data[1];
178                 subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
179                 switch (family)
180                   {
181                   case 0x0000: /* not really a family, but it works */
182                     if (subtype == 0x0001)
183                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0000, 0x0001, workingPtr);
184                     else
185                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
186                     break;
187                   case 0x0001: /* Family: General */
188                     switch (subtype)
189                       {
190                       case 0x0001:
191                         workingPtr->handled = aim_parse_generalerrs(workingPtr);
192                         break;
193                       case 0x0003:
194                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x0003, workingPtr);
195                         break;
196                       case 0x0005:
197                         workingPtr->handled = aim_handleredirect_middle(workingPtr);
198                         break;
199                       case 0x0007:
200                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x0007, workingPtr);
201                         break;
202                       case 0x000a:
203                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x000a, workingPtr);
204                         break;
205                       case 0x000f:
206                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x000f, workingPtr);
207                         break;
208                       case 0x0013:
209                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0001, 0x0013, workingPtr);
210                         break;
211                       default:
212                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
213                       }
214                     break;
215                   case 0x0002: /* Family: Location */
216                     switch (subtype)
217                       {
218                       case 0x0001:
219                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0002, 0x0001, workingPtr);
220                         break;
221                       case 0x0003:
222                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0002, 0x0003, workingPtr);
223                         break;
224                       case 0x0006:
225                         workingPtr->handled = aim_parse_userinfo_middle(workingPtr);
226                         break;
227                       default:
228                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
229                       }
230                     break;
231                   case 0x0003: /* Family: Buddy List */
232                     switch (subtype)
233                       {
234                       case 0x0001:
235                         workingPtr->handled = aim_parse_generalerrs(workingPtr);
236                         break;
237                       case 0x0003:
238                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0003, 0x0003, workingPtr);
239                         break;
240                       case 0x000b: /* oncoming buddy */
241                         workingPtr->handled = aim_parse_oncoming_middle(workingPtr);
242                         break;
243                       case 0x000c: /* offgoing buddy */
244                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0003, 0x000c, workingPtr);
245                         break;
246                       default:
247                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
248                       }
249                     break;
250                   case 0x0004: /* Family: Messeging */
251                     switch (subtype)
252                       {
253                       case 0x0001:
254                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0004, 0x0001, workingPtr);
255                         break;
256                       case 0x0005:
257                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0004, 0x0005, workingPtr);
258                         break;
259                       case 0x0007:
260                         workingPtr->handled = aim_parse_incoming_im_middle(workingPtr);
261                         break;
262                       case 0x000a:
263                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0004, 0x000a, workingPtr);
264                         break;
265                       default:
266                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
267                       }
268                     break;
269                   case 0x0009:
270                     if (subtype == 0x0001)
271                       workingPtr->handled = aim_parse_generalerrs(workingPtr);
272                     else if (subtype == 0x0003)
273                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x0009, 0x0003, workingPtr);
274                     else
275                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
276                     break;
277                   case 0x000a:  /* Family: User lookup */
278                     switch (subtype)
279                       {
280                       case 0x0001:
281                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x000a, 0x0001, workingPtr);
282                         break;
283                       case 0x0003:
284                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x000a, 0x0003, workingPtr);
285                         break;
286                       default:
287                         workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
288                       }
289                     break;
290                   case 0x000b:
291                     if (subtype == 0x0001)
292                       workingPtr->handled = aim_parse_generalerrs(workingPtr);
293                     else if (subtype == 0x0002)
294                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, 0x000b, 0x0002, workingPtr);
295                     else
296                       workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
297                     break;
298                   default:
299                     workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
300                     break;
301                   }
302               }
303               break;
304             case AIM_CONN_TYPE_CHATNAV:
305               {
306                 u_short family;
307                 u_short subtype;
308                 family = (workingPtr->data[0] << 8) + workingPtr->data[1];
309                 subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
310                 if ( (workingPtr->data[0] == 0x00) &&
311                      (workingPtr->data[1] == 0x02) &&
312                      (workingPtr->data[2] == 0x00) &&
313                      (workingPtr->data[3] == 0x06) )
314                   {
315                     workingPtr->handled = 1;
316                     aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
317                   }
318                 else
319                   {
320                     workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, family, subtype, workingPtr);
321                   }
322               }
323               break;
324             case AIM_CONN_TYPE_CHAT:
325               printf("\nAHH! Dont know what to do with CHAT stuff yet!\n");
326               workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
327               break;
328             default:
329               printf("\nAHHHHH! UNKNOWN CONNECTION TYPE! (0x%02x)\n\n", workingPtr->conn->type);
330               workingPtr->handled = aim_callhandler_noparam(workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
331               break;
332             }
333               /* move to next command */
334           workingPtr = workingPtr->next;
335         }
336     }
337
338   aim_queue_incoming = aim_purge_rxqueue(aim_queue_incoming);
339   
340   return 0;
341 }
342
343 /*
344  * TODO: check and cure memory leakage in this function.
345  */
346 int aim_authparse(struct command_rx_struct *command)
347 {
348   rxcallback_t userfunc = NULL;
349   int iserror = 0;
350   struct aim_tlv_t *tlv = NULL;
351   char *errorurl = NULL;
352   short errorcode = 0x00;
353   u_int z = 0;
354
355   if ( (command->data[0] == 0x00) &&
356        (command->data[1] == 0x01) &&
357        (command->data[2] == 0x00) &&
358        (command->data[3] == 0x03) )
359     {
360       /* "server ready"  -- can be ignored */
361       userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY);
362     }
363   else if ( (command->data[0] == 0x00) &&
364             (command->data[1] == 0x07) &&
365             (command->data[2] == 0x00) &&
366             (command->data[3] == 0x05) )
367     {
368       /* "information change reply" */
369       userfunc = aim_callhandler(command->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY);
370     }
371   else
372     {
373       /* anything else -- usually used for login; just parse as pure TLVs */
374
375       /*
376        * Free up the loginstruct first.
377        */
378       if (aim_logininfo.screen_name)
379         {
380           free(aim_logininfo.screen_name);
381           aim_logininfo.screen_name = NULL;
382         }
383       if (aim_logininfo.BOSIP)
384         {
385           free(aim_logininfo.BOSIP);
386           aim_logininfo.BOSIP = NULL;
387         }
388       if (aim_logininfo.cookie)
389         {
390           free(aim_logininfo.cookie);
391           aim_logininfo.cookie = NULL;
392         }
393       if (aim_logininfo.email)
394         {
395           free(aim_logininfo.email);
396           aim_logininfo.email = NULL;
397         }
398       aim_logininfo.regstatus = 0;
399
400       /* all this block does is figure out if it's an
401          error or a success, nothing more */
402       while (z < command->commandlen)
403         {
404           tlv = aim_grabtlvstr(&(command->data[z]));
405           switch(tlv->type) 
406             {
407             case 0x0001: /* screen name */
408               aim_logininfo.screen_name = tlv->value;
409               z += 2 + 2 + tlv->length;
410               free(tlv);
411               tlv = NULL;
412               break;
413             case 0x0004: /* error URL */
414               errorurl = tlv->value;
415               z += 2 + 2 + tlv->length;
416               free(tlv);
417               tlv = NULL;
418               break;
419             case 0x0005: /* BOS IP */
420               aim_logininfo.BOSIP = tlv->value;
421               z += 2 + 2 + tlv->length;
422               free(tlv);
423               tlv = NULL;
424               break;
425             case 0x0006: /* auth cookie */
426               aim_logininfo.cookie = tlv->value;
427               z += 2 + 2 + tlv->length;
428               free(tlv);
429               tlv=NULL;
430               break;
431             case 0x0011: /* email addy */
432               aim_logininfo.email = tlv->value;
433               z += 2 + 2 + tlv->length;
434               free(tlv);
435               tlv = NULL;
436               break;
437             case 0x0013: /* registration status */
438               aim_logininfo.regstatus = *(tlv->value);
439               z += 2 + 2 + tlv->length;
440               aim_freetlv(&tlv);
441               break;
442             case 0x0008: /* error code */
443               errorcode = *(tlv->value);
444               z += 2 + 2 + tlv->length;
445               aim_freetlv(&tlv);
446               iserror = 1;
447               break;
448             default:
449           z += 2 + 2 + tlv->length;
450           aim_freetlv(&tlv);
451           /* dunno */
452             }
453         }
454
455       if (iserror && 
456           errorurl)
457         {
458           userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_ERROR);
459           if (userfunc)
460             return userfunc(command, &aim_logininfo, errorurl, errorcode);
461           return 0;
462         }
463       else if (aim_logininfo.screen_name && 
464                aim_logininfo.cookie && aim_logininfo.BOSIP)
465         {
466           userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHSUCCESS);
467           if (userfunc)
468             return userfunc(command, &aim_logininfo);
469           return 0;
470         }
471       else
472         userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHOTHER);
473     }
474
475   if (userfunc)
476     return userfunc(command);
477   printf("handler not available!\n");
478   return 0;
479 }
480
481 /*
482  * TODO: check for and cure any memory leaks here.
483  */
484 int aim_handleredirect_middle(struct command_rx_struct *command, ...)
485 {
486   struct aim_tlv_t *tlv = NULL;
487   u_int z = 10;
488   int serviceid = 0x00;
489   char *cookie = NULL;
490   char *ip = NULL;
491   rxcallback_t userfunc = NULL;
492
493   while (z < command->commandlen)
494     {
495       tlv = aim_grabtlvstr(&(command->data[z]));
496       switch(tlv->type)
497         {
498         case 0x000d:  /* service id */
499           aim_freetlv(&tlv);
500           /* regrab as an int */
501           tlv = aim_grabtlv(&(command->data[z]));
502           serviceid = (tlv->value[0] << 8) + tlv->value[1]; /* hehe */
503           z += 2 + 2 + tlv->length;
504           aim_freetlv(&tlv);
505           break;
506         case 0x0005:  /* service server IP */
507           ip = tlv->value;
508           z += 2 + 2 + tlv->length;
509           free(tlv);
510           tlv = NULL;
511           break;
512         case 0x0006: /* auth cookie */
513           cookie = tlv->value;
514           z += 2 + 2 + tlv->length;
515           free(tlv);
516           tlv = NULL;
517           break;
518         default:
519           /* dunno */
520           z += 2 + 2 + tlv->length;
521           aim_freetlv(&tlv);
522         }
523     }
524   userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
525   if (userfunc)
526     return userfunc(command, serviceid, ip, cookie);
527   return 0;
528 }
529
530 int aim_parse_unknown(struct command_rx_struct *command, ...)
531 {
532   u_int i = 0;
533
534   printf("\nRecieved unknown packet:");
535
536   for (i = 0; i < command->commandlen; i++)
537     {
538       if ((i % 8) == 0)
539         printf("\n\t");
540
541       printf("0x%2x ", command->data[i]);
542     }
543   
544   printf("\n\n");
545
546   return 1;
547 }
548
549
550 /*
551  * aim_parse_generalerrs()
552  *
553  * Middle handler for 0x0001 snac of each family.
554  *
555  */
556 int aim_parse_generalerrs(struct command_rx_struct *command, ...)
557 {
558   u_short family;
559   u_short subtype;
560   family = (command->data[0] << 8) + command->data[1];
561   subtype = (command->data[2] << 8) + command->data[3];
562   
563   switch(family)
564     {
565     default:
566       /* Unknown family */
567       return aim_callhandler_noparam(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);
568     }
569
570   return 1;
571 }
572
573
574
This page took 0.08383 seconds and 5 git commands to generate.