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