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.
13 * Bleck functions get called when there's no non-bleck functions
14 * around to cleanup the mess...
16 int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...)
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);
26 int aim_conn_addhandler(struct aim_session_t *sess,
27 struct aim_conn_t *conn,
30 rxcallback_t newhandler,
33 struct aim_rxcblist_t *new,*cur;
39 printf("aim_conn_addhandler: adding for %04x/%04x\n", family, type);
42 new = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t));
47 new->handler = &bleck;
49 new->handler = newhandler;
52 cur = conn->handlerlist;
54 conn->handlerlist = new;
65 int aim_clearhandlers(struct aim_conn_t *conn)
67 struct aim_rxcblist_t *cur,*tmp;
71 cur = conn->handlerlist;
81 rxcallback_t aim_callhandler(struct aim_conn_t *conn,
85 struct aim_rxcblist_t *cur;
91 printf("aim_callhandler: calling for %04x/%04x\n", family, type);
94 cur = conn->handlerlist;
97 if ( (cur->family == family) && (cur->type == type) )
104 return aim_callhandler(conn, family, 0xffff);
107 int aim_callhandler_noparam(struct aim_session_t *sess,
108 struct aim_conn_t *conn,
111 struct command_rx_struct *ptr)
113 rxcallback_t userfunc = NULL;
114 userfunc = aim_callhandler(conn, family, type);
116 return userfunc(sess, ptr);
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
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.
137 TODO: Get rid of all the ugly if's.
139 TODO: More support for mid-level handlers.
140 TODO: Allow for NULL handlers.
143 int aim_rxdispatch(struct aim_session_t *sess)
146 struct command_rx_struct *workingPtr = NULL;
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");
153 workingPtr = sess->queue_incoming;
154 for (i = 0; workingPtr != NULL; i++)
156 switch(workingPtr->conn->type)
158 case AIM_CONN_TYPE_AUTH:
162 head = aimutil_get32(workingPtr->data);
163 if (head == 0x00000001)
166 printf("got connection ack on auth line\n");
168 workingPtr->handled = 1;
172 /* any user callbacks will be called from here */
173 workingPtr->handled = aim_authparse(sess, workingPtr);
177 case AIM_CONN_TYPE_BOS:
182 family = aimutil_get16(workingPtr->data);
183 subtype = aimutil_get16(workingPtr->data+2);
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);
191 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
193 case 0x0001: /* Family: General */
197 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
200 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
203 workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
206 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
209 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000a, workingPtr);
212 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
215 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0013, workingPtr);
218 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
221 case 0x0002: /* Family: Location */
225 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0001, workingPtr);
228 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
231 workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
234 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
237 case 0x0003: /* Family: Buddy List */
241 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
244 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0003, 0x0003, workingPtr);
246 case 0x000b: /* oncoming buddy */
247 workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
249 case 0x000c: /* offgoing buddy */
250 workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
253 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
256 case 0x0004: /* Family: Messeging */
260 workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
263 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
266 workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
269 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x000a, workingPtr);
272 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
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);
281 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
283 case 0x000a: /* Family: User lookup */
287 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr);
290 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, workingPtr);
293 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
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);
302 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
305 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
310 case AIM_CONN_TYPE_CHATNAV:
314 family = aimutil_get16(workingPtr->data);
315 subtype= aimutil_get16(workingPtr->data+2);
317 if ((family == 0x0002) && (subtype == 0x0006))
319 workingPtr->handled = 1;
320 aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
324 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
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);
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);
337 /* move to next command */
338 workingPtr = workingPtr->next;
342 sess->queue_incoming = aim_purge_rxqueue(sess->queue_incoming);
348 * TODO: check and cure memory leakage in this function.
349 * TODO: update to use new tlvlist routines
351 int aim_authparse(struct aim_session_t *sess,
352 struct command_rx_struct *command)
354 rxcallback_t userfunc = NULL;
356 struct aim_tlv_t *tlv = NULL;
357 char *errorurl = NULL;
358 short errorcode = 0x00;
360 u_short family,subtype;
362 family = aimutil_get16(command->data);
363 subtype= aimutil_get16(command->data+2);
365 if ( (family == 0x0001) &&
368 /* "server ready" -- can be ignored */
369 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY);
371 else if ( (family == 0x0007) &&
374 /* "information change reply" */
375 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY);
379 /* anything else -- usually used for login; just parse as pure TLVs */
382 * Free up the loginstruct first.
384 sess->logininfo.screen_name[0] = '\0';
385 if (sess->logininfo.BOSIP)
387 free(sess->logininfo.BOSIP);
388 sess->logininfo.BOSIP = NULL;
390 if (sess->logininfo.email)
392 free(sess->logininfo.email);
393 sess->logininfo.email = NULL;
395 sess->logininfo.regstatus = 0;
397 /* all this block does is figure out if it's an
398 error or a success, nothing more */
399 while (z < command->commandlen)
401 tlv = aim_grabtlvstr(&(command->data[z]));
404 case 0x0001: /* screen name */
405 if (tlv->length >= MAXSNLEN)
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);
412 strncpy(sess->logininfo.screen_name, tlv->value, tlv->length);
413 z += 2 + 2 + tlv->length;
417 case 0x0004: /* error URL */
418 errorurl = tlv->value;
419 z += 2 + 2 + tlv->length;
423 case 0x0005: /* BOS IP */
424 sess->logininfo.BOSIP = tlv->value;
425 z += 2 + 2 + tlv->length;
429 case 0x0006: /* auth cookie */
430 memcpy(sess->logininfo.cookie, tlv->value, AIM_COOKIELEN);
431 z += 2 + 2 + tlv->length;
435 case 0x0011: /* email addy */
436 sess->logininfo.email = tlv->value;
437 z += 2 + 2 + tlv->length;
441 case 0x0013: /* registration status */
442 sess->logininfo.regstatus = *(tlv->value);
443 z += 2 + 2 + tlv->length;
446 case 0x0008: /* error code */
447 errorcode = *(tlv->value);
448 z += 2 + 2 + tlv->length;
453 z += 2 + 2 + tlv->length;
462 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_ERROR);
464 return userfunc(sess, command, errorurl, errorcode);
467 else if (sess->logininfo.screen_name[0] &&
468 sess->logininfo.cookie[0] && sess->logininfo.BOSIP)
470 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHSUCCESS);
472 return userfunc(sess, command);
476 userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHOTHER);
480 return userfunc(sess, command);
481 printf("handler not available!\n");
486 * TODO: check for and cure any memory leaks here.
488 int aim_handleredirect_middle(struct aim_session_t *sess,
489 struct command_rx_struct *command, ...)
491 struct aim_tlv_t *tlv = NULL;
493 int serviceid = 0x00;
496 rxcallback_t userfunc = NULL;
498 while (z < command->commandlen)
500 tlv = aim_grabtlvstr(&(command->data[z]));
503 case 0x000d: /* service id */
505 /* regrab as an int */
506 tlv = aim_grabtlv(&(command->data[z]));
507 serviceid = aimutil_get16(tlv->value);
508 z += 2 + 2 + tlv->length;
511 case 0x0005: /* service server IP */
513 z += 2 + 2 + tlv->length;
517 case 0x0006: /* auth cookie */
519 z += 2 + 2 + tlv->length;
525 z += 2 + 2 + tlv->length;
529 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
531 return userfunc(sess, command, serviceid, ip, cookie);
535 int aim_parse_unknown(struct aim_session_t *sess,
536 struct command_rx_struct *command, ...)
540 printf("\nRecieved unknown packet:");
542 for (i = 0; i < command->commandlen; i++)
547 printf("0x%2x ", command->data[i]);
557 * aim_parse_generalerrs()
559 * Middle handler for 0x0001 snac of each family.
562 int aim_parse_generalerrs(struct aim_session_t *sess,
563 struct command_rx_struct *command, ...)
568 family = aimutil_get16(command->data+0);
569 subtype= aimutil_get16(command->data+2);
575 return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);