]> andersk Git - libfaim.git/blob - aim_rxhandlers.c
Lots of minor cleanups. Adds new (disabled) SNAC-based login.
[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
516                   {
517                     workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
518                   }
519               }
520               break;
521             case AIM_CONN_TYPE_CHAT:
522               printf("\nAHH! Dont know what to do with CHAT stuff yet!\n");
523               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
524               break;
525             default:
526               printf("\nAHHHHH! UNKNOWN CONNECTION TYPE! (0x%02x)\n\n", workingPtr->conn->type);
527               workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
528               break;
529             }
530           /* move to next command */
531           workingPtr = workingPtr->next;
532         }
533     }
534
535   sess->queue_incoming = aim_purge_rxqueue(sess->queue_incoming);
536   
537   return 0;
538 }
539
540 int aim_parsemotd_middle(struct aim_session_t *sess,
541                               struct command_rx_struct *command, ...)
542 {
543   rxcallback_t userfunc = NULL;
544   char *msg;
545   int ret=1;
546   struct aim_tlvlist_t *tlvlist;
547   u_short id;
548
549   /*
550    * Dunno.
551    */
552   id = aimutil_get16(command->data+10);
553
554   /* 
555    * TLVs follow 
556    */
557   tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12);
558   
559   msg = aim_gettlv_str(tlvlist, 0x000b, 1);
560   
561   userfunc = aim_callhandler(command->conn, 0x0001, 0x0013);
562   if (userfunc)
563     ret =  userfunc(sess, command, id, msg);
564
565   aim_freetlvchain(&tlvlist);
566
567   return ret;
568   
569 }
570
571 int aim_handleredirect_middle(struct aim_session_t *sess,
572                               struct command_rx_struct *command, ...)
573 {
574   struct aim_tlv_t *tmptlv = NULL;
575   int serviceid = 0x00;
576   char cookie[AIM_COOKIELEN];
577   char *ip = NULL;
578   rxcallback_t userfunc = NULL;
579   struct aim_tlvlist_t *tlvlist;
580   int ret = 1;
581   
582   tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10);
583   
584   tmptlv = aim_gettlv(tlvlist, 0x000d, 1);
585   serviceid = aimutil_get16(tmptlv->value);
586
587   ip = aim_gettlv_str(tlvlist, 0x0005, 1);
588   
589   tmptlv = aim_gettlv(tlvlist, 0x0006, 1);
590   memcpy(cookie, tmptlv->value, AIM_COOKIELEN);
591
592   userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
593   if (userfunc)
594     ret =  userfunc(sess, command, serviceid, ip, cookie);
595
596   aim_freetlvchain(&tlvlist);
597
598   return ret;
599 }
600
601 int aim_parse_unknown(struct aim_session_t *sess,
602                       struct command_rx_struct *command, ...)
603 {
604   u_int i = 0;
605
606   printf("\nRecieved unknown packet:");
607
608   for (i = 0; i < command->commandlen; i++)
609     {
610       if ((i % 8) == 0)
611         printf("\n\t");
612
613       printf("0x%2x ", command->data[i]);
614     }
615   
616   printf("\n\n");
617
618   return 1;
619 }
620
621
622 /*
623  * aim_parse_generalerrs()
624  *
625  * Middle handler for 0x0001 snac of each family.
626  *
627  */
628 int aim_parse_generalerrs(struct aim_session_t *sess,
629                           struct command_rx_struct *command, ...)
630 {
631   u_short family;
632   u_short subtype;
633   
634   family = aimutil_get16(command->data+0);
635   subtype= aimutil_get16(command->data+2);
636   
637   switch(family)
638     {
639     default:
640       /* Unknown family */
641       return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);
642     }
643
644   return 1;
645 }
646
647
648
This page took 0.255276 seconds and 5 git commands to generate.