comparison libfaim/aim_rxhandlers.c @ 237:6ced2f1c8b24

[gaim-migrate @ 247] How cool is this, libfaim is making a comeback. I completely redid everything, as was necessary because of the updates to libfaim since gaim 0.9.7. You can sign on and send/recv IMs, but there's a bad lag between display updates that I haven't figured out how to fix yet. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Sat, 20 May 2000 00:30:53 +0000
parents 68b230f8da5f
children 1eeece1c7b7b
comparison
equal deleted inserted replaced
236:62d470738cc7 237:6ced2f1c8b24
1
2 /* 1 /*
3 aim_rxhandlers.c 2 * 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 * 3 *
22 * TODO: MASSIVE OVERHAUL. This method of doing it (array of function 4 * This file contains most all of the incoming packet handlers, along
23 * pointers) is ugly. Overhaul may mean including chained callbacks 5 * with aim_rxdispatch(), the Rx dispatcher. Queue/list management is
24 * for having client features such as run-time loadable modules. 6 * actually done in aim_rxqueue.c.
25 * 7 *
26 */ 8 */
27 rxcallback_t aim_callbacks[] = { 9
28 bleck, /* incoming IM */ 10 #include <aim.h>
29 bleck, /* oncoming buddy */ 11
30 bleck, /* offgoing buddy */ 12 /*
31 bleck, /* messaging error */ 13 * Bleck functions get called when there's no non-bleck functions
32 bleck, /* server missed call */ 14 * around to cleanup the mess...
33 bleck, /* login phase 4 packet C command 1*/ 15 */
34 bleck, /* login phase 4 packet C command 2 */ 16 int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...)
35 bleck, /* login phase 2, first resp */ 17 {
36 bleck, /* login phase 2, second resp -- **REQUIRED** */ 18 u_short family;
37 bleck, /* login phase 3 packet B */ 19 u_short subtype;
38 bleck, /* login phase 3D packet A */ 20
39 bleck, /* login phase 3D packet B */ 21 u_short maxf;
40 bleck, /* login phase 3D packet C */ 22 u_short maxs;
41 bleck, /* login phase 3D packet D */ 23
42 bleck, /* login phase 3D packet E */ 24 /* XXX: this is ugly. and big just for debugging. */
43 bleck, /* redirect -- **REQUIRED** */ 25 char *literals[14][25] = {
44 bleck, /* server rate change */ 26 {"Invalid",
45 bleck, /* user location error */ 27 NULL
46 aim_parse_unknown, /* completely unknown command */ 28 },
47 bleck, /* User Info Response */ 29 {"General",
48 bleck, /* User Search by Address response */ 30 "Invalid",
49 bleck, /* User Search by Name response */ 31 "Error",
50 bleck, /* user search fail */ 32 "Client Ready",
51 bleck, /* auth error */ 33 "Server Ready",
52 bleck, /* auth success */ 34 "Service Request",
53 bleck, /* auth server ready */ 35 "Redirect",
54 bleck, /* auth other */ 36 "Rate Information Request",
55 bleck, /* info change reply */ 37 "Rate Information",
56 bleck, /* ChatNAV: server ready */ 38 "Rate Information Ack",
57 0x00 39 NULL,
58 }; 40 "Rate Information Change",
59 41 "Server Pause",
60 42 NULL,
61 int aim_register_callbacks(rxcallback_t *newcallbacks) 43 "Server Resume",
62 { 44 "Request Personal User Information",
63 int i = 0; 45 "Personal User Information",
64 46 "Evil Notification",
65 for (i = 0; aim_callbacks[i] != 0x00; i++) 47 NULL,
66 { 48 "Migration notice",
67 if ( (newcallbacks[i] != NULL) && 49 "Message of the Day",
68 (newcallbacks[i] != 0x00) ) 50 "Set Privacy Flags",
69 { 51 "Well Known URL",
70 #if debug > 3 52 "NOP"
71 printf("aim_register_callbacks: changed handler %d\n", i); 53 },
72 #endif 54 {"Location",
73 aim_callbacks[i] = newcallbacks[i]; 55 "Invalid",
74 } 56 "Error",
75 } 57 "Request Rights",
76 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 faimdprintf(1, "aim_conn_addhandler: adding for %04x/%04x\n", family, type);
197
198 new = (struct aim_rxcblist_t *)calloc(1, sizeof(struct aim_rxcblist_t));
199 new->family = family;
200 new->type = type;
201 new->flags = flags;
202 if (!newhandler)
203 new->handler = &bleck;
204 else
205 new->handler = newhandler;
206 new->next = NULL;
207
208 cur = conn->handlerlist;
209 if (!cur)
210 conn->handlerlist = new;
211 else
212 {
213 while (cur->next)
214 cur = cur->next;
215 cur->next = new;
216 }
217
77 return 0; 218 return 0;
219 }
220
221 int aim_clearhandlers(struct aim_conn_t *conn)
222 {
223 struct aim_rxcblist_t *cur,*tmp;
224 if (!conn)
225 return -1;
226
227 cur = conn->handlerlist;
228 while(cur)
229 {
230 tmp = cur->next;
231 free(cur);
232 cur = tmp;
233 }
234 return 0;
235 }
236
237 rxcallback_t aim_callhandler(struct aim_conn_t *conn,
238 u_short family,
239 u_short type)
240 {
241 struct aim_rxcblist_t *cur;
242
243 if (!conn)
244 return NULL;
245
246 faimdprintf(1, "aim_callhandler: calling for %04x/%04x\n", family, type);
247
248 cur = conn->handlerlist;
249 while(cur)
250 {
251 if ( (cur->family == family) && (cur->type == type) )
252 return cur->handler;
253 cur = cur->next;
254 }
255
256 if (type==0xffff)
257 return NULL;
258 return aim_callhandler(conn, family, 0xffff);
259 }
260
261 int aim_callhandler_noparam(struct aim_session_t *sess,
262 struct aim_conn_t *conn,
263 u_short family,
264 u_short type,
265 struct command_rx_struct *ptr)
266 {
267 rxcallback_t userfunc = NULL;
268 userfunc = aim_callhandler(conn, family, type);
269 if (userfunc)
270 return userfunc(sess, ptr);
271 return 1; /* XXX */
78 } 272 }
79 273
80 /* 274 /*
81 aim_rxdispatch() 275 aim_rxdispatch()
82 276
98 TODO: Clean up. 292 TODO: Clean up.
99 TODO: More support for mid-level handlers. 293 TODO: More support for mid-level handlers.
100 TODO: Allow for NULL handlers. 294 TODO: Allow for NULL handlers.
101 295
102 */ 296 */
103 int aim_rxdispatch(void) 297 int aim_rxdispatch(struct aim_session_t *sess)
104 { 298 {
105 int i = 0; 299 int i = 0;
106 struct command_rx_struct *workingPtr = NULL; 300 struct command_rx_struct *workingPtr = NULL;
107 301
108 if (aim_queue_incoming == NULL) 302 if (sess->queue_incoming == NULL) {
109 /* this shouldn't really happen, unless the main loop's select is broke */ 303 faimdprintf(1, "parse_generic: incoming packet queue empty.\n");
110 printf("parse_generic: incoming packet queue empty.\n"); 304 return 0;
111 else 305 } else {
112 { 306 workingPtr = sess->queue_incoming;
113 workingPtr = aim_queue_incoming; 307 for (i = 0; workingPtr != NULL; workingPtr = workingPtr->next, i++) {
114 for (i = 0; workingPtr != NULL; i++) 308 /*
115 { 309 * XXX: This is still fairly ugly.
116 switch(workingPtr->conn->type) 310 */
117 { 311 if (workingPtr->handled)
118 case AIM_CONN_TYPE_AUTH: 312 continue;
119 if ( (workingPtr->data[0] == 0x00) && 313
120 (workingPtr->data[1] == 0x00) && 314 switch(workingPtr->conn->type) {
121 (workingPtr->data[2] == 0x00) && 315 case -1:
122 (workingPtr->data[3] == 0x01) ) 316 /*
123 { 317 * This can happen if we have a queued command
124 #if debug > 0 318 * that was recieved after a connection has
125 fprintf(stderr, "got connection ack on auth line\n"); 319 * been terminated. In which case, the handler
320 * list has been cleared, and there's nothing we
321 * can do for it. We can only cancel it.
322 */
323 workingPtr->handled = 1;
324 break;
325 case AIM_CONN_TYPE_AUTH: {
326 u_long head;
327
328 head = aimutil_get32(workingPtr->data);
329 if (head == 0x00000001) {
330 faimdprintf(1, "got connection ack on auth line\n");
331 workingPtr->handled = 1;
332 } else {
333 u_short family,subtype;
334
335 family = aimutil_get16(workingPtr->data);
336 subtype = aimutil_get16(workingPtr->data+2);
337
338 switch (family) {
339 /* New login protocol */
340 #ifdef SNACLOGIN
341 case 0x0017:
342 if (subtype == 0x0001)
343 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr);
344 else if (subtype == 0x0003)
345 workingPtr->handled = aim_authparse(sess, workingPtr);
346 else if (subtype == 0x0007)
347 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0007, workingPtr);
348 else
349 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr);
350 break;
351 #else
352 /* XXX: this isnt foolproof */
353 case 0x0001:
354 if (subtype == 0x0003)
355 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, workingPtr);
356 else
357 workingPtr->handled = aim_authparse(sess, workingPtr);
358 break;
359 case 0x0007:
360 if (subtype == 0x0005)
361 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr);
362 break;
363 default:
364 /* Old login protocol */
365 /* any user callbacks will be called from here */
366 workingPtr->handled = aim_authparse(sess, workingPtr);
126 #endif 367 #endif
127 workingPtr->handled = 1; 368 }
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 } 369 }
290 } 370 break;
291 371 }
292 aim_queue_incoming = aim_purge_rxqueue(aim_queue_incoming); 372 case AIM_CONN_TYPE_BOS: {
293 373 u_short family;
294 return 0; 374 u_short subtype;
295 } 375
296 376 family = aimutil_get16(workingPtr->data);
297 /* 377 subtype = aimutil_get16(workingPtr->data+2);
298 * TODO: check and cure memory leakage in this function. 378
299 */ 379 switch (family) {
300 int aim_authparse(struct command_rx_struct *command) 380 case 0x0000: /* not really a family, but it works */
301 { 381 if (subtype == 0x0001)
302 int iserror = 0; 382 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
303 struct aim_tlv_t *tlv = NULL; 383 else
304 char *errorurl = NULL; 384 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
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; 385 break;
420 case 0x0005: /* service server IP */ 386 case 0x0001: /* Family: General */
421 ip = tlv->value; 387 switch (subtype) {
422 z += 2 + 2 + tlv->length; 388 case 0x0001:
423 free(tlv); 389 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
424 tlv = NULL; 390 break;
391 case 0x0003:
392 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
393 break;
394 case 0x0005:
395 workingPtr->handled = aim_handleredirect_middle(sess, workingPtr);
396 break;
397 case 0x0007:
398 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
399 break;
400 case 0x000a:
401 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000a, workingPtr);
402 break;
403 case 0x000f:
404 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr);
405 break;
406 case 0x0013:
407 workingPtr->handled = aim_parsemotd_middle(sess, workingPtr);
408 break;
409 default:
410 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr);
411 break;
412 }
413 case 0x0002: /* Family: Location */
414 switch (subtype) {
415 case 0x0001:
416 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0001, workingPtr);
417 break;
418 case 0x0003:
419 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0002, 0x0003, workingPtr);
420 break;
421 case 0x0006:
422 workingPtr->handled = aim_parse_userinfo_middle(sess, workingPtr);
423 break;
424 default:
425 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOC, AIM_CB_LOC_DEFAULT, workingPtr);
426 break;
427 }
428 case 0x0003: /* Family: Buddy List */
429 switch (subtype) {
430 case 0x0001:
431 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
432 break;
433 case 0x0003:
434 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0003, 0x0003, workingPtr);
435 break;
436 case 0x000b: /* oncoming buddy */
437 workingPtr->handled = aim_parse_oncoming_middle(sess, workingPtr);
438 break;
439 case 0x000c: /* offgoing buddy */
440 workingPtr->handled = aim_parse_offgoing_middle(sess, workingPtr);
441 break;
442 default:
443 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BUD, AIM_CB_BUD_DEFAULT, workingPtr);
444 }
425 break; 445 break;
426 case 0x0006: /* auth cookie */ 446 case 0x0004: /* Family: Messeging */
427 cookie = tlv->value; 447 switch (subtype) {
428 z += 2 + 2 + tlv->length; 448 case 0x0001:
429 free(tlv); 449 workingPtr->handled = aim_parse_msgerror_middle(sess, workingPtr);
430 tlv = NULL; 450 break;
451 case 0x0005:
452 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr);
453 break;
454 case 0x0007:
455 workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr);
456 break;
457 case 0x000a:
458 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x000a, workingPtr);
459 break;
460 default:
461 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_DEFAULT, workingPtr);
462 }
463 break;
464 case 0x0009:
465 if (subtype == 0x0001)
466 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
467 else if (subtype == 0x0003)
468 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0009, 0x0003, workingPtr);
469 else
470 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_BOS, AIM_CB_BOS_DEFAULT, workingPtr);
471 break;
472 case 0x000a: /* Family: User lookup */
473 switch (subtype) {
474 case 0x0001:
475 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0001, workingPtr);
476 break;
477 case 0x0003:
478 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000a, 0x0003, workingPtr);
479 break;
480 default:
481 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_LOK, AIM_CB_LOK_DEFAULT, workingPtr);
482 }
483 break;
484 case 0x000b:
485 if (subtype == 0x0001)
486 workingPtr->handled = aim_parse_generalerrs(sess, workingPtr);
487 else if (subtype == 0x0002)
488 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x000b, 0x0002, workingPtr);
489 else
490 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr);
431 break; 491 break;
432 default: 492 default:
433 /* dunno */ 493 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
434 z += 2 + 2 + tlv->length; 494 break;
435 aim_freetlv(&tlv);
436 } 495 }
437 } 496 break;
438 return (aim_callbacks[AIM_CB_LOGIN_P3D_F])(command, serviceid, ip, cookie); 497 }
439 } 498 case AIM_CONN_TYPE_CHATNAV: {
440 499 u_short family;
441 int aim_parse_unknown(struct command_rx_struct *command, ...) 500 u_short subtype;
442 { 501 family = aimutil_get16(workingPtr->data);
443 int i = 0; 502 subtype= aimutil_get16(workingPtr->data+2);
444 503
445 printf("\nRecieved unknown packet:"); 504 if ((family == 0x0002) && (subtype == 0x0006)) {
505 workingPtr->handled = 1;
506 aim_conn_setstatus(workingPtr->conn, AIM_CONN_STATUS_READY);
507 } else if ((family == 0x000d) && (subtype == 0x0009)) {
508 workingPtr->handled = aim_chatnav_parse_info(sess, workingPtr);
509 } else {
510 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr);
511 }
512 break;
513 }
514 case AIM_CONN_TYPE_CHAT: {
515 u_short family, subtype;
516
517 family = aimutil_get16(workingPtr->data);
518 subtype= aimutil_get16(workingPtr->data+2);
519
520 if ((family == 0x0000) && (subtype == 0x00001))
521 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0000, 0x0001, workingPtr);
522 else if (family == 0x0001) {
523 if (subtype == 0x0001)
524 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0001, workingPtr);
525 else if (subtype == 0x0003)
526 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0003, workingPtr);
527 else if (subtype == 0x0007)
528 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0007, workingPtr);
529 else
530 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
531 } else if (family == 0x000e) {
532 if (subtype == 0x0002)
533 workingPtr->handled = aim_chat_parse_infoupdate(sess, workingPtr);
534 else if (subtype == 0x0003)
535 workingPtr->handled = aim_chat_parse_joined(sess, workingPtr);
536 else if (subtype == 0x0004)
537 workingPtr->handled = aim_chat_parse_leave(sess, workingPtr);
538 else if (subtype == 0x0006)
539 workingPtr->handled = aim_chat_parse_incoming(sess, workingPtr);
540 else
541 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
542 } else {
543 printf("Chat: unknown snac %04x/%04x\n", family, subtype);
544 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_DEFAULT, workingPtr);
545 }
546 break;
547 }
548 default:
549 printf("\ninternal error: unknown connection type (very bad.) (type = %d, fd = %d, channel = %02x, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->type, workingPtr->commandlen);
550 workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
551 break;
552 }
553 }
554 }
555
556 /*
557 * This doesn't have to be called here. It could easily be done
558 * by a seperate thread or something. It's an administrative operation,
559 * and can take a while. Though the less you call it the less memory
560 * you'll have :)
561 */
562 aim_purge_rxqueue(sess);
563
564 return 0;
565 }
566
567 int aim_parsemotd_middle(struct aim_session_t *sess,
568 struct command_rx_struct *command, ...)
569 {
570 rxcallback_t userfunc = NULL;
571 char *msg;
572 int ret=1;
573 struct aim_tlvlist_t *tlvlist;
574 u_short id;
575
576 /*
577 * Dunno.
578 */
579 id = aimutil_get16(command->data+10);
580
581 /*
582 * TLVs follow
583 */
584 tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12);
585
586 msg = aim_gettlv_str(tlvlist, 0x000b, 1);
587
588 userfunc = aim_callhandler(command->conn, 0x0001, 0x0013);
589 if (userfunc)
590 ret = userfunc(sess, command, id, msg);
591
592 aim_freetlvchain(&tlvlist);
593
594 return ret;
595
596 }
597
598 int aim_handleredirect_middle(struct aim_session_t *sess,
599 struct command_rx_struct *command, ...)
600 {
601 struct aim_tlv_t *tmptlv = NULL;
602 int serviceid = 0x00;
603 char cookie[AIM_COOKIELEN];
604 char *ip = NULL;
605 rxcallback_t userfunc = NULL;
606 struct aim_tlvlist_t *tlvlist;
607 int ret = 1;
608
609 if (!(tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10)))
610 {
611 printf("libfaim: major bug: unable to read tlvchain from redirect\n");
612 return ret;
613 }
614
615 if (!(tmptlv = aim_gettlv(tlvlist, 0x000d, 1)))
616 {
617 printf("libfaim: major bug: no service ID in tlvchain from redirect\n");
618 aim_freetlvchain(&tlvlist);
619 return ret;
620 }
621 serviceid = aimutil_get16(tmptlv->value);
622
623 if (!(ip = aim_gettlv_str(tlvlist, 0x0005, 1)))
624 {
625 printf("libfaim: major bug: no IP in tlvchain from redirect (service 0x%02x)\n", serviceid);
626 aim_freetlvchain(&tlvlist);
627 return ret;
628 }
629
630 if (!(tmptlv = aim_gettlv(tlvlist, 0x0006, 1)))
631 {
632 printf("libfaim: major bug: no cookie in tlvchain from redirect (service 0x%02x)\n", serviceid);
633 aim_freetlvchain(&tlvlist);
634 return ret;
635 }
636 memcpy(cookie, tmptlv->value, AIM_COOKIELEN);
637
638 if (serviceid == AIM_CONN_TYPE_CHAT)
639 {
640 /*
641 * Chat hack.
642 *
643 */
644 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
645 if (userfunc)
646 ret = userfunc(sess, command, serviceid, ip, cookie, sess->pendingjoin);
647 free(sess->pendingjoin);
648 sess->pendingjoin = NULL;
649 }
650 else
651 {
652 userfunc = aim_callhandler(command->conn, 0x0001, 0x0005);
653 if (userfunc)
654 ret = userfunc(sess, command, serviceid, ip, cookie);
655 }
656
657 /*
658 * XXX: Is there a leak here? Where does IP get freed?
659 */
660 aim_freetlvchain(&tlvlist);
661
662 return ret;
663 }
664
665 int aim_parse_unknown(struct aim_session_t *sess,
666 struct command_rx_struct *command, ...)
667 {
668 u_int i = 0;
669
670 faimdprintf(1, "\nRecieved unknown packet:");
446 671
447 for (i = 0; i < command->commandlen; i++) 672 for (i = 0; i < command->commandlen; i++)
448 { 673 {
449 if ((i % 8) == 0) 674 if ((i % 8) == 0)
450 printf("\n\t"); 675 printf("\n\t");
462 * aim_parse_generalerrs() 687 * aim_parse_generalerrs()
463 * 688 *
464 * Middle handler for 0x0001 snac of each family. 689 * Middle handler for 0x0001 snac of each family.
465 * 690 *
466 */ 691 */
467 int aim_parse_generalerrs(struct command_rx_struct *command, ...) 692 int aim_parse_generalerrs(struct aim_session_t *sess,
693 struct command_rx_struct *command, ...)
468 { 694 {
469 u_short family; 695 u_short family;
470 u_short subtype; 696 u_short subtype;
471 family = (command->data[0] << 8) + command->data[1]; 697
472 subtype = (command->data[2] << 8) + command->data[3]; 698 family = aimutil_get16(command->data+0);
699 subtype= aimutil_get16(command->data+2);
473 700
474 switch(family) 701 switch(family)
475 { 702 {
476 default: 703 default:
477 /* Unknown family */ 704 /* Unknown family */
478 return (aim_callbacks[AIM_CB_UNKNOWN])(command); 705 return aim_callhandler_noparam(sess, command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, command);
479 } 706 }
480 707
481 return 1; 708 return 1;
482 } 709 }
483 710