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