comparison libfaim/aim_rxhandlers.c @ 2:68b230f8da5f

[gaim-migrate @ 11] A few more commits :) committer: Tailor Script <tailor@pidgin.im>
author Rob Flynn <gaim@robflynn.com>
date Thu, 23 Mar 2000 03:16:06 +0000
parents
children 6ced2f1c8b24
comparison
equal deleted inserted replaced
1:2846a03bda67 2:68b230f8da5f
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