2
|
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 int bleck(struct command_rx_struct *param, ...)
|
|
15 {
|
|
16 return 1;
|
|
17 }
|
|
18
|
|
19 /*
|
|
20 * The callbacks. Used to pass data up from the wire into the client.
|
|
21 *
|
|
22 * TODO: MASSIVE OVERHAUL. This method of doing it (array of function
|
|
23 * pointers) is ugly. Overhaul may mean including chained callbacks
|
|
24 * for having client features such as run-time loadable modules.
|
|
25 *
|
|
26 */
|
|
27 rxcallback_t aim_callbacks[] = {
|
|
28 bleck, /* incoming IM */
|
|
29 bleck, /* oncoming buddy */
|
|
30 bleck, /* offgoing buddy */
|
|
31 bleck, /* messaging error */
|
|
32 bleck, /* server missed call */
|
|
33 bleck, /* login phase 4 packet C command 1*/
|
|
34 bleck, /* login phase 4 packet C command 2 */
|
|
35 bleck, /* login phase 2, first resp */
|
|
36 bleck, /* login phase 2, second resp -- **REQUIRED** */
|
|
37 bleck, /* login phase 3 packet B */
|
|
38 bleck, /* login phase 3D packet A */
|
|
39 bleck, /* login phase 3D packet B */
|
|
40 bleck, /* login phase 3D packet C */
|
|
41 bleck, /* login phase 3D packet D */
|
|
42 bleck, /* login phase 3D packet E */
|
|
43 bleck, /* redirect -- **REQUIRED** */
|
|
44 bleck, /* server rate change */
|
|
45 bleck, /* user location error */
|
|
46 aim_parse_unknown, /* completely unknown command */
|
|
47 bleck, /* User Info Response */
|
|
48 bleck, /* User Search by Address response */
|
|
49 bleck, /* User Search by Name response */
|
|
50 bleck, /* user search fail */
|
|
51 bleck, /* auth error */
|
|
52 bleck, /* auth success */
|
|
53 bleck, /* auth server ready */
|
|
54 bleck, /* auth other */
|
|
55 bleck, /* info change reply */
|
|
56 bleck, /* ChatNAV: server ready */
|
|
57 0x00
|
|
58 };
|
|
59
|
|
60
|
|
61 int aim_register_callbacks(rxcallback_t *newcallbacks)
|
|
62 {
|
|
63 int i = 0;
|
|
64
|
|
65 for (i = 0; aim_callbacks[i] != 0x00; i++)
|
|
66 {
|
|
67 if ( (newcallbacks[i] != NULL) &&
|
|
68 (newcallbacks[i] != 0x00) )
|
|
69 {
|
|
70 #if debug > 3
|
|
71 printf("aim_register_callbacks: changed handler %d\n", i);
|
|
72 #endif
|
|
73 aim_callbacks[i] = newcallbacks[i];
|
|
74 }
|
|
75 }
|
|
76
|
|
77 return 0;
|
|
78 }
|
|
79
|
|
80 /*
|
|
81 aim_rxdispatch()
|
|
82
|
|
83 Basically, heres what this should do:
|
|
84 1) Determine correct packet handler for this packet
|
|
85 2) Mark the packet handled (so it can be dequeued in purge_queue())
|
|
86 3) Send the packet to the packet handler
|
|
87 4) Go to next packet in the queue and start over
|
|
88 5) When done, run purge_queue() to purge handled commands
|
|
89
|
|
90 Note that any unhandlable packets should probably be left in the
|
|
91 queue. This is the best way to prevent data loss. This means
|
|
92 that a single packet may get looked at by this function multiple
|
|
93 times. This is more good than bad! This behavior may change.
|
|
94
|
|
95 Aren't queue's fun?
|
|
96
|
|
97 TODO: Get rid of all the ugly if's.
|
|
98 TODO: Clean up.
|
|
99 TODO: More support for mid-level handlers.
|
|
100 TODO: Allow for NULL handlers.
|
|
101
|
|
102 */
|
|
103 int aim_rxdispatch(void)
|
|
104 {
|
|
105 int i = 0;
|
|
106 struct command_rx_struct *workingPtr = NULL;
|
|
107
|
|
108 if (aim_queue_incoming == NULL)
|
|
109 /* this shouldn't really happen, unless the main loop's select is broke */
|
|
110 printf("parse_generic: incoming packet queue empty.\n");
|
|
111 else
|
|
112 {
|
|
113 workingPtr = aim_queue_incoming;
|
|
114 for (i = 0; workingPtr != NULL; i++)
|
|
115 {
|
|
116 switch(workingPtr->conn->type)
|
|
117 {
|
|
118 case AIM_CONN_TYPE_AUTH:
|
|
119 if ( (workingPtr->data[0] == 0x00) &&
|
|
120 (workingPtr->data[1] == 0x00) &&
|
|
121 (workingPtr->data[2] == 0x00) &&
|
|
122 (workingPtr->data[3] == 0x01) )
|
|
123 {
|
|
124 #if debug > 0
|
|
125 fprintf(stderr, "got connection ack on auth line\n");
|
|
126 #endif
|
|
127 workingPtr->handled = 1;
|
|
128 }
|
|
129 else
|
|
130 {
|
|
131 /* any user callbacks will be called from here */
|
|
132 workingPtr->handled = aim_authparse(workingPtr);
|
|
133 }
|
|
134 break;
|
|
135 case AIM_CONN_TYPE_BOS:
|
|
136 {
|
|
137 u_short family;
|
|
138 u_short subtype;
|
|
139 family = (workingPtr->data[0] << 8) + workingPtr->data[1];
|
|
140 subtype = (workingPtr->data[2] << 8) + workingPtr->data[3];
|
|
141 switch (family)
|
|
142 {
|
|
143 case 0x0000: /* not really a family, but it works */
|
|
144 if (subtype == 0x0001)
|
|
145 workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P2_1])(workingPtr);
|
|
146 else
|
|
147 workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
|
|
148 break;
|
|
149 case 0x0001: /* Family: General */
|
|
150 switch (subtype)
|
|
151 {
|
|
152 case 0x0001:
|
|
153 workingPtr->handled = aim_parse_generalerrs(workingPtr);
|
|
154 break;
|
|
155 case 0x0003:
|
|
156 workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P2_2])(workingPtr);
|
|
157 break;
|
|
158 case 0x0005:
|
|
159 workingPtr->handled = aim_handleredirect_middle(workingPtr);
|
|
160 break;
|
|
161 case 0x0007:
|
|
162 workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3_B])(workingPtr);
|
|
163 break;
|
|
164 case 0x000a:
|
|
165 workingPtr->handled = (aim_callbacks[AIM_CB_RATECHANGE])(workingPtr);
|
|
166 break;
|
|
167 case 0x000f:
|
|
168 workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_A])(workingPtr);
|
|
169 break;
|
|
170 case 0x0013:
|
|
171 workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P4_C2])(workingPtr);
|
|
172 break;
|
|
173 default:
|
|
174 workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
|
|
175 }
|
|
176 break;
|
|
177 case 0x0002: /* Family: Location */
|
|
178 switch (subtype)
|
|
179 {
|
|
180 case 0x0001:
|
|
181 workingPtr->handled = (aim_callbacks[AIM_CB_MISSED_IM])(workingPtr);
|
|
182 break;
|
|
183 case 0x0003:
|
|
184 workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_D])(workingPtr);
|
|
185 break;
|
|
186 case 0x0006:
|
|
187 workingPtr->handled = aim_parse_userinfo_middle(workingPtr);
|
|
188 break;
|
|
189 default:
|
|
190 workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
|
|
191 }
|
|
192 break;
|
|
193 case 0x0003: /* Family: Buddy List */
|
|
194 switch (subtype)
|
|
195 {
|
|
196 case 0x0001:
|
|
197 workingPtr->handled = aim_parse_generalerrs(workingPtr);
|
|
198 break;
|
|
199 case 0x0003:
|
|
200 workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_C])(workingPtr);
|
|
201 break;
|
|
202 case 0x000b:
|
|
203 workingPtr->handled = (aim_callbacks[AIM_CB_ONCOMING_BUDDY])(workingPtr);
|
|
204 break;
|
|
205 case 0x000c:
|
|
206 workingPtr->handled = (aim_callbacks[AIM_CB_OFFGOING_BUDDY])(workingPtr);
|
|
207 break;
|
|
208 default:
|
|
209 workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
|
|
210 }
|
|
211 break;
|
|
212 case 0x0004: /* Family: Messeging */
|
|
213 switch (subtype)
|
|
214 {
|
|
215 case 0x0001:
|
|
216 workingPtr->handled = (aim_callbacks[AIM_CB_USERERROR])(workingPtr);
|
|
217 break;
|
|
218 case 0x0005:
|
|
219 workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_E])(workingPtr);
|
|
220 break;
|
|
221 case 0x0007:
|
|
222 workingPtr->handled = aim_parse_incoming_im_middle(workingPtr);
|
|
223 break;
|
|
224 case 0x000a:
|
|
225 workingPtr->handled = (aim_callbacks[AIM_CB_MISSED_CALL])(workingPtr);
|
|
226 break;
|
|
227 default:
|
|
228 workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
|
|
229 }
|
|
230 break;
|
|
231 case 0x0009:
|
|
232 if (subtype == 0x0001)
|
|
233 workingPtr->handled = aim_parse_generalerrs(workingPtr);
|
|
234 else if (subtype == 0x0003)
|
|
235 workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P3D_B])(workingPtr);
|
|
236 else
|
|
237 workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
|
|
238 break;
|
|
239 case 0x000a: /* Family: User lookup */
|
|
240 switch (subtype)
|
|
241 {
|
|
242 case 0x0001:
|
|
243 workingPtr->handled = (aim_callbacks[AIM_CB_SEARCH_FAIL])(workingPtr);
|
|
244 break;
|
|
245 case 0x0003:
|
|
246 workingPtr->handled = (aim_callbacks[AIM_CB_SEARCH_ADDRESS])(workingPtr);
|
|
247 break;
|
|
248 default:
|
|
249 workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
|
|
250 }
|
|
251 break;
|
|
252 case 0x000b:
|
|
253 if (subtype == 0x0001)
|
|
254 workingPtr->handled = aim_parse_generalerrs(workingPtr);
|
|
255 else if (subtype == 0x0002)
|
|
256 workingPtr->handled = (aim_callbacks[AIM_CB_LOGIN_P4_C1])(workingPtr);
|
|
257 else
|
|
258 workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
|
|
259 break;
|
|
260 default:
|
|
261 workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
|
|
262 break;
|
|
263 }
|
|
264 }
|
|
265 break;
|
|
266 case AIM_CONN_TYPE_CHATNAV:
|
|
267 if ( (workingPtr->data[0] == 0x00) &&
|
|
268 (workingPtr->data[1] == 0x02) &&
|
|
269 (workingPtr->data[2] == 0x00) &&
|
|
270 (workingPtr->data[3] == 0x06) )
|
|
271 {
|
|
272 workingPtr->handled = 1;
|
|
273 aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
|
|
274 }
|
|
275 else
|
|
276 workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
|
|
277 break;
|
|
278 case AIM_CONN_TYPE_CHAT:
|
|
279 fprintf(stderr, "\nAHH! Dont know what to do with CHAT stuff yet!\n");
|
|
280 workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
|
|
281 break;
|
|
282 default:
|
|
283 fprintf(stderr, "\nAHHHHH! UNKNOWN CONNECTION TYPE!\n\n");
|
|
284 workingPtr->handled = (aim_callbacks[AIM_CB_UNKNOWN])(workingPtr);
|
|
285 break;
|
|
286 }
|
|
287 /* move to next command */
|
|
288 workingPtr = workingPtr->next;
|
|
289 }
|
|
290 }
|
|
291
|
|
292 aim_queue_incoming = aim_purge_rxqueue(aim_queue_incoming);
|
|
293
|
|
294 return 0;
|
|
295 }
|
|
296
|
|
297 /*
|
|
298 * TODO: check and cure memory leakage in this function.
|
|
299 */
|
|
300 int aim_authparse(struct command_rx_struct *command)
|
|
301 {
|
|
302 int iserror = 0;
|
|
303 struct aim_tlv_t *tlv = NULL;
|
|
304 char *errorurl = NULL;
|
|
305 short errorcode;
|
|
306 int z = 0;
|
|
307
|
|
308 if ( (command->data[0] == 0x00) &&
|
|
309 (command->data[1] == 0x01) &&
|
|
310 (command->data[2] == 0x00) &&
|
|
311 (command->data[3] == 0x03) )
|
|
312 {
|
|
313 /* "server ready" -- can be ignored */
|
|
314 return (aim_callbacks[AIM_CB_AUTH_SVRREADY])(command);
|
|
315 }
|
|
316 else if ( (command->data[0] == 0x00) &&
|
|
317 (command->data[1] == 0x07) &&
|
|
318 (command->data[2] == 0x00) &&
|
|
319 (command->data[3] == 0x05) )
|
|
320 {
|
|
321 /* "information change reply" */
|
|
322 return (aim_callbacks[AIM_CB_AUTH_INFOCHNG_REPLY])(command);
|
|
323 }
|
|
324 else
|
|
325 {
|
|
326 /* anything else -- usually used for login; just parse as pure TLVs */
|
|
327
|
|
328
|
|
329 /* all this block does is figure out if it's an
|
|
330 error or a success, nothing more */
|
|
331 while (z < command->commandlen)
|
|
332 {
|
|
333 tlv = aim_grabtlvstr(&(command->data[z]));
|
|
334 switch(tlv->type)
|
|
335 {
|
|
336 case 0x0001: /* screen name */
|
|
337 aim_logininfo.screen_name = tlv->value;
|
|
338 z += 2 + 2 + tlv->length;
|
|
339 free(tlv);
|
|
340 tlv = NULL;
|
|
341 break;
|
|
342 case 0x0004: /* error URL */
|
|
343 errorurl = tlv->value;
|
|
344 z += 2 + 2 + tlv->length;
|
|
345 free(tlv);
|
|
346 tlv = NULL;
|
|
347 break;
|
|
348 case 0x0005: /* BOS IP */
|
|
349 aim_logininfo.BOSIP = tlv->value;
|
|
350 z += 2 + 2 + tlv->length;
|
|
351 free(tlv);
|
|
352 tlv = NULL;
|
|
353 break;
|
|
354 case 0x0006: /* auth cookie */
|
|
355 aim_logininfo.cookie = tlv->value;
|
|
356 z += 2 + 2 + tlv->length;
|
|
357 free(tlv);
|
|
358 tlv=NULL;
|
|
359 break;
|
|
360 case 0x0011: /* email addy */
|
|
361 aim_logininfo.email = tlv->value;
|
|
362 z += 2 + 2 + tlv->length;
|
|
363 free(tlv);
|
|
364 tlv = NULL;
|
|
365 break;
|
|
366 case 0x0013: /* registration status */
|
|
367 aim_logininfo.regstatus = *(tlv->value);
|
|
368 z += 2 + 2 + tlv->length;
|
|
369 aim_freetlv(&tlv);
|
|
370 break;
|
|
371 case 0x0008: /* error code */
|
|
372 errorcode = *(tlv->value);
|
|
373 z += 2 + 2 + tlv->length;
|
|
374 aim_freetlv(&tlv);
|
|
375 iserror = 1;
|
|
376 break;
|
|
377 default:
|
|
378 z += 2 + 2 + tlv->length;
|
|
379 aim_freetlv(&tlv);
|
|
380 /* dunno */
|
|
381 }
|
|
382 }
|
|
383
|
|
384 if (iserror &&
|
|
385 errorurl &&
|
|
386 errorcode)
|
|
387 return (aim_callbacks[AIM_CB_AUTH_ERROR])(command, &aim_logininfo, errorurl, errorcode);
|
|
388 else if (aim_logininfo.screen_name &&
|
|
389 aim_logininfo.cookie && aim_logininfo.BOSIP)
|
|
390 return (aim_callbacks[AIM_CB_AUTH_SUCCESS])(command, &aim_logininfo);
|
|
391 else
|
|
392 return (aim_callbacks[AIM_CB_AUTH_OTHER])(command);
|
|
393 }
|
|
394 }
|
|
395
|
|
396 /*
|
|
397 * TODO: check for and cure any memory leaks here.
|
|
398 */
|
|
399 int aim_handleredirect_middle(struct command_rx_struct *command, ...)
|
|
400 {
|
|
401 struct aim_tlv_t *tlv = NULL;
|
|
402 int z = 10;
|
|
403 int serviceid;
|
|
404 char *cookie;
|
|
405 char *ip;
|
|
406
|
|
407 while (z < command->commandlen)
|
|
408 {
|
|
409 tlv = aim_grabtlvstr(&(command->data[z]));
|
|
410 switch(tlv->type)
|
|
411 {
|
|
412 case 0x000d: /* service id */
|
|
413 aim_freetlv(&tlv);
|
|
414 /* regrab as an int */
|
|
415 tlv = aim_grabtlv(&(command->data[z]));
|
|
416 serviceid = (tlv->value[0] << 8) + tlv->value[1]; /* hehe */
|
|
417 z += 2 + 2 + tlv->length;
|
|
418 aim_freetlv(&tlv);
|
|
419 break;
|
|
420 case 0x0005: /* service server IP */
|
|
421 ip = tlv->value;
|
|
422 z += 2 + 2 + tlv->length;
|
|
423 free(tlv);
|
|
424 tlv = NULL;
|
|
425 break;
|
|
426 case 0x0006: /* auth cookie */
|
|
427 cookie = tlv->value;
|
|
428 z += 2 + 2 + tlv->length;
|
|
429 free(tlv);
|
|
430 tlv = NULL;
|
|
431 break;
|
|
432 default:
|
|
433 /* dunno */
|
|
434 z += 2 + 2 + tlv->length;
|
|
435 aim_freetlv(&tlv);
|
|
436 }
|
|
437 }
|
|
438 return (aim_callbacks[AIM_CB_LOGIN_P3D_F])(command, serviceid, ip, cookie);
|
|
439 }
|
|
440
|
|
441 int aim_parse_unknown(struct command_rx_struct *command, ...)
|
|
442 {
|
|
443 int i = 0;
|
|
444
|
|
445 printf("\nRecieved unknown packet:");
|
|
446
|
|
447 for (i = 0; i < command->commandlen; i++)
|
|
448 {
|
|
449 if ((i % 8) == 0)
|
|
450 printf("\n\t");
|
|
451
|
|
452 printf("0x%2x ", command->data[i]);
|
|
453 }
|
|
454
|
|
455 printf("\n\n");
|
|
456
|
|
457 return 1;
|
|
458 }
|
|
459
|
|
460
|
|
461 /*
|
|
462 * aim_parse_generalerrs()
|
|
463 *
|
|
464 * Middle handler for 0x0001 snac of each family.
|
|
465 *
|
|
466 */
|
|
467 int aim_parse_generalerrs(struct command_rx_struct *command, ...)
|
|
468 {
|
|
469 u_short family;
|
|
470 u_short subtype;
|
|
471 family = (command->data[0] << 8) + command->data[1];
|
|
472 subtype = (command->data[2] << 8) + command->data[3];
|
|
473
|
|
474 switch(family)
|
|
475 {
|
|
476 default:
|
|
477 /* Unknown family */
|
|
478 return (aim_callbacks[AIM_CB_UNKNOWN])(command);
|
|
479 }
|
|
480
|
|
481 return 1;
|
|
482 }
|
|
483
|
|
484
|
|
485
|