source: aim.c @ 6a415e9

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 6a415e9 was 6a415e9, checked in by James M. Kretchmar <kretch@mit.edu>, 17 years ago
Added the variable 'aim_ingorelogin_timer', which specifies the number of seconds after an AIM login for which AIM login notifications should be ignored. Defaults to 0 for now. Added the timer object to implement the above and to replace other timers that have been impelmented by hand.
  • Property mode set to 100644
File size: 82.5 KB
Line 
1#include <stdio.h>
2#include <stdio.h>
3#include <sys/stat.h>
4#include "owl.h"
5
6/**********************************************************************/
7
8struct owlfaim_priv {
9  char *aimbinarypath;
10  char *screenname;
11  char *password;
12  char *server;
13  char *proxy;
14  char *proxyusername;
15  char *proxypass;
16  char *ohcaptainmycaptain;
17  int connected;
18
19  FILE *listingfile;
20  char *listingpath;
21
22  fu8_t *buddyicon;
23  int buddyiconlen;
24  time_t buddyiconstamp;
25  fu16_t buddyiconsum;
26};
27
28/*
29static char *msgerrreasons[] = {
30        "Invalid error",
31        "Invalid SNAC",
32        "Rate to host",
33        "Rate to client",
34        "Not logged on",
35        "Service unavailable",
36        "Service not defined",
37        "Obsolete SNAC",
38        "Not supported by host",
39        "Not supported by client",
40        "Refused by client",
41        "Reply too big",
42        "Responses lost",
43        "Request denied",
44        "Busted SNAC payload",
45        "Insufficient rights",
46        "In local permit/deny",
47        "Too evil (sender)",
48        "Too evil (receiver)",
49        "User temporarily unavailable",
50        "No match",
51        "List overflow",
52        "Request ambiguous",
53        "Queue full",
54        "Not while on AOL",
55};
56static int msgerrreasonslen = 25;
57*/
58
59static void faimtest_debugcb(aim_session_t *sess, int level, const char *format, va_list va);
60static int faimtest_parse_login(aim_session_t *sess, aim_frame_t *fr, ...);
61static int faimtest_parse_authresp(aim_session_t *sess, aim_frame_t *fr, ...);
62int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...);
63int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...);
64void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn);
65static int conninitdone_bos(aim_session_t *sess, aim_frame_t *fr, ...);
66int login(aim_session_t *sess, const char *sn, const char *passwd);
67static int conninitdone_admin(aim_session_t *sess, aim_frame_t *fr, ...);
68int logout(aim_session_t *sess);
69
70static int faimtest_parse_connerr(aim_session_t *sess, aim_frame_t *fr, ...);
71static int faimtest_accountconfirm(aim_session_t *sess, aim_frame_t *fr, ...);
72static int faimtest_infochange(aim_session_t *sess, aim_frame_t *fr, ...);
73static int faimtest_handleredirect(aim_session_t *sess, aim_frame_t *fr, ...);
74static int faimtest_icbmparaminfo(aim_session_t *sess, aim_frame_t *fr, ...);
75static int faimtest_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...);
76static int faimtest_bosrights(aim_session_t *sess, aim_frame_t *fr, ...);
77static int faimtest_locrights(aim_session_t *sess, aim_frame_t *fr, ...);
78static int faimtest_reportinterval(aim_session_t *sess, aim_frame_t *fr, ...);
79static int faimtest_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...);
80static int getaimdata(aim_session_t *sess, unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname);
81static int faimtest_memrequest(aim_session_t *sess, aim_frame_t *fr, ...);
82static void printuserflags(fu16_t flags);
83static int faimtest_parse_userinfo(aim_session_t *sess, aim_frame_t *fr, ...);
84static int faimtest_handlecmd(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, const char *tmpstr);
85static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args);
86static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args);
87static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...);
88static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...);
89static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...);
90int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...);
91static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...);
92static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...);
93static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...);
94static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...);
95static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...);
96static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...);
97static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...);
98static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...);
99static int handlepopup(aim_session_t *sess, aim_frame_t *fr, ...);
100static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...);
101static int migrate(aim_session_t *sess, aim_frame_t *fr, ...);
102static int ssirights(aim_session_t *sess, aim_frame_t *fr, ...);
103static int ssidata(aim_session_t *sess, aim_frame_t *fr, ...);
104static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...);
105static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...);
106static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...);
107
108static int directim_incoming(aim_session_t *sess, aim_frame_t *fr, ...);
109static int directim_typing(aim_session_t *sess, aim_frame_t *fr, ...);
110static int faimtest_directim_initiate(aim_session_t *sess, aim_frame_t *fr, ...);
111static int faimtest_getfile_filereq(aim_session_t *ses, aim_frame_t *fr, ...);
112static int faimtest_getfile_filesend(aim_session_t *sess, aim_frame_t *fr, ...);
113static int faimtest_getfile_complete(aim_session_t *sess, aim_frame_t *fr, ...);
114static int faimtest_getfile_disconnect(aim_session_t *sess, aim_frame_t *fr, ...);
115static int faimtest_getfile_listing(aim_session_t *sess, aim_frame_t *fr, ...);
116static int faimtest_getfile_listingreq(aim_session_t *sess, aim_frame_t *fr, ...);
117static int faimtest_getfile_receive(aim_session_t *sess, aim_frame_t *fr, ...);
118static int faimtest_getfile_state4(aim_session_t *sess, aim_frame_t *fr, ...);
119static int faimtest_getfile_initiate(aim_session_t *sess, aim_frame_t *fr, ...);
120void getfile_start(aim_session_t *sess, aim_conn_t *conn, const char *sn);
121void getfile_requested(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args);
122void directim_start(aim_session_t *sess, const char *sn);
123void directim_requested(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args);
124
125void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir);
126void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir);
127
128/*****************************************************************/
129
130void owl_aim_init(void)
131{
132  aim_session_init(owl_global_get_aimsess(&g), AIM_SESS_FLAGS_NONBLOCKCONNECT, 1);
133  aim_setdebuggingcb(owl_global_get_aimsess(&g), faimtest_debugcb);
134}
135
136int owl_aim_login(char *screenname, char *password)
137{
138  int ret;
139  struct owlfaim_priv *priv;
140
141  /* this will leak, I know and just don't care right now */
142  priv=owl_malloc(sizeof(struct owlfaim_priv));
143  memset(priv, 0, sizeof(struct owlfaim_priv));
144
145  priv->screenname = owl_strdup(screenname);
146  priv->password = owl_strdup(password);
147  priv->server = "login.oscar.aol.com";
148  owl_global_get_aimsess(&g)->aux_data = priv;
149
150 
151  /* login */
152  ret=login(owl_global_get_aimsess(&g), priv->screenname, priv->password);
153  if (ret) {
154    owl_global_set_aimnologgedin(&g);
155    /* printf("login returned %i\n"); */
156    return(-1);
157  }
158  owl_global_set_aimloggedin(&g, screenname);
159  return(0);
160}
161
162void owl_aim_logout(void)
163{
164  /* need to check if it's connected first, I think */
165  aim_session_kill(owl_global_get_aimsess(&g));
166  owl_global_set_aimnologgedin(&g);
167}
168
169int owl_aim_send_im(char *to, char *msg)
170{
171  aim_send_im(owl_global_get_aimsess(&g), to, AIM_IMFLAGS_ACK, msg);
172
173  /* I don't know how to check for an error yet */
174  return(0);
175}
176
177void owl_aim_addbuddy(char *screenname)
178{
179  aim_add_buddy(owl_global_get_aimsess(&g), owl_global_get_waitingconn(&g), screenname);
180}
181
182void owl_aim_delbuddy(char *screenname)
183{
184  aim_remove_buddy(owl_global_get_aimsess(&g), NULL, screenname);
185}
186
187void owl_aim_chat_join(char *chatroom)
188{
189}
190
191void owl_aim_chat_leave(char *chatroom)
192{
193}
194
195int owl_aim_chat_sendmsg(char *chatroom, char *msg)
196{
197  return(0);
198}
199
200/* caller must free the return */
201char *owl_aim_normalize_screenname(char *in) {
202  char *out;
203  int i, j, k;
204
205  j=strlen(in);
206  out=owl_malloc(j+30);
207  k=0;
208  for (i=0; i<j; i++) {
209    if (in[i]!=' ') {
210      out[k]=in[i];
211      k++;
212    }
213  }
214  out[k]='\0';
215  return(out);
216}
217
218int owl_aim_process_events() {
219  aim_session_t *aimsess;
220  aim_conn_t *waitingconn = NULL;
221  struct timeval tv;
222  int selstat = 0;
223  struct owlfaim_priv *priv;
224
225  aimsess=owl_global_get_aimsess(&g);
226  priv = (struct owlfaim_priv *) &(aimsess->aux_data);
227
228  /* do a select without blocking */
229  tv.tv_sec = 0;
230  tv.tv_usec = 0;
231  waitingconn = aim_select(aimsess, &tv, &selstat);
232
233  if (owl_global_is_aimnop_time(&g)) {
234    aim_flap_nop(aimsess, aim_getconn_type(aimsess, AIM_CONN_TYPE_BOS));
235    owl_global_aimnop_sent(&g);
236  }
237
238  if (selstat == -1) { /* error */
239    /* keepgoing = 0; */ /* fall through */
240  } else if (selstat == 0) { /* no events pending */
241    /* printf("selstat == 0\n"); */
242  } else if (selstat == 1) { /* outgoing data pending */
243    /* printf("selstat == 1\n"); */
244    aim_tx_flushqueue(aimsess);
245  } else if (selstat == 2) { /* incoming data pending */
246    /* printf("selstat == 2\n"); */
247    if (waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
248      if (aim_handlerendconnect(aimsess, waitingconn) < 0) {
249        /* printf("connection error (rend out)\n"); */
250        aim_conn_kill(aimsess, &waitingconn);
251      }
252    } else {
253      if (aim_get_command(aimsess, waitingconn) >= 0) {
254        aim_rxdispatch(aimsess);
255      } else {
256        /* printf("connection error (type 0x%04x:0x%04x)\n", waitingconn->type, waitingconn->subtype); */
257        /* we should have callbacks for all these, else the library will do the conn_kill for us. */
258        if (waitingconn->type == AIM_CONN_TYPE_RENDEZVOUS) {
259          if (waitingconn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
260            /* printf("disconnected from %s\n", aim_directim_getsn(waitingconn)); */
261            aim_conn_kill(aimsess, &waitingconn);
262          }
263        } else {
264          aim_conn_kill(aimsess, &waitingconn);
265        }
266        if (!aim_getconn_type(aimsess, AIM_CONN_TYPE_BOS)) {
267          /* printf("major connection error\n"); */
268          /* break; */
269          /* we should probably kill the session */
270        }
271      }
272    }
273  }
274  /* free(priv->buddyicon); */
275  /* exit(0); */
276  return(0);
277}
278
279static void faimtest_debugcb(aim_session_t *sess, int level, const char *format, va_list va)
280{
281  return;
282}
283
284
285static int faimtest_parse_login(aim_session_t *sess, aim_frame_t *fr, ...)
286{
287  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
288  struct client_info_s info = AIM_CLIENTINFO_KNOWNGOOD;
289  char *key;
290  va_list ap;
291
292  va_start(ap, fr);
293  key = va_arg(ap, char *);
294  va_end(ap);
295
296  aim_send_login(sess, fr->conn, priv->screenname, priv->password, &info, key);
297
298  return 1;
299}
300
301
302static int faimtest_parse_authresp(aim_session_t *sess, aim_frame_t *fr, ...)
303{
304  va_list ap;
305  struct aim_authresp_info *info;
306  aim_conn_t *bosconn;
307
308  va_start(ap, fr);
309  info = va_arg(ap, struct aim_authresp_info *);
310  va_end(ap);
311
312  /* printf("Screen name: %s\n", info->sn); */
313
314  /*
315   * Check for error.
316   */
317  if (info->errorcode || !info->bosip || !info->cookie) {
318    /*
319    printf("Login Error Code 0x%04x\n", info->errorcode);
320    printf("Error URL: %s\n", info->errorurl);
321    */
322    aim_conn_kill(sess, &fr->conn);
323    return 1;
324  }
325
326  /*
327  printf("Reg status: %d\n", info->regstatus);
328  printf("Email: %s\n", info->email);
329  printf("BOS IP: %s\n", info->bosip);
330  */
331
332  /* printf("Closing auth connection...\n"); */
333  aim_conn_kill(sess, &fr->conn);
334  if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, info->bosip))) {
335    /* printf("could not connect to BOS: internal error\n"); */
336    return 1;
337  } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {
338    /* printf("could not connect to BOS\n"); */
339    aim_conn_kill(sess, &bosconn);
340    return 1;
341  }
342  addcb_bos(sess, bosconn);
343  aim_sendcookie(sess, bosconn, info->cookie);
344  return 1;
345}
346
347int faimtest_flapversion(aim_session_t *sess, aim_frame_t *fr, ...)
348{
349#if 0
350  /* XXX fix libfaim to support this */
351  printf("using FLAP version 0x%08x\n", /* aimutil_get32(fr->data)*/ 0xffffffff);
352
353  /*
354   * This is an alternate location for starting the login process.
355   */
356  /* XXX should do more checking to make sure its really the right AUTH conn */
357  if (fr->conn->type == AIM_CONN_TYPE_AUTH) {
358    /* do NOT send a flapversion, request_login will send it if needed */
359    aim_request_login(sess, fr->conn, priv->screenname);
360    /* printf("faimtest: login request sent\n"); */
361  }
362#endif
363
364  return 1;
365}
366
367
368int faimtest_conncomplete(aim_session_t *sess, aim_frame_t *fr, ...)
369{
370  return 1;
371}
372
373void addcb_bos(aim_session_t *sess, aim_conn_t *bosconn)
374{
375
376  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
377  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_bos, 0);
378
379  aim_conn_addhandler(sess, bosconn, 0x0013,         0x0003,                        ssirights, 0);
380  aim_conn_addhandler(sess, bosconn, 0x0013,         0x0006,                        ssidata, 0);
381  aim_conn_addhandler(sess, bosconn, 0x0013,         0x000f,                        ssidatanochange, 0);
382  aim_conn_addhandler(sess, bosconn, 0x0008,         0x0002,                        handlepopup, 0);
383  aim_conn_addhandler(sess, bosconn, 0x0009,         0x0003,                        faimtest_bosrights, 0);
384  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT,           faimtest_handleredirect, 0);
385  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL,  faimtest_reportinterval, 0);
386  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO,         faimtest_parse_buddyrights, 0);
387  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD,               faimtest_parse_motd, 0);
388  aim_conn_addhandler(sess, bosconn, 0x0004,         0x0005,                        faimtest_icbmparaminfo, 0);
389  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR,    faimtest_parse_connerr, 0);
390  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_RIGHTSINFO,         faimtest_locrights, 0);
391  aim_conn_addhandler(sess, bosconn, 0x0001,         0x001f,                        faimtest_memrequest, 0);
392  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING,           faimtest_parse_oncoming, 0);
393  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING,           faimtest_parse_offgoing, 0);
394  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING,           faimtest_parse_incoming_im, 0);
395  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR,              faimtest_parse_locerr, 0);
396  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL,         faimtest_parse_misses, 0);
397  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE,         faimtest_parse_ratechange, 0);
398  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL,               faimtest_parse_evilnotify, 0);
399  aim_conn_addhandler(sess, bosconn, 0x000a,         0x0001,                        faimtest_parse_searcherror, 0);
400  aim_conn_addhandler(sess, bosconn, 0x000a,         0x0003,                        faimtest_parse_searchreply, 0);
401  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR,              faimtest_parse_msgerr, 0);
402  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO,           faimtest_parse_userinfo, 0);
403  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK,                faimtest_parse_msgack, 0);
404
405  aim_conn_addhandler(sess, bosconn, 0x0001,         0x0001,                        faimtest_parse_genericerr, 0);
406  aim_conn_addhandler(sess, bosconn, 0x0003,         0x0001,                        faimtest_parse_genericerr, 0);
407  aim_conn_addhandler(sess, bosconn, 0x0009,         0x0001,                        faimtest_parse_genericerr, 0);
408  aim_conn_addhandler(sess, bosconn, 0x0001,         0x000b,                        serverpause, 0);
409  aim_conn_addhandler(sess, bosconn, 0x0001,         0x0012,                        migrate, 0);
410  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG,         offlinemsg, 0);
411  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE, offlinemsgdone, 0);
412
413  #ifdef MID_REWROTE_ALL_THE_CRAP
414  aim_conn_addhandler(sess, bosconn, 0xffff,         0xffff,                        faimtest_parse_unknown, 0);
415  #endif
416
417  return;
418}
419
420static int conninitdone_bos(aim_session_t *sess, aim_frame_t *fr, ...)
421{
422  char buddies[128]; /* this is the new buddy list */
423  char profile[256]; /* this is the new profile */
424  char awaymsg[] = {"blah blah blah Ole! blah blah blah"};
425
426  /* Caution: Buddy1 and Buddy2 are real people! (who I don't know) */
427  /*  snprintf(buddies, sizeof(buddies), "Buddy1&Buddy2&%s&", priv->ohcaptainmycaptain ? priv->ohcaptainmycaptain : "blah");
428  snprintf(profile, sizeof(profile), "Hello.<br>My captain is %s.  They were dumb enough to leave this message in their client, or they are using faimtest.  Shame
429on them.", priv->ohcaptainmycaptain);
430  */
431
432  /*
433  snprintf(buddies, sizeof(buddies), "Buddy1&Buddy2&");
434  snprintf(profile, sizeof(profile), "Hello.<br>This is a test");
435  */
436
437  aim_reqpersonalinfo(sess, fr->conn);
438  aim_bos_reqlocaterights(sess, fr->conn);
439
440  /*aim_bos_setprofile(sess, fr->conn, profile, awaymsg, AIM_CAPS_BUDDYICON | AIM_CAPS_CHAT | AIM_CAPS_GETFILE | AIM_CAPS_SENDFILE | AIM_CAPS_IMIMAGE | AIM_CAPS_GAMES | AIM_CAPS_SAVESTOCKS | AIM_CAPS_SENDBUDDYLIST | AIM_CAPS_ICQ | AIM_CAPS_ICQUNKNOWN | AIM_CAPS_ICQRTF | AIM_CAPS_ICQSERVERRELAY | AIM_CAPS_TRILLIANCRYPT); */
441  aim_bos_setprofile(sess, fr->conn, profile, "", AIM_CAPS_SENDBUDDYLIST | AIM_CAPS_CHAT );
442  aim_bos_reqbuddyrights(sess, fr->conn);
443
444  /* send the buddy list and profile (required, even if empty) */
445  aim_bos_setbuddylist(sess, fr->conn, buddies);
446
447  aim_reqicbmparams(sess);
448
449  aim_bos_reqrights(sess, fr->conn);
450  /* set group permissions -- all user classes */
451  aim_bos_setgroupperm(sess, fr->conn, AIM_FLAG_ALLUSERS);
452  aim_bos_setprivacyflags(sess, fr->conn, AIM_PRIVFLAGS_ALLOWIDLE);
453
454  return 1;
455}
456
457int login(aim_session_t *sess, const char *sn, const char *passwd)
458{
459  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
460  aim_conn_t *authconn;
461
462  if (sn) priv->screenname = strdup(sn);
463  if (passwd) priv->password = strdup(passwd);
464  if (priv->proxy) aim_setupproxy(sess, priv->proxy, priv->proxyusername, priv->proxypass);
465
466  if (!priv->screenname || !priv->password) {
467    /* printf("need SN and password\n"); */
468    return -1;
469  }
470
471  if (!(authconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, priv->server ? priv->server : FAIM_LOGIN_SERVER))) {
472    /* printf("internal connection error during login\n"); */
473    return (-1);
474  } else if (authconn->fd == -1) {
475    if (authconn->status & AIM_CONN_STATUS_RESOLVERR) {
476      /* printf("could not resolve authorizer name\n");*/
477    } else if (authconn->status & AIM_CONN_STATUS_CONNERR) {
478      /* printf("could not connect to authorizer\n"); */
479    }
480    aim_conn_kill(sess, &authconn);
481
482    return (-1);
483  }
484
485  aim_conn_addhandler(sess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
486  aim_conn_addhandler(sess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
487  aim_conn_addhandler(sess, authconn, 0x0017, 0x0007, faimtest_parse_login, 0);
488  aim_conn_addhandler(sess, authconn, 0x0017, 0x0003, faimtest_parse_authresp, 0);
489
490  /* If the connection is in progress, this will just be queued */
491  aim_request_login(sess, authconn, priv->screenname);
492
493  /* printf("login request sent\n"); */
494
495  return(0);
496}
497
498
499static int conninitdone_admin(aim_session_t *sess, aim_frame_t *fr, ...)
500{
501  aim_clientready(sess, fr->conn);
502  /* printf("initialization done for admin connection\n"); */
503  return(1);
504}
505
506int logout(aim_session_t *sess)
507{
508  aim_session_kill(sess);
509  owl_aim_init();
510 
511  /* kretch
512  if (faimtest_init() == -1)
513    printf("faimtest_init failed\n");
514  */
515
516  return(0);
517}
518
519/**************************************************************************************************/
520
521static int faimtest_parse_connerr(aim_session_t *sess, aim_frame_t *fr, ...)
522{
523  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
524  va_list ap;
525  fu16_t code;
526  char *msg;
527 
528  va_start(ap, fr);
529  code = va_arg(ap, int);
530  msg = va_arg(ap, char *);
531  va_end(ap);
532 
533  /* printf("connerr: Code 0x%04x: %s\n", code, msg); */
534  aim_conn_kill(sess, &fr->conn); /* this will break the main loop */
535 
536  priv->connected = 0;
537 
538  return 1;
539}
540
541static int faimtest_accountconfirm(aim_session_t *sess, aim_frame_t *fr, ...)
542{
543  int status;
544  va_list ap;
545 
546  va_start(ap, fr);
547  status = va_arg(ap, int); /* status code of confirmation request */
548  va_end(ap);
549 
550  /* printf("account confirmation returned status 0x%04x (%s)\n", status, (status==0x0000)?"email sent":"unknown"); */
551 
552  return 1;
553}
554
555static int faimtest_infochange(aim_session_t *sess, aim_frame_t *fr, ...)
556{
557  fu16_t change = 0, perms, type;
558  int length, str;
559  char *val;
560  va_list ap;
561 
562  va_start(ap, fr);
563  change = va_arg(ap, int);
564  perms = (fu16_t)va_arg(ap, unsigned int);
565  type = (fu16_t)va_arg(ap, unsigned int);
566  length = va_arg(ap, int);
567  val = va_arg(ap, char *);
568  str = va_arg(ap, int);
569  va_end(ap);
570 
571  /* printf("info%s: perms = %d, type = %x, length = %d, val = %s\n", change?" change":"", perms, type, length, str?val:"(not string)"); */
572 
573  return 1;
574}
575
576
577static int faimtest_handleredirect(aim_session_t *sess, aim_frame_t *fr, ...)
578{
579  va_list ap;
580  struct aim_redirect_data *redir;
581 
582  va_start(ap, fr);
583  redir = va_arg(ap, struct aim_redirect_data *);
584 
585  if (redir->group == 0x0005) {  /* Adverts */
586   
587  } else if (redir->group == 0x0007) {  /* Authorizer */
588    aim_conn_t *tstconn;
589   
590    tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, redir->ip);
591    if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
592      /* printf("unable to reconnect with authorizer\n"); */
593    } else {
594      aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_FLAPVER, faimtest_flapversion, 0);
595      aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
596      aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_admin, 0);
597      aim_conn_addhandler(sess, tstconn, 0x0007, 0x0007, faimtest_accountconfirm, 0);
598      aim_conn_addhandler(sess, tstconn, 0x0007, 0x0003, faimtest_infochange, 0);
599      aim_conn_addhandler(sess, tstconn, 0x0007, 0x0005, faimtest_infochange, 0);
600      /* Send the cookie to the Auth */
601      aim_sendcookie(sess, tstconn, redir->cookie);
602      /* printf("sent cookie to authorizer host\n"); */
603    }
604  } else if (redir->group == 0x000d) {  /* ChatNav */
605    chatnav_redirect(sess, redir);
606  } else if (redir->group == 0x000e) { /* Chat */
607    chat_redirect(sess, redir);
608  } else {
609    /* printf("uh oh... got redirect for unknown service 0x%04x!!\n", redir->group); */
610  }
611  va_end(ap);
612  return 1;
613}
614
615static int faimtest_icbmparaminfo(aim_session_t *sess, aim_frame_t *fr, ...)
616{
617  struct aim_icbmparameters *params;
618  va_list ap;
619 
620  va_start(ap, fr);
621  params = va_arg(ap, struct aim_icbmparameters *);
622  va_end(ap);
623 
624  /* printf("ICBM Parameters: maxchannel = %d, default flags = 0x%08lx, max msg len = %d, max sender evil = %f, max reciever evil = %f, min msg interval = %ld\n", params->maxchan, params->flags, params->maxmsglen, ((float)params->maxsenderwarn)/10.0, ((float)params->maxrecverwarn)/10.0, params->minmsginterval); */
625     
626  /*
627  * Set these to your taste, or client medium.  Setting minmsginterval
628  * higher is good for keeping yourself from getting flooded (esp
629  * if you're on a slow connection or something where that would be
630  * useful).
631  */
632  params->maxmsglen = 8000;
633  params->minmsginterval = 0; /* in milliseconds */
634  aim_seticbmparam(sess, params);
635 
636  return 1;
637}
638
639static int faimtest_parse_buddyrights(aim_session_t *sess, aim_frame_t *fr, ...)
640{
641  va_list ap;
642  fu16_t maxbuddies, maxwatchers;
643 
644  va_start(ap, fr);
645  maxbuddies = va_arg(ap, int);
646  maxwatchers = va_arg(ap, int);
647  va_end(ap);
648 
649  /* printf("buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers); */
650 
651  aim_ssi_reqrights(sess, fr->conn);
652 
653  return 1;
654}
655
656static int faimtest_bosrights(aim_session_t *sess, aim_frame_t *fr, ...)
657{
658  va_list ap;
659  fu16_t maxpermits, maxdenies;
660 
661  va_start(ap, fr);
662  maxpermits = va_arg(ap, int);
663  maxdenies = va_arg(ap, int);
664  va_end(ap);
665 
666  /* printf("BOS rights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies); */
667  aim_clientready(sess, fr->conn);
668  /* printf("officially connected to BOS.\n"); */
669  aim_icq_reqofflinemsgs(sess);
670  return 1;
671}
672
673static int faimtest_locrights(aim_session_t *sess, aim_frame_t *fr, ...)
674{
675  va_list ap;
676  fu16_t maxsiglen;
677 
678  va_start(ap, fr);
679  maxsiglen = va_arg(ap, int);
680  va_end(ap);
681 
682  /* printf("locate rights: max signature length = %d\n", maxsiglen); */
683 
684  return 1;
685}
686
687static int faimtest_reportinterval(aim_session_t *sess, aim_frame_t *fr, ...)
688{
689  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
690  va_list ap;
691  fu16_t interval;
692 
693  va_start(ap, fr);
694  interval = va_arg(ap, int);
695  va_end(ap);
696 
697  /* printf("minimum report interval: %d (seconds?)\n", interval); */
698 
699  if (!priv->connected) {
700    priv->connected++;
701  }
702  aim_reqicbmparams(sess);
703  return 1;
704}
705
706static int faimtest_parse_motd(aim_session_t *sess, aim_frame_t *fr, ...)
707{
708  char *msg;
709  fu16_t id;
710  va_list ap;
711  /* static int codeslen = 5;
712  static char *codes[] = {
713    "Unknown",
714    "Mandatory upgrade",
715    "Advisory upgrade",
716    "System bulletin",
717    "Top o' the world!"
718  };
719  */
720
721  return 1;
722 
723  va_start(ap, fr);
724  id = va_arg(ap, int);
725  msg = va_arg(ap, char *);
726  va_end(ap);
727 
728  /* printf("motd: %s (%d / %s)\n", msg, id, (id < codeslen)?codes[id]:"unknown"); */
729 
730  return 1;
731}
732
733/*
734 * This is a little more complicated than it looks.  The module
735 * name (proto, boscore, etc) may or may not be given.  If it is
736 * not given, then use aim.exe.  If it is given, put ".ocm" on the
737 * end of it.
738 *
739 * Now, if the offset or length requested would cause a read past
740 * the end of the file, then the request is considered invalid.  Invalid
741 * requests are processed specially.  The value hashed is the
742 * the request, put into little-endian (eight bytes: offset followed
743 * by length). 
744 *
745 * Additionally, if the request is valid, the length is mod 4096.  It is
746 * important that the length is checked for validity first before doing
747 * the mod.
748 *
749 * Note to Bosco's Brigade: if you'd like to break this, put the
750 * module name on an invalid request.
751 *
752 */
753static int getaimdata(aim_session_t *sess, unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname)
754{
755  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
756  FILE *f;
757  static const char defaultmod[] = "aim.exe";
758  char *filename = NULL;
759  struct stat st;
760  unsigned char *buf;
761  int invalid = 0;
762 
763  if (!bufret || !buflenret)
764    return -1;
765 
766  if (modname) {
767    if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(modname)+4+1))) {
768      /* perror("memrequest: malloc"); */
769      return -1;
770    }
771    sprintf(filename, "%s/%s.ocm", priv->aimbinarypath, modname);
772  } else {
773    if (!(filename = malloc(strlen(priv->aimbinarypath)+1+strlen(defaultmod)+1))) {
774      /* perror("memrequest: malloc"); */
775      return -1;
776    }
777    sprintf(filename, "%s/%s", priv->aimbinarypath, defaultmod);
778  }
779 
780  if (stat(filename, &st) == -1) {
781    if (!modname) {
782      /* perror("memrequest: stat"); */
783      free(filename);
784      return -1;
785    }
786    invalid = 1;
787  }
788 
789  if (!invalid) {
790    if ((offset > st.st_size) || (len > st.st_size))
791      invalid = 1;
792    else if ((st.st_size - offset) < len)
793      len = st.st_size - offset;
794    else if ((st.st_size - len) < len)
795      len = st.st_size - len;
796  }
797 
798  if (!invalid && len) {
799    len %= 4096;
800  }
801 
802  if (invalid) {
803    int i;
804   
805    free(filename); /* not needed */
806    printf("memrequest: recieved invalid request for 0x%08lx bytes at 0x%08lx (file %s)\n", len, offset, modname);
807    i = 8;
808    if (modname) {
809      i+=strlen(modname);
810    }
811   
812    if (!(buf = malloc(i))) {
813      return -1;
814    }
815   
816    i=0;
817   
818    if (modname) {
819      memcpy(buf, modname, strlen(modname));
820      i+=strlen(modname);
821    }
822   
823    /* Damn endianness. This must be little (LSB first) endian. */
824    buf[i++] = offset & 0xff;
825    buf[i++] = (offset >> 8) & 0xff;
826    buf[i++] = (offset >> 16) & 0xff;
827    buf[i++] = (offset >> 24) & 0xff;
828    buf[i++] = len & 0xff;
829    buf[i++] = (len >> 8) & 0xff;
830    buf[i++] = (len >> 16) & 0xff;
831    buf[i++] = (len >> 24) & 0xff;
832   
833    *bufret = buf;
834    *buflenret = i;
835  } else {
836    if (!(buf = malloc(len))) {
837      free(filename);
838      return -1;
839    }
840    /* printf("memrequest: loading %ld bytes from 0x%08lx in \"%s\"...\n", len, offset, filename); */
841    if (!(f = fopen(filename, "r"))) {
842      /* perror("memrequest: fopen"); */
843      free(filename);
844      free(buf);
845      return -1;
846    }
847   
848    free(filename);
849   
850    if (fseek(f, offset, SEEK_SET) == -1) {
851      /* perror("memrequest: fseek"); */
852      fclose(f);
853      free(buf);
854      return -1;
855    }
856   
857    if (fread(buf, len, 1, f) != 1) {
858      /* perror("memrequest: fread"); */
859      fclose(f);
860      free(buf);
861      return -1;
862    }
863   
864    fclose(f);
865    *bufret = buf;
866    *buflenret = len;
867  }
868  return 0; /* success! */
869}
870
871/*
872 * This will get an offset and a length.  The client should read this
873 * data out of whatever AIM.EXE binary the user has provided (hopefully
874 * it matches the client information thats sent at login) and pass a
875 * buffer back to libfaim so it can hash the data and send it to AOL for
876 * inspection by the client police.
877 */
878static int faimtest_memrequest(aim_session_t *sess, aim_frame_t *fr, ...)
879{
880  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
881  va_list ap;
882  fu32_t offset, len;
883  char *modname;
884  unsigned char *buf;
885  int buflen;
886 
887  va_start(ap, fr);
888  offset = va_arg(ap, fu32_t);
889  len = va_arg(ap, fu32_t);
890  modname = va_arg(ap, char *);
891  va_end(ap);
892 
893  if (priv->aimbinarypath && (getaimdata(sess, &buf, &buflen, offset, len, modname) == 0)) {
894    aim_sendmemblock(sess, fr->conn, offset, buflen, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
895    free(buf);
896  } else {
897    /* printf("memrequest: unable to use AIM binary (\"%s/%s\"), sending defaults...\n", priv->aimbinarypath, modname); */
898    aim_sendmemblock(sess, fr->conn, offset, len, NULL, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
899  }
900  return 1;
901}
902
903static void printuserflags(fu16_t flags)
904{
905
906  if (flags & AIM_FLAG_UNCONFIRMED)
907    printf("UNCONFIRMED ");
908  if (flags & AIM_FLAG_ADMINISTRATOR)
909    printf("ADMINISTRATOR ");
910  if (flags & AIM_FLAG_AOL)
911    printf("AOL ");
912  if (flags & AIM_FLAG_OSCAR_PAY)
913    printf("OSCAR_PAY ");
914  if (flags & AIM_FLAG_FREE)
915    printf("FREE ");
916  if (flags & AIM_FLAG_AWAY)
917    printf("AWAY ");
918  if (flags & AIM_FLAG_ICQ)
919    printf("ICQ ");
920  if (flags & AIM_FLAG_WIRELESS)
921    printf("WIRELESS ");
922  if (flags & AIM_FLAG_ACTIVEBUDDY)
923    printf("ACTIVEBUDDY ");
924 
925  return;
926}
927
928static int faimtest_parse_userinfo(aim_session_t *sess, aim_frame_t *fr, ...)
929{
930  aim_userinfo_t *userinfo;
931  char *prof_encoding = NULL;
932  char *prof = NULL;
933  fu16_t inforeq = 0;
934
935  va_list ap;
936  va_start(ap, fr);
937  userinfo = va_arg(ap, aim_userinfo_t *);
938  inforeq = (fu16_t)va_arg(ap, unsigned int);
939  prof_encoding = va_arg(ap, char *);
940  prof = va_arg(ap, char *);
941  va_end(ap);
942
943  return (1);
944
945  printf("userinfo: sn: %s\n", userinfo->sn);
946  printf("userinfo: warnlevel: %f\n", aim_userinfo_warnlevel(userinfo));
947  printf("userinfo: flags: 0x%04x = ", userinfo->flags);
948  printuserflags(userinfo->flags);
949  printf("\n");
950 
951  printf("userinfo: membersince: %lu\n", userinfo->membersince);
952  printf("userinfo: onlinesince: %lu\n", userinfo->onlinesince);
953  printf("userinfo: idletime: 0x%04x\n", userinfo->idletime);
954  printf("userinfo: capabilities = %s = 0x%08lx\n", (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present", userinfo->capabilities);
955 
956 
957  if (inforeq == AIM_GETINFO_GENERALINFO) {
958    printf("userinfo: profile_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
959    printf("userinfo: prof: %s\n", prof ? prof : "[none]");
960  } else if (inforeq == AIM_GETINFO_AWAYMESSAGE) {
961    printf("userinfo: awaymsg_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
962    printf("userinfo: awaymsg: %s\n", prof ? prof : "[none]");
963  } else if (inforeq == AIM_GETINFO_CAPABILITIES) {
964    printf("userinfo: capabilities: see above\n");
965  } else {
966    printf("userinfo: unknown info request\n");
967  }
968 
969  return 1;
970}
971
972static int faimtest_handlecmd(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, const char *tmpstr)
973{
974  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
975 
976  if (!strncmp(tmpstr, "disconnect", 10)) {
977    logout(sess);
978  } else if (strstr(tmpstr, "goodday")) {
979    aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_ACK, "Good day to you too.");
980  } else if (strstr(tmpstr, "haveicon") && priv->buddyicon) {
981    struct aim_sendimext_args args;
982    /* static const char iconmsg[] = {"I have an icon"}; */
983    static const char iconmsg[] = {""};
984   
985    args.destsn = userinfo->sn;
986    args.flags = AIM_IMFLAGS_HASICON;
987    args.msg = iconmsg;
988    args.msglen = strlen(iconmsg);
989    args.iconlen = priv->buddyiconlen;
990    args.iconstamp = priv->buddyiconstamp;
991    args.iconsum = priv->buddyiconsum;
992   
993    /* aim_send_im_ext(sess, &args); */
994   
995  } else if (strstr(tmpstr, "sendbin")) {
996    struct aim_sendimext_args args;
997    static const unsigned char data[] = {
998      0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
999      0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1000      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1001      0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1002      0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
1003      0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1004    };
1005   
1006    /*
1007     * I put this here as a demonstration of how to send
1008     * arbitrary binary data via OSCAR ICBM's without the need
1009     * for escape or baseN encoding of any sort. 
1010     *
1011     * Apparently if you set the charset to something WinAIM
1012     * doesn't recognize, it will completly ignore the message.
1013     * That is, it will not display anything in the conversation
1014     * window for the user that recieved it.
1015     *
1016     * HOWEVER, if they do not have a conversation window open
1017     * for you, a new one will be created, but it will not have
1018     * any messages in it.  Therefore sending these things could
1019     * be a great way to seemingly subliminally convince people
1020     * to talk to you...
1021     *
1022     */
1023    args.destsn = userinfo->sn;
1024    args.flags = AIM_IMFLAGS_CUSTOMCHARSET;
1025    args.charset = args.charsubset = 0x4242;
1026    args.msg = data;
1027    args.msglen = sizeof(data);
1028    aim_send_im_ext(sess, &args);
1029   } else if (strstr(tmpstr, "sendmulti")) {
1030    struct aim_sendimext_args args;
1031    aim_mpmsg_t mpm;
1032    static const fu16_t unidata[] = { /* "UNICODE." */
1033      0x0055, 0x004e, 0x0049, 0x0043,
1034      0x004f, 0x0044, 0x0045, 0x002e,
1035    };
1036    static const int unidatalen = 8;
1037   
1038    /*
1039     * This is how multipart messages should be sent.
1040     *
1041     * This should render as:
1042     *        "Part 1, ASCII.  UNICODE.Part 3, ASCII.  "
1043     */
1044   
1045    aim_mpmsg_init(sess, &mpm);
1046    aim_mpmsg_addascii(sess, &mpm, "Part 1, ASCII.  ");
1047    aim_mpmsg_addunicode(sess, &mpm, unidata, unidatalen);
1048    aim_mpmsg_addascii(sess, &mpm, "Part 3, ASCII.  ");
1049   
1050    args.destsn = userinfo->sn;
1051    args.flags = AIM_IMFLAGS_MULTIPART;
1052    args.mpmsg = &mpm;
1053   
1054    aim_send_im_ext(sess, &args);
1055   
1056    aim_mpmsg_free(sess, &mpm);
1057   
1058  } else if (strstr(tmpstr, "sendprebin")) {
1059    static const unsigned char data[] = {
1060      0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1061      0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1062      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1063      0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1064      0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
1065      0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1066    };
1067    struct aim_sendimext_args args;
1068    aim_mpmsg_t mpm;
1069   
1070    /*
1071     * This demonstrates sending a human-readable preamble,
1072     * and then arbitrary binary data.
1073     *
1074     * This means that you can very inconspicuously send binary
1075     * attachments to other users.  In WinAIM, this appears as
1076     * though it only had the ASCII portion.
1077     *
1078     */
1079   
1080    aim_mpmsg_init(sess, &mpm);
1081    aim_mpmsg_addascii(sess, &mpm, "This message has binary data.");
1082    aim_mpmsg_addraw(sess, &mpm, 0x4242, 0x4242, data, sizeof(data));
1083   
1084    args.destsn = userinfo->sn;
1085    args.flags = AIM_IMFLAGS_MULTIPART;
1086    args.mpmsg = &mpm;
1087   
1088    aim_send_im_ext(sess, &args);
1089    aim_mpmsg_free(sess, &mpm);
1090   
1091  } else if (strstr(tmpstr, "havefeat")) {
1092    struct aim_sendimext_args args;
1093    static const char featmsg[] = {"I have nifty features."};
1094    fu8_t features[] = {0x01, 0x01, 0x01, 0x02, 0x42, 0x43, 0x44, 0x45};
1095   
1096    args.destsn = userinfo->sn;
1097    args.flags = AIM_IMFLAGS_CUSTOMFEATURES;
1098    args.msg = featmsg;
1099    args.msglen = strlen(featmsg);
1100    args.features = features;
1101    args.featureslen = sizeof(features);
1102   
1103    aim_send_im_ext(sess, &args);
1104  } else if (strstr(tmpstr, "sendicon") && priv->buddyicon) {
1105    aim_send_icon(sess, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum);
1106  } else if (strstr(tmpstr, "warnme")) {
1107    /* printf("icbm: sending non-anon warning\n"); */
1108    aim_send_warning(sess, conn, userinfo->sn, 0);
1109  } else if (strstr(tmpstr, "anonwarn")) {
1110    /* printf("icbm: sending anon warning\n"); */
1111    aim_send_warning(sess, conn, userinfo->sn, AIM_WARN_ANON);
1112  } else if (strstr(tmpstr, "setdirectoryinfo")) {
1113    /* printf("icbm: sending backwards profile data\n"); */
1114    aim_setdirectoryinfo(sess, conn, "tsrif", "elddim", "tsal", "nediam", "emankcin", "teerts", "ytic", "etats", "piz", 0, 1);
1115  } else if (strstr(tmpstr, "setinterests")) {
1116    /* printf("icbm: setting fun interests\n"); */
1117    aim_setuserinterests(sess, conn, "interest1", "interest2", "interest3", "interest4", "interest5", 1);
1118  } else if (!strncmp(tmpstr, "getfile", 7)) {
1119    if (!priv->ohcaptainmycaptain) {
1120      aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_ACK, "I have no owner!");
1121    } else {
1122      getfile_start(sess, conn, (strlen(tmpstr) < 8)?priv->ohcaptainmycaptain:tmpstr+8);
1123    }
1124  } else if (!strncmp(tmpstr, "open chatnav", 12)) {
1125    aim_reqservice(sess, conn, AIM_CONN_TYPE_CHATNAV);
1126  } else if (!strncmp(tmpstr, "create", 6)) {
1127    aim_chatnav_createroom(sess,aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV), (strlen(tmpstr) < 7)?"WorldDomination":tmpstr+7, 0x0004);
1128  } else if (!strncmp(tmpstr, "close chatnav", 13)) {
1129    aim_conn_t *chatnavconn;
1130    if ((chatnavconn = aim_getconn_type(sess, AIM_CONN_TYPE_CHATNAV)))
1131      aim_conn_kill(sess, &chatnavconn);
1132  } else if (!strncmp(tmpstr, "join", 4)) {
1133    aim_chat_join(sess, conn, 0x0004, "worlddomination", 0x0000);
1134  } else if (!strncmp(tmpstr, "leave", 5)) {
1135    aim_chat_leaveroom(sess, "worlddomination");
1136  } else if (!strncmp(tmpstr, "getinfo", 7)) {
1137    aim_getinfo(sess, conn, "midendian", AIM_GETINFO_GENERALINFO);
1138    aim_getinfo(sess, conn, "midendian", AIM_GETINFO_AWAYMESSAGE);
1139    aim_getinfo(sess, conn, "midendian", AIM_GETINFO_CAPABILITIES);
1140  } else if (strstr(tmpstr, "open directim")) {
1141    directim_start(sess, userinfo->sn);
1142  } else if(strstr(tmpstr, "lookup")) {
1143    aim_usersearch_address(sess, conn, "mid@auk.cx");
1144  } else if (!strncmp(tmpstr, "reqsendmsg", 10)) {
1145    aim_send_im(sess, priv->ohcaptainmycaptain, 0, "sendmsg 7900");
1146  } else if (!strncmp(tmpstr, "reqadmin", 8)) {
1147    aim_reqservice(sess, conn, AIM_CONN_TYPE_AUTH);
1148  } else if (!strncmp(tmpstr, "changenick", 10)) {
1149    aim_admin_setnick(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "diputs8  1");
1150  } else if (!strncmp(tmpstr, "reqconfirm", 10)) {
1151    aim_admin_reqconfirm(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH));
1152  } else if (!strncmp(tmpstr, "reqemail", 8)) {
1153    aim_admin_getinfo(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), 0x0011);
1154  } else if (!strncmp(tmpstr, "changepass", 8)) {
1155    aim_admin_changepasswd(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWPASSWORD", "OLDPASSWORD");
1156  } else if (!strncmp(tmpstr, "setemail", 8)) {
1157    aim_admin_setemail(sess, aim_getconn_type(sess, AIM_CONN_TYPE_AUTH), "NEWEMAILADDRESS");
1158  } else if (!strncmp(tmpstr, "sendmsg", 7)) {
1159    int i;
1160   
1161    i = atoi(tmpstr+8);
1162    if (i < 10000) {
1163      char *newbuf;
1164      int z;
1165     
1166      newbuf = malloc(i+1);
1167      for (z = 0; z < i; z++)
1168        newbuf[z] = (z % 10)+0x30;
1169      newbuf[i] = '\0';
1170      aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_ACK | AIM_IMFLAGS_AWAY, newbuf);
1171      free(newbuf);
1172    }
1173  } else if (strstr(tmpstr, "seticqstatus")) {
1174    aim_setextstatus(sess, conn, AIM_ICQ_STATE_DND);
1175  } else if (strstr(tmpstr, "rtfmsg")) {
1176    static const char rtfmsg[] = {"{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fswiss\\fcharset0 Arial;}{\\f1\\froman\\fprq2\\fcharset0 Georgia;}{\\f2\\fmodern\\fprq1\\fcharset0 MS Mincho;}{\\f3\\froman\\fprq2\\fcharset2 Symbol;}}\\viewkind4\\uc1\\pard\\f0\\fs20 Test\\f1 test\\f2\fs44 test\\f3\\fs20 test\\f0\\par}"};
1177    struct aim_sendrtfmsg_args rtfargs;
1178   
1179    memset(&rtfargs, 0, sizeof(rtfargs));
1180    rtfargs.destsn = userinfo->sn;
1181    rtfargs.fgcolor = 0xffffffff;
1182    rtfargs.bgcolor = 0x00000000;
1183    rtfargs.rtfmsg = rtfmsg;
1184    aim_send_rtfmsg(sess, &rtfargs);
1185  } else {
1186    /* printf("unknown command.\n"); */
1187    aim_add_buddy(sess, conn, userinfo->sn);
1188  } 
1189 
1190  return 0;
1191}
1192
1193/*
1194 * Channel 1: Standard Message
1195 */
1196static int faimtest_parse_incoming_im_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args)
1197{
1198  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
1199  char *tmpstr;
1200  int clienttype = AIM_CLIENTTYPE_UNKNOWN;
1201  owl_message *m;
1202  char *stripmsg;
1203  char realmsg[8192+1] = {""};
1204  clienttype = aim_fingerprintclient(args->features, args->featureslen);
1205
1206  /*
1207  printf("icbm: sn = \"%s\"\n", userinfo->sn);
1208  printf("icbm: probable client type: %d\n", clienttype);
1209  printf("icbm: warnlevel = %f\n", aim_userinfo_warnlevel(userinfo));
1210  printf("icbm: flags = 0x%04x = ", userinfo->flags);
1211  printuserflags(userinfo->flags);
1212  printf("\n");
1213  */
1214
1215  /*
1216  printf("icbm: membersince = %lu\n", userinfo->membersince);
1217  printf("icbm: onlinesince = %lu\n", userinfo->onlinesince);
1218  printf("icbm: idletime = 0x%04x\n", userinfo->idletime);
1219  printf("icbm: capabilities = %s = 0x%08lx\n", (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present", userinfo->capabilities);
1220  */
1221
1222  /*
1223  printf("icbm: icbmflags = ");
1224  if (args->icbmflags & AIM_IMFLAGS_AWAY) printf("away ");
1225  if (args->icbmflags & AIM_IMFLAGS_ACK) printf("ackrequest ");
1226  if (args->icbmflags & AIM_IMFLAGS_OFFLINE) printf("offline ");
1227  if (args->icbmflags & AIM_IMFLAGS_BUDDYREQ) printf("buddyreq ");
1228  if (args->icbmflags & AIM_IMFLAGS_HASICON) printf("hasicon ");
1229  printf("\n");
1230  */
1231
1232  if (args->icbmflags & AIM_IMFLAGS_CUSTOMCHARSET) {
1233    /* printf("icbm: encoding flags = {%04x, %04x}\n", args->charset, args->charsubset); */
1234  }
1235 
1236  /*
1237   * Quickly convert it to eight bit format, replacing non-ASCII UNICODE
1238   * characters with their equivelent HTML entity.
1239   */
1240  if (args->icbmflags & AIM_IMFLAGS_UNICODE) {
1241    int i;
1242   
1243    for (i = 0; i < args->msglen; i += 2) {
1244      fu16_t uni;
1245
1246      uni = ((args->msg[i] & 0xff) << 8) | (args->msg[i+1] & 0xff);
1247      if ((uni < 128) || ((uni >= 160) && (uni <= 255))) { /* ISO 8859-1 */
1248        snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "%c", uni);
1249      } else { /* something else, do UNICODE entity */
1250        snprintf(realmsg+strlen(realmsg), sizeof(realmsg)-strlen(realmsg), "&#%04x;", uni);
1251      }
1252    }
1253  } else {
1254    /*
1255     * For non-UNICODE encodings (ASCII and ISO 8859-1), there is
1256     * no need to do anything special here.  Most
1257     * terminals/whatever will be able to display such characters
1258     * unmodified.
1259     *
1260     * Beware that PC-ASCII 128 through 159 are _not_ actually
1261     * defined in ASCII or ISO 8859-1, and you should send them as
1262     * UNICODE.  WinAIM will send these characters in a UNICODE
1263     * message, so you need to do so as well.
1264     *
1265     * You may not think it necessary to handle UNICODE messages. 
1266     * You're probably wrong.  For one thing, Microsoft "Smart
1267     * Quotes" will be sent by WinAIM as UNICODE (not HTML UNICODE,
1268     * but real UNICODE). If you don't parse UNICODE at all, your
1269     * users will get a blank message instead of the message
1270     * containing Smart Quotes.
1271     *
1272     */
1273    strncpy(realmsg, args->msg, sizeof(realmsg));
1274  }
1275
1276  /* create a message, and put it on the message queue */
1277  stripmsg=owl_text_htmlstrip(realmsg);
1278  m=owl_malloc(sizeof(owl_message));
1279  owl_message_create_incoming_aim(m, userinfo->sn, owl_global_get_aim_screenname(&g), stripmsg);
1280  owl_global_messagequeue_addmsg(&g, m);
1281  owl_free(stripmsg);
1282
1283  return(1);
1284 
1285  /* printf("icbm: message: %s\n", realmsg); */
1286 
1287  if (args->icbmflags & AIM_IMFLAGS_MULTIPART) {
1288    aim_mpmsg_section_t *sec;
1289    int z;
1290
1291    /* printf("icbm: multipart: this message has %d parts\n", args->mpmsg.numparts); */
1292   
1293    for (sec = args->mpmsg.parts, z = 0; sec; sec = sec->next, z++) {
1294      if ((sec->charset == 0x0000) || (sec->charset == 0x0003) || (sec->charset == 0xffff)) {
1295        /* printf("icbm: multipart:   part %d: charset 0x%04x, subset 0x%04x, msg = %s\n", z, sec->charset, sec->charsubset, sec->data); */
1296      } else {
1297        /* printf("icbm: multipart:   part %d: charset 0x%04x, subset 0x%04x, binary or UNICODE data\n", z, sec->charset, sec->charsubset); */
1298      }
1299    }
1300  }
1301 
1302  if (args->icbmflags & AIM_IMFLAGS_HASICON) {
1303    /* aim_send_im(sess, userinfo->sn, AIM_IMFLAGS_BUDDYREQ, "You have an icon"); */
1304    /* printf("icbm: their icon: iconstamp = %ld, iconlen = 0x%08lx, iconsum = 0x%04x\n", args->iconstamp, args->iconlen, args->iconsum); */
1305  }
1306
1307  /*
1308  if (realmsg) {
1309    int i = 0;
1310    while (realmsg[i] == '<') {
1311      if (realmsg[i] == '<') {
1312        while (realmsg[i] != '>')
1313          i++;
1314        i++;
1315      }
1316    }
1317    tmpstr = realmsg+i;
1318    faimtest_handlecmd(sess, conn, userinfo, tmpstr);
1319  }
1320  */
1321 
1322  if (priv->buddyicon && (args->icbmflags & AIM_IMFLAGS_BUDDYREQ)) {
1323    aim_send_icon(sess, userinfo->sn, priv->buddyicon, priv->buddyiconlen, priv->buddyiconstamp, priv->buddyiconsum);
1324  }
1325 
1326  return 1;
1327}
1328
1329/*
1330 * Channel 2: Rendevous Request
1331 */
1332static int faimtest_parse_incoming_im_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args)
1333{
1334  /*
1335  printf("rendezvous: source sn = %s\n", userinfo->sn);
1336  printf("rendezvous: \twarnlevel = %f\n", aim_userinfo_warnlevel(userinfo));
1337  printf("rendezvous: \tclass = 0x%04x = ", userinfo->flags);
1338  printuserflags(userinfo->flags);
1339  printf("\n");
1340 
1341  printf("rendezvous: \tonlinesince = %lu\n", userinfo->onlinesince);
1342  printf("rendezvous: \tidletime = 0x%04x\n", userinfo->idletime);
1343 
1344  printf("rendezvous: message/description = %s\n", args->msg);
1345  printf("rendezvous: encoding = %s\n", args->encoding);
1346  printf("rendezvous: language = %s\n", args->language);
1347  */
1348 
1349  if (args->reqclass == AIM_CAPS_GETFILE) {
1350    getfile_requested(sess, conn, userinfo, args);
1351  } else if (args->reqclass == AIM_CAPS_SENDFILE) {
1352    /* printf("send file!\n"); */
1353  } else if (args->reqclass == AIM_CAPS_CHAT) {
1354    /*
1355    printf("chat invitation: room name = %s\n", args->info.chat.roominfo.name);
1356    printf("chat invitation: exchange = 0x%04x\n", args->info.chat.roominfo.exchange);
1357    printf("chat invitation: instance = 0x%04x\n", args->info.chat.roominfo.instance);
1358    */
1359    /* Automatically join room... */
1360    /* printf("chat invitiation: autojoining %s...\n", args->info.chat.roominfo.name); */
1361
1362    /* aim_chat_join(sess, conn, args->info.chat.roominfo.exchange, args->info.chat.roominfo.name, args->info.chat.roominfo.instance); */
1363  } else if (args->reqclass == AIM_CAPS_IMIMAGE) {
1364    directim_requested(sess, conn, userinfo, args);
1365  } else if (args->reqclass == AIM_CAPS_BUDDYICON) {
1366    /* printf("Buddy Icon from %s, length = %lu\n", userinfo->sn, args->info.icon.length); */
1367  } else if (args->reqclass == AIM_CAPS_ICQRTF) {
1368    /* printf("RTF message from %s: (fgcolor = 0x%08lx, bgcolor = 0x%08lx) %s\n", userinfo->sn, args->info.rtfmsg.fgcolor, args->info.rtfmsg.bgcolor, args->info.rtfmsg.rtfmsg); */
1369  } else {
1370    /* printf("icbm: unknown reqclass (%d)\n", args->reqclass); */
1371  }
1372  return 1;
1373}
1374
1375static int faimtest_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...)
1376{
1377  fu16_t channel;
1378  aim_userinfo_t *userinfo;
1379  va_list ap;
1380  int ret = 0;
1381 
1382  va_start(ap, fr);
1383  channel = (fu16_t)va_arg(ap, unsigned int);
1384  userinfo = va_arg(ap, aim_userinfo_t *);
1385 
1386  if (channel == 1) {
1387    struct aim_incomingim_ch1_args *args;
1388    args = va_arg(ap, struct aim_incomingim_ch1_args *);
1389    ret = faimtest_parse_incoming_im_chan1(sess, fr->conn, userinfo, args);
1390  } else if (channel == 2) {
1391    struct aim_incomingim_ch2_args *args;
1392    args = va_arg(ap, struct aim_incomingim_ch2_args *);
1393    ret = faimtest_parse_incoming_im_chan2(sess, fr->conn, userinfo, args);
1394  } else {
1395    /* printf("unsupported channel 0x%04x\n", channel); */
1396  }
1397  va_end(ap);
1398  /* printf("icbm: done with ICBM handling (ret = %d)\n", ret); */
1399  return 1;
1400}
1401
1402static int faimtest_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...)
1403{
1404  aim_userinfo_t *userinfo;
1405
1406  va_list ap;
1407  va_start(ap, fr);
1408  userinfo = va_arg(ap, aim_userinfo_t *);
1409  va_end(ap);
1410
1411  /* first check that we're not still ignoreing login messages */
1412  if (!owl_timer_is_expired(owl_global_get_aim_login_timer(&g))) return;
1413 
1414  owl_buddylist_oncoming(owl_global_get_buddylist(&g), userinfo->sn);
1415 
1416  /*
1417    printf("%ld  %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1418    time(NULL),
1419    userinfo->sn, userinfo->flags,
1420    (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1421    (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1422    (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1423    (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1424    (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1425    (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1426    (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1427    (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1428    (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1429    userinfo->capabilities);
1430  */
1431  return(1);
1432}
1433
1434static int faimtest_parse_offgoing(aim_session_t *sess, aim_frame_t *fr, ...)
1435{
1436  aim_userinfo_t *userinfo;
1437  va_list ap;
1438 
1439  va_start(ap, fr);
1440  userinfo = va_arg(ap, aim_userinfo_t *);
1441  va_end(ap);
1442
1443  owl_buddylist_offgoing(owl_global_get_buddylist(&g), userinfo->sn);
1444
1445  /*
1446  printf("%ld  %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
1447         time(NULL),
1448         userinfo->sn, userinfo->flags,
1449         (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"",
1450         (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"",
1451         (userinfo->flags&AIM_FLAG_AOL)?" AOL":"",
1452         (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"",
1453         (userinfo->flags&AIM_FLAG_FREE)?" FREE":"",
1454         (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"",
1455         (userinfo->flags&AIM_FLAG_ICQ)?" ICQ":"",
1456         (userinfo->flags&AIM_FLAG_WIRELESS)?" WIRELESS":"",
1457         (userinfo->present & AIM_USERINFO_PRESENT_CAPABILITIES) ? "present" : "not present",
1458         userinfo->capabilities);
1459  */
1460 
1461  return 1;
1462}
1463
1464/* Used by chat as well. */
1465int faimtest_parse_genericerr(aim_session_t *sess, aim_frame_t *fr, ...)
1466{
1467  va_list ap;
1468  fu16_t reason;
1469 
1470  va_start(ap, fr);
1471  reason = (fu16_t)va_arg(ap, unsigned int);
1472  va_end(ap);
1473 
1474  /* printf("snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1475 
1476  return 1;
1477}
1478
1479static int faimtest_parse_msgerr(aim_session_t *sess, aim_frame_t *fr, ...)
1480{
1481  va_list ap;
1482  char *destsn;
1483  fu16_t reason;
1484 
1485  va_start(ap, fr);
1486  reason = (fu16_t)va_arg(ap, unsigned int);
1487  destsn = va_arg(ap, char *);
1488  va_end(ap);
1489 
1490  /* printf("message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1491 
1492  return 1;
1493}
1494
1495static int faimtest_parse_locerr(aim_session_t *sess, aim_frame_t *fr, ...)
1496{
1497  va_list ap;
1498  char *destsn;
1499  fu16_t reason;
1500 
1501  va_start(ap, fr);
1502  reason = (fu16_t)va_arg(ap, unsigned int);
1503  destsn = va_arg(ap, char *);
1504  va_end(ap);
1505 
1506  /* printf("user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
1507 
1508  return 1;
1509}
1510
1511static int faimtest_parse_misses(aim_session_t *sess, aim_frame_t *fr, ...)
1512{
1513  /*
1514  static char *missedreasons[] = {
1515    "Invalid (0)",
1516    "Message too large",
1517    "Rate exceeded",
1518    "Evil Sender",
1519    "Evil Receiver"
1520  };
1521  static int missedreasonslen = 5; */
1522 
1523  va_list ap;
1524  fu16_t chan, nummissed, reason;
1525  aim_userinfo_t *userinfo;
1526 
1527  va_start(ap, fr);
1528  chan = (fu16_t)va_arg(ap, unsigned int);
1529  userinfo = va_arg(ap, aim_userinfo_t *);
1530  nummissed = (fu16_t)va_arg(ap, unsigned int);
1531  reason = (fu16_t)va_arg(ap, unsigned int);
1532  va_end(ap);
1533 
1534  /* printf("missed %d messages from %s on channel %d (reason %d: %s)\n", nummissed, userinfo->sn, chan, reason, (reason<missedreasonslen)?missedreasons[reason]:"unknown"); */
1535 
1536  return 1;
1537}
1538
1539/*
1540 * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
1541 */
1542static int faimtest_parse_msgack(aim_session_t *sess, aim_frame_t *fr, ...)
1543{
1544  va_list ap;
1545  fu16_t type;
1546  char *sn = NULL;
1547 
1548  va_start(ap, fr);
1549  type = (fu16_t)va_arg(ap, unsigned int);
1550  sn = va_arg(ap, char *);
1551  va_end(ap);
1552 
1553  /* printf("msgack: 0x%04x / %s\n", type, sn); */
1554 
1555  return 1;
1556}
1557
1558static int faimtest_parse_ratechange(aim_session_t *sess, aim_frame_t *fr, ...)
1559{
1560  /*
1561  static char *codes[5] = {
1562    "invalid",
1563    "change",
1564    "warning",
1565    "limit",
1566    "limit cleared"
1567  };
1568  */
1569  va_list ap;
1570  fu16_t code, rateclass;
1571  fu32_t windowsize, clear, alert, limit, disconnect;
1572  fu32_t currentavg, maxavg;
1573 
1574  va_start(ap, fr); 
1575 
1576  /* See code explanations below */
1577  code = (fu16_t)va_arg(ap, unsigned int);
1578 
1579  /*
1580   * See comments above aim_parse_ratechange_middle() in aim_rxhandlers.c.
1581   */
1582  rateclass = (fu16_t)va_arg(ap, unsigned int);
1583 
1584  /*
1585   * Not sure what this is exactly.  I think its the temporal
1586   * relation factor (ie, how to make the rest of the numbers
1587   * make sense in the real world).
1588   */
1589  windowsize = va_arg(ap, fu32_t);
1590 
1591  /* Explained below */
1592  clear = va_arg(ap, fu32_t);
1593  alert = va_arg(ap, fu32_t);
1594  limit = va_arg(ap, fu32_t);
1595  disconnect = va_arg(ap, fu32_t);
1596  currentavg = va_arg(ap, fu32_t);
1597  maxavg = va_arg(ap, fu32_t);
1598 
1599  va_end(ap);
1600 
1601  /*
1602  printf("rate %s (rate class 0x%04x): curavg = %ld, maxavg = %ld, alert at %ld, clear warning at %ld, limit at %ld, disconnect at %ld (window size = %ld)\n",
1603         (code < 5)?codes[code]:"invalid",
1604         rateclass,
1605         currentavg, maxavg,
1606         alert, clear,
1607         limit, disconnect,
1608         windowsize);
1609  */
1610  return 1;
1611}
1612
1613static int faimtest_parse_evilnotify(aim_session_t *sess, aim_frame_t *fr, ...)
1614{
1615  va_list ap;
1616  fu16_t newevil;
1617  aim_userinfo_t *userinfo;
1618 
1619  va_start(ap, fr);
1620  newevil = (fu16_t)va_arg(ap, unsigned int);
1621  userinfo = va_arg(ap, aim_userinfo_t *);
1622  va_end(ap);
1623 
1624  /*
1625   * Evil Notifications that are lacking userinfo->sn are anon-warns
1626   * if they are an evil increases, but are not warnings at all if its
1627   * a decrease (its the natural backoff happening).
1628   *
1629   * newevil is passed as an int representing the new evil value times
1630   * ten.
1631   */
1632  /* printf("evil level change: new value = %2.1f%% (caused by %s)\n", ((float)newevil)/10, (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous"); */
1633 
1634  return 1;
1635}
1636
1637static int faimtest_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...)
1638{
1639  va_list ap;
1640  char *address, *SNs;
1641  int num;
1642  /* int i; */
1643 
1644  va_start(ap, fr);
1645  address = va_arg(ap, char *);
1646  num = va_arg(ap, int);
1647  SNs = va_arg(ap, char *);
1648  va_end(ap);
1649 
1650  /* printf("E-Mail Search Results for %s: ", address);
1651 
1652  for(i = 0; i < num; i++)
1653    printf("%s, ", &SNs[i*(MAXSNLEN+1)]);
1654  printf("\n");
1655  */
1656 
1657  return 1;
1658}
1659
1660static int faimtest_parse_searcherror(aim_session_t *sess, aim_frame_t *fr, ...)
1661{
1662  va_list ap;
1663  char *address;
1664 
1665  va_start(ap, fr);
1666  address = va_arg(ap, char *);
1667  va_end(ap);
1668 
1669  /* printf("E-Mail Search Results for %s: No Results or Invalid Email\n", address); */
1670 
1671  return 1;
1672}
1673
1674static int handlepopup(aim_session_t *sess, aim_frame_t *fr, ...)
1675{
1676  va_list ap;
1677  char *msg, *url;
1678  fu16_t width, height, delay;
1679 
1680  va_start(ap, fr);
1681  msg = va_arg(ap, char *);
1682  url = va_arg(ap, char *);
1683  width = va_arg(ap, unsigned int);
1684  height = va_arg(ap, unsigned int);
1685  delay = va_arg(ap, unsigned int);
1686  va_end(ap);
1687 
1688  /* printf("popup: (%dx%x:%d) %s (%s)\n", width, height, delay, msg, url); */
1689 
1690  return 1;
1691}
1692
1693static int serverpause(aim_session_t *sess, aim_frame_t *fr, ...)
1694{
1695  aim_sendpauseack(sess, fr->conn);
1696  return 1;
1697}
1698
1699static int migrate(aim_session_t *sess, aim_frame_t *fr, ...)
1700{
1701  va_list ap;
1702  aim_conn_t *bosconn;
1703  char *bosip;
1704  fu8_t *cookie;
1705 
1706  va_start(ap, fr);
1707  bosip = va_arg(ap, char *);
1708  cookie = va_arg(ap, fu8_t *);
1709  va_end(ap);
1710 
1711  /* printf("migration in progress -- new BOS is %s -- disconnecting\n", bosip); */
1712  aim_conn_kill(sess, &fr->conn);
1713 
1714  if (!(bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, bosip))) {
1715    /* printf("migrate: could not connect to BOS: internal error\n"); */
1716    return 1;
1717  } else if (bosconn->status & AIM_CONN_STATUS_CONNERR) {       
1718    /* printf("migrate: could not connect to BOS\n"); */
1719    aim_conn_kill(sess, &bosconn);
1720    return 1;
1721  }
1722 
1723  /* Login will happen all over again. */
1724  addcb_bos(sess, bosconn);
1725  aim_sendcookie(sess, bosconn, cookie);
1726  return 1;
1727}
1728
1729static int ssirights(aim_session_t *sess, aim_frame_t *fr, ...)
1730{
1731 
1732  /* printf("got SSI rights, requesting data\n"); */
1733  aim_ssi_reqdata(sess, fr->conn, 0, 0x0000);
1734 
1735  return 1;
1736}
1737
1738static int ssidata(aim_session_t *sess, aim_frame_t *fr, ...)
1739{
1740  va_list ap;
1741  fu8_t fmtver;
1742  fu16_t itemcount;
1743  fu32_t stamp;
1744  struct aim_ssi_item *list, *l;
1745 
1746  va_start(ap, fr);
1747  fmtver = va_arg(ap, unsigned int);
1748  itemcount = va_arg(ap, unsigned int);
1749  stamp = va_arg(ap, fu32_t);
1750  list = va_arg(ap, struct aim_ssi_item *);
1751  va_end(ap);
1752 
1753  /* printf("got SSI data: (0x%02x, %d items, %ld)\n", fmtver, itemcount, stamp); */
1754  for (l = list; l; l = l->next) {
1755    /* printf("\t0x%04x (%s) - 0x%04x/0x%04x\n", l->type, l->name, l->gid, l->bid); */
1756    /* printf("I would have printed data here!\n"); */
1757  }
1758 
1759  aim_ssi_enable(sess, fr->conn);
1760 
1761  return 1;
1762}
1763
1764static int ssidatanochange(aim_session_t *sess, aim_frame_t *fr, ...)
1765{
1766  /* printf("server says we have the latest SSI data already\n"); */
1767  aim_ssi_enable(sess, fr->conn);
1768  return 1;
1769}
1770
1771static int offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...)
1772{
1773  va_list ap;
1774  struct aim_icq_offlinemsg *msg;
1775 
1776  va_start(ap, fr);
1777  msg = va_arg(ap, struct aim_icq_offlinemsg *);
1778  va_end(ap);
1779 
1780  if (msg->type == 0x0001) {
1781    /* printf("offline message from %ld at %d/%d/%d %02d:%02d : %s\n", msg->sender, msg->year, msg->month, msg->day, msg->hour, msg->minute, msg->msg); */
1782  } else {
1783    /* printf("unknown offline message type 0x%04x\n", msg->type); */
1784  }
1785  return 1;
1786}
1787
1788static int offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...)
1789{
1790  /* Tell the server to delete them. */
1791  aim_icq_ackofflinemsgs(sess);
1792  return 1;
1793}
1794
1795
1796/******************** chat.c **************************/
1797
1798
1799static int faimtest_chat_join(aim_session_t *sess, aim_frame_t *fr, ...)
1800{
1801  va_list ap;
1802  aim_userinfo_t *userinfo;
1803  int count;
1804  /* int i; */
1805 
1806  va_start(ap, fr);
1807  count = va_arg(ap, int);
1808  userinfo = va_arg(ap, aim_userinfo_t *);
1809  va_end(ap);
1810
1811  /*
1812  printf("chat: %s:  New occupants have joined:\n", aim_chat_getname(fr->conn));
1813  for (i = 0; i < count; i++)
1814    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1815  */
1816  return 1;
1817}
1818
1819static int faimtest_chat_leave(aim_session_t *sess, aim_frame_t *fr, ...)
1820{
1821  aim_userinfo_t *userinfo;
1822  va_list ap;
1823  int count;
1824  /* int i; */
1825
1826 
1827  va_start(ap, fr);
1828  count = va_arg(ap, int);
1829  userinfo = va_arg(ap, aim_userinfo_t *);
1830  va_end(ap);
1831 
1832  /*
1833    printf("chat: %s:  Some occupants have left:\n", aim_chat_getname(fr->conn));
1834   
1835    for (i = 0; i < count; i++)
1836    printf("chat: %s: \t%s\n", aim_chat_getname(fr->conn), userinfo[i].sn);
1837  */
1838  return 1;
1839}
1840
1841static int faimtest_chat_infoupdate(aim_session_t *sess, aim_frame_t *fr, ...)
1842{
1843  va_list ap;
1844  aim_userinfo_t *userinfo;
1845  struct aim_chat_roominfo *roominfo;
1846  char *roomname;
1847  int usercount;
1848  char *roomdesc;
1849  fu16_t flags, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
1850  fu32_t creationtime;
1851  const char *croomname;
1852  /* int i; */
1853 
1854  croomname = aim_chat_getname(fr->conn);
1855 
1856  va_start(ap, fr);
1857  roominfo = va_arg(ap, struct aim_chat_roominfo *);
1858  roomname = va_arg(ap, char *);
1859  usercount = va_arg(ap, int);
1860  userinfo = va_arg(ap, aim_userinfo_t *);
1861  roomdesc = va_arg(ap, char *);
1862  flags = (fu16_t)va_arg(ap, unsigned int);
1863  creationtime = va_arg(ap, fu32_t);
1864  maxmsglen = (fu16_t)va_arg(ap, unsigned int);
1865  unknown_d2 = (fu16_t)va_arg(ap, unsigned int);
1866  unknown_d5 = (fu16_t)va_arg(ap, unsigned int);
1867  maxvisiblemsglen = (fu16_t)va_arg(ap, unsigned int);
1868  va_end(ap);
1869
1870  /*
1871  printf("chat: %s:  info update:\n", croomname);
1872  printf("chat: %s:  \tRoominfo: {%04x, %s, %04x}\n", croomname, roominfo->exchange, roominfo->name, roominfo->instance);
1873  printf("chat: %s:  \tRoomname: %s\n", croomname, roomname);
1874  printf("chat: %s:  \tRoomdesc: %s\n", croomname, roomdesc);
1875  printf("chat: %s:  \tOccupants: (%d)\n", croomname, usercount);
1876
1877  for (i = 0; i < usercount; i++)
1878    printf("chat: %s:  \t\t%s\n", croomname, userinfo[i].sn);
1879 
1880  printf("chat: %s:  \tRoom flags: 0x%04x (%s%s%s%s)\n",
1881         croomname, flags,
1882         (flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
1883         (flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
1884         (flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
1885         (flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
1886  printf("chat: %s:  \tCreation time: %lu (time_t)\n", croomname, creationtime);
1887  printf("chat: %s:  \tUnknown_d2: 0x%04x\n", croomname, unknown_d2);
1888  printf("chat: %s:  \tUnknown_d5: 0x%02x\n", croomname, unknown_d5);
1889  printf("chat: %s:  \tMax message length: %d bytes\n", croomname, maxmsglen);
1890  printf("chat: %s:  \tMax visible message length: %d bytes\n", croomname, maxvisiblemsglen);
1891  */
1892 
1893  return 1;
1894}
1895
1896static int faimtest_chat_incomingmsg(aim_session_t *sess, aim_frame_t *fr, ...)
1897{
1898  va_list ap;
1899  aim_userinfo_t *userinfo;
1900  char *msg;
1901  char tmpbuf[1152];
1902 
1903  va_start(ap, fr);
1904  userinfo = va_arg(ap, aim_userinfo_t *);     
1905  msg = va_arg(ap, char *);
1906  va_end(ap);
1907
1908  /*
1909  printf("chat: %s: incoming msg from %s: %s\n", aim_chat_getname(fr->conn), userinfo->sn, msg);
1910  */
1911 
1912  /*
1913   * Do an echo for testing purposes.  But not for ourselves ("oops!")
1914   */
1915  if (strcmp(userinfo->sn, sess->sn) != 0) {
1916    /* sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg); */
1917    aim_chat_send_im(sess, fr->conn, 0, tmpbuf, strlen(tmpbuf));
1918  }
1919 
1920  return 1;
1921}
1922
1923static int faimtest_chatnav_info(aim_session_t *sess, aim_frame_t *fr, ...)
1924{
1925  fu16_t type;
1926  va_list ap;
1927 
1928  va_start(ap, fr);
1929  type = (fu16_t)va_arg(ap, unsigned int);
1930 
1931  if (type == 0x0002) {
1932    int maxrooms;
1933    struct aim_chat_exchangeinfo *exchanges;
1934    int exchangecount;
1935    /* int i; */
1936   
1937    maxrooms = va_arg(ap, int);
1938    exchangecount = va_arg(ap, int);
1939    exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
1940    va_end(ap);
1941
1942    /*
1943    printf("chat info: Chat Rights:\n");
1944    printf("chat info: \tMax Concurrent Rooms: %d\n", maxrooms);
1945    printf("chat info: \tExchange List: (%d total)\n", exchangecount);
1946    for (i = 0; i < exchangecount; i++) {
1947      printf("chat info: \t\t%x: %s (%s/%s) (0x%04x = %s%s%s%s)\n",
1948             exchanges[i].number,
1949             exchanges[i].name,
1950             exchanges[i].charset1,
1951             exchanges[i].lang1,
1952             exchanges[i].flags,
1953             (exchanges[i].flags & AIM_CHATROOM_FLAG_EVILABLE) ? "Evilable, " : "",
1954             (exchanges[i].flags & AIM_CHATROOM_FLAG_NAV_ONLY) ? "Nav Only, " : "",
1955             (exchanges[i].flags & AIM_CHATROOM_FLAG_INSTANCING_ALLOWED) ? "Instancing allowed, " : "",
1956             (exchanges[i].flags & AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED) ? "Occupant peek allowed, " : "");
1957    }
1958    */
1959  } else if (type == 0x0008) {
1960    char *fqcn, *name, *ck;
1961    fu16_t instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
1962    fu8_t createperms;
1963    fu32_t createtime;
1964   
1965    fqcn = va_arg(ap, char *);
1966    instance = (fu16_t)va_arg(ap, unsigned int);
1967    exchange = (fu16_t)va_arg(ap, unsigned int);
1968    flags = (fu16_t)va_arg(ap, unsigned int);
1969    createtime = va_arg(ap, fu32_t);
1970    maxmsglen = (fu16_t)va_arg(ap, unsigned int);
1971    maxoccupancy = (fu16_t)va_arg(ap, unsigned int);
1972    createperms = (fu8_t)va_arg(ap, unsigned int);
1973    unknown = (fu16_t)va_arg(ap, unsigned int);
1974    name = va_arg(ap, char *);
1975    ck = va_arg(ap, char *);
1976    va_end(ap);
1977   
1978    /* printf("received room create reply for %s/0x%04x\n", fqcn, exchange); */
1979   
1980  } else {
1981    va_end(ap);
1982    /* printf("chatnav info: unknown type (%04x)\n", type); */
1983  }
1984 
1985  return 1;
1986}
1987
1988static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...)
1989{
1990
1991  aim_clientready(sess, fr->conn);
1992 
1993  if (fr->conn->type == AIM_CONN_TYPE_CHATNAV) {
1994    /* printf("chatnav ready\n"); */
1995    aim_conn_addhandler(sess, fr->conn, 0x000d, 0x0001, faimtest_parse_genericerr, 0);
1996    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, faimtest_chatnav_info, 0);
1997    aim_chatnav_reqrights(sess, fr->conn);
1998  } else if (fr->conn->type == AIM_CONN_TYPE_CHAT) {
1999    /* printf("chat ready\n"); */
2000    aim_conn_addhandler(sess, fr->conn, 0x000e, 0x0001, faimtest_parse_genericerr, 0);
2001    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, faimtest_chat_join, 0);
2002    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, faimtest_chat_leave, 0);
2003    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, faimtest_chat_infoupdate, 0);
2004    aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, faimtest_chat_incomingmsg, 0);
2005  }
2006  return 1;
2007}
2008
2009void chatnav_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
2010{
2011  aim_conn_t *tstconn;
2012 
2013  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, redir->ip);
2014  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
2015    /* printf("unable to connect to chat(nav) server\n"); */
2016    if (tstconn)
2017      aim_conn_kill(sess, &tstconn);
2018    return;
2019  }
2020 
2021  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
2022  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
2023  aim_sendcookie(sess, tstconn, redir->cookie);
2024  /* printf("chatnav: connected\n"); */
2025  return;
2026}
2027
2028/* XXX this needs instance too */
2029void chat_redirect(aim_session_t *sess, struct aim_redirect_data *redir)
2030{
2031  aim_conn_t *tstconn;
2032 
2033  tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, redir->ip);
2034  if (!tstconn || (tstconn->status & AIM_CONN_STATUS_RESOLVERR)) {
2035    /* printf("unable to connect to chat server\n"); */
2036    if (tstconn) aim_conn_kill(sess, &tstconn);
2037    return; 
2038  }             
2039  /* printf("chat: connected to %s instance %d on exchange %d\n", redir->chat.room, redir->chat.instance, redir->chat.exchange); */
2040 
2041  /*
2042   * We must do this to attach the stored name to the connection!
2043   */
2044  aim_chat_attachname(tstconn, redir->chat.exchange, redir->chat.room, redir->chat.instance);
2045  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNCOMPLETE, faimtest_conncomplete, 0);
2046  aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_chat, 0);
2047  aim_sendcookie(sess, tstconn, redir->cookie);
2048  return;       
2049}
2050
2051
2052
2053
2054/******************************************* ft.c ******************************************/
2055
2056
2057static int directim_incoming(aim_session_t *sess, aim_frame_t *fr, ...)
2058{
2059  va_list ap;
2060  char *sn, *msg;
2061 
2062  va_start(ap, fr);
2063  sn = va_arg(ap, char *);
2064  msg = va_arg(ap, char *);
2065  va_end(ap);
2066 
2067  /* printf("Directim from %s: %s\n", sn, msg); */
2068  if (strstr(msg, "sendmsg")) {
2069    int i;
2070   
2071    i = atoi(strstr(msg, "sendmsg")+8);
2072    if (i < 10000) {
2073      char *newbuf;
2074      int z;
2075     
2076      newbuf = malloc(i+1);
2077      for (z = 0; z < i; z++)
2078        newbuf[z] = (z % 10)+0x30;
2079      newbuf[i] = '\0';
2080      aim_send_im_direct(sess, fr->conn, newbuf);
2081      free(newbuf);
2082    }
2083  } else if (strstr(msg, "goodday")) {
2084    aim_send_im_direct(sess, fr->conn, "Good day to you, too");
2085  } else {
2086    char newmsg[1024];
2087    snprintf(newmsg, sizeof(newmsg), "unknown (%s)\n", msg);
2088    aim_send_im_direct(sess, fr->conn, newmsg);
2089  }
2090
2091  return 1;
2092}
2093
2094static int directim_typing(aim_session_t *sess, aim_frame_t *fr, ...)
2095{
2096  va_list ap;
2097  char *sn;
2098 
2099  va_start(ap, fr);
2100  sn = va_arg(ap, char *);
2101  va_end(ap);
2102  /* printf("ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", sn); */
2103  return 1;
2104}
2105
2106static int faimtest_directim_initiate(aim_session_t *sess, aim_frame_t *fr, ...)
2107{
2108  va_list ap;
2109  aim_conn_t *newconn, *listenerconn;
2110 
2111  va_start(ap, fr);
2112  newconn = va_arg(ap, aim_conn_t *);
2113  listenerconn = va_arg(ap, aim_conn_t *);
2114  va_end(ap);
2115 
2116  aim_conn_close(listenerconn);
2117  aim_conn_kill(sess, &listenerconn);
2118 
2119  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, directim_incoming, 0);
2120  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, directim_typing, 0);
2121 
2122  aim_send_im_direct(sess, newconn, "goodday");
2123 
2124  /* printf("OFT: DirectIM: connected to %s\n", aim_directim_getsn(newconn)); */
2125 
2126  return 1;
2127}
2128
2129static int faimtest_getfile_filereq(aim_session_t *ses, aim_frame_t *fr, ...)
2130{
2131  va_list ap;
2132  aim_conn_t *oftconn;
2133  struct aim_fileheader_t *fh;
2134  fu8_t *cookie;
2135 
2136  va_start(ap, fr);
2137  oftconn = va_arg(ap, aim_conn_t *);
2138  fh = va_arg(ap, struct aim_fileheader_t *);
2139  cookie = va_arg(ap, fu8_t *);
2140  va_end(ap);
2141 
2142  /* printf("request for file %s.\n", fh->name); */
2143 
2144  return 1;
2145}
2146
2147static int faimtest_getfile_filesend(aim_session_t *sess, aim_frame_t *fr, ...)
2148{
2149  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
2150  va_list ap;
2151  aim_conn_t *oftconn;
2152  struct aim_fileheader_t *fh;
2153  char *path;
2154  fu8_t *cookie;
2155  int pos, bufpos = 0, bufsize = 2048, i;
2156  char *buf;
2157  FILE *file;
2158 
2159  va_start(ap, fr);
2160  oftconn = va_arg(ap, aim_conn_t *);
2161  fh = va_arg(ap, struct aim_fileheader_t *);
2162  cookie = va_arg(ap, fu8_t *);
2163  va_end(ap);
2164 
2165  /* printf("sending file %s(%ld).\n", fh->name, fh->size); */
2166
2167  if (!(buf = malloc(2048)))
2168    return -1;
2169 
2170  if (!(path = (char *)calloc(1, strlen(priv->listingpath) +strlen(fh->name)+2))) {
2171    /* perror("calloc"); */
2172    /* printf("error in calloc of path\n"); */
2173   
2174    return 0; /* XXX: no idea what winaim expects here =) */
2175  }
2176
2177  snprintf(path, strlen(priv->listingpath)+strlen(fh->name)+2, "%s/%s", priv->listingpath, fh->name);
2178 
2179  if (!(file = fopen(path, "r"))) {
2180    /* printf("getfile_send fopen failed for %s. damn.\n", path); */
2181    return 0;
2182  }
2183 
2184  /*
2185   * This is a mess. Remember that faimtest is demonstration code
2186   * only and for the sake of the gods, don't use this code in any
2187   * of your clients. --mid
2188   */
2189  for(pos = 0; pos < fh->size; pos++) {
2190   
2191    bufpos = pos % bufsize;
2192   
2193    if (bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
2194      if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
2195        /* perror("faim: getfile_send: write1"); */
2196        /* printf("faim: getfile_send: whoopsy, didn't write it all...\n"); */
2197        free(buf);   
2198        return 0;
2199      }
2200    }
2201   
2202    if( (buf[bufpos] = fgetc(file)) == EOF) {
2203      if(pos != fh->size) {
2204        /* printf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size); */
2205        free(buf);   
2206        return 0;
2207      }
2208    }     
2209    /* printf("%c(0x%02x) ", buf[pos], buf[pos]); */
2210  }
2211 
2212  if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
2213    /* perror("faim: getfile_send: write2"); */
2214    /* printf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n"); */
2215    free(buf);   
2216    return 0;
2217  }
2218 
2219  free(buf);
2220  free(fh);
2221 
2222  return 1;
2223}
2224
2225static int faimtest_getfile_complete(aim_session_t *sess, aim_frame_t *fr, ...) 
2226{
2227  va_list ap;
2228  aim_conn_t *conn;
2229  struct aim_fileheader_t *fh;
2230 
2231  va_start(ap, fr);
2232  conn = va_arg(ap, aim_conn_t *);
2233  fh = va_arg(ap, struct aim_fileheader_t *);
2234  va_end(ap);
2235 
2236  /* printf("completed file transfer for %s.\n", fh->name); */
2237 
2238  aim_conn_close(conn);
2239  aim_conn_kill(sess, &conn);
2240 
2241  return 1;
2242}
2243
2244static int faimtest_getfile_disconnect(aim_session_t *sess, aim_frame_t *fr, ...)
2245{
2246  va_list ap;
2247  aim_conn_t *conn;
2248  char *sn;
2249 
2250  va_start(ap, fr);
2251  conn = va_arg(ap, aim_conn_t *);
2252  sn = va_arg(ap, char *);
2253  va_end(ap);
2254 
2255  aim_conn_kill(sess, &conn);
2256 
2257  /* printf("getfile: disconnected from %s\n", sn); */
2258 
2259  return 1;
2260}
2261
2262static int faimtest_getfile_listing(aim_session_t *sess, aim_frame_t *fr, ...)
2263{
2264  va_list ap;
2265  aim_conn_t *conn;
2266  char *listing;
2267  struct aim_filetransfer_priv *ft;
2268  char *filename, *nameend, *sizec;
2269  int filesize, namelen;
2270 
2271  va_start(ap, fr);
2272  conn = va_arg(ap, aim_conn_t *);
2273  ft = va_arg(ap, struct aim_filetransfer_priv *);
2274  listing = va_arg(ap, char *);
2275  va_end(ap);
2276 
2277  /* printf("listing on %d==================\n%s\n===========\n", conn->fd, listing); */
2278 
2279  nameend = strstr(listing+0x1a, "\r");
2280  namelen = nameend - (listing + 0x1a);
2281 
2282  filename = malloc(namelen + 1);
2283  strncpy(filename, listing+0x1a, namelen);
2284  filename[namelen] = 0x00;
2285 
2286  sizec = malloc(8+1);
2287  memcpy(sizec, listing + 0x11, 8);
2288  sizec[8] = 0x00;
2289 
2290  filesize =  strtol(sizec, (char **)NULL, 10);
2291 
2292  /* printf("requesting %d %s(%d long)\n", namelen, filename, filesize); */
2293 
2294  aim_oft_getfile_request(sess, conn, filename, filesize);
2295 
2296  free(filename);
2297  free(sizec);
2298 
2299  return 0;
2300}
2301
2302static int faimtest_getfile_listingreq(aim_session_t *sess, aim_frame_t *fr, ...)
2303{
2304  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
2305  va_list ap;
2306  aim_conn_t *oftconn;
2307  struct aim_fileheader_t *fh;
2308  int pos, bufpos = 0, bufsize = 2048, i;
2309  char *buf;
2310 
2311  va_start(ap, fr);
2312  oftconn = va_arg(ap, aim_conn_t *);
2313  fh = va_arg(ap, struct aim_fileheader_t *);
2314  va_end(ap);
2315 
2316  /* printf("sending listing of size %ld\n", fh->size); */
2317
2318  if(!(buf = malloc(2048))) return -1;
2319 
2320  for(pos = 0; pos < fh->size; pos++) {
2321    bufpos = pos % bufsize;
2322    if(bufpos == 0 && pos > 0) { /* filled our buffer. spit it across the wire */
2323      if ( (i = send(oftconn->fd, buf, bufsize, 0)) != bufsize ) {
2324        /* perror("faim: getfile_send: write1"); */
2325        /* printf("faim: getfile_send: whoopsy, didn't write it all...\n"); */
2326        free(buf);   
2327        return 0;
2328      }
2329    }
2330    if( (buf[bufpos] = fgetc(priv->listingfile)) == EOF) {
2331      if(pos != fh->size) {
2332        /* printf("faim: getfile_send: hrm... apparent early EOF at pos 0x%x of 0x%lx\n", pos, fh->size); */
2333        free(buf);   
2334        return 0;
2335      }
2336    }     
2337  }
2338 
2339  if( (i = send(oftconn->fd, buf, bufpos+1, 0)) != (bufpos+1)) {
2340    /* perror("faim: getfile_send: write2"); */
2341    /* printf("faim: getfile_send cleanup: whoopsy, didn't write it all...\n"); */
2342    free(buf);   
2343    return 0;
2344  }
2345 
2346  /* printf("sent listing\n"); */
2347  free(buf);
2348 
2349  return 0;
2350}
2351
2352static int faimtest_getfile_receive(aim_session_t *sess, aim_frame_t *fr, ...)
2353{
2354  va_list ap;
2355  aim_conn_t *conn;
2356  struct aim_filetransfer_priv *ft;
2357  unsigned char data;
2358  int pos;
2359 
2360  va_start(ap, fr);
2361  conn = va_arg(ap, aim_conn_t *);
2362  ft = va_arg(ap, struct aim_filetransfer_priv *);
2363  va_end(ap);
2364
2365  /* printf("receiving %ld bytes of file data for %s:\n\t", ft->fh.size, ft->fh.name); */
2366
2367  for(pos = 0; pos < ft->fh.size; pos++) {
2368    read(conn->fd, &data, 1);
2369    /* printf("%c(%02x) ", data, data); */
2370  }
2371
2372  /* printf("\n"); */
2373
2374  aim_oft_getfile_end(sess, conn);
2375  return 0;
2376}
2377
2378static int faimtest_getfile_state4(aim_session_t *sess, aim_frame_t *fr, ...)
2379{
2380  va_list ap;
2381  aim_conn_t *conn;
2382 
2383  va_start(ap, fr);
2384  conn = va_arg(ap, aim_conn_t *);
2385  va_end(ap);
2386 
2387  aim_conn_close(conn);
2388  aim_conn_kill(sess, &conn);
2389 
2390  return 0;
2391}
2392
2393static int faimtest_getfile_initiate(aim_session_t *sess, aim_frame_t *fr, ...)
2394{
2395  va_list ap;
2396  aim_conn_t *conn, *listenerconn;
2397  struct aim_filetransfer_priv *priv;
2398 
2399  va_start(ap, fr);
2400  conn = va_arg(ap, aim_conn_t *);
2401  listenerconn = va_arg(ap, aim_conn_t *);
2402  va_end(ap);
2403 
2404  aim_conn_close(listenerconn);
2405  aim_conn_kill(sess, &listenerconn);
2406 
2407  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ,  faimtest_getfile_filereq, 0);
2408  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
2409  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);     
2410  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);     
2411  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTING, faimtest_getfile_listing, 0);
2412  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0);
2413  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILERECEIVE, faimtest_getfile_receive, 0);
2414  aim_conn_addhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILESTATE4, faimtest_getfile_state4, 0);
2415 
2416  priv = (struct aim_filetransfer_priv *)conn->priv;
2417 
2418  /* printf("getfile: %s (%s) connected to us on %d\n", priv->sn, priv->ip, conn->fd); */
2419 
2420  return 1;
2421}
2422
2423void getfile_start(aim_session_t *sess, aim_conn_t *conn, const char *sn)
2424{
2425  aim_conn_t *newconn;
2426 
2427  newconn = aim_getfile_initiate(sess, conn, sn);
2428  /* printf("getting file listing from %s\n", sn); */
2429  aim_conn_addhandler(sess, newconn,  AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEINITIATE, faimtest_getfile_initiate,0);
2430 
2431  return;
2432}
2433
2434void getfile_requested(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args)
2435{
2436  struct owlfaim_priv *priv = (struct owlfaim_priv *)sess->aux_data;
2437  aim_conn_t *newconn;
2438  struct aim_fileheader_t *fh;
2439 
2440  printf("get file request from %s (at %s/%s/%s) %x\n", userinfo->sn, args->clientip, args->clientip2, args->verifiedip, args->reqclass);
2441  fh = aim_getlisting(sess, priv->listingfile);
2442  newconn = aim_accepttransfer(sess, conn, userinfo->sn, args->cookie, args->clientip, fh->totfiles, fh->totsize, fh->size, fh->checksum, args->reqclass);
2443  free(fh);
2444
2445  if ( (!newconn) || (newconn->fd == -1) ) {
2446    printf("getfile: requestconn: apparent error in accepttransfer\n");
2447    if (newconn) aim_conn_kill(sess, &newconn);
2448    return;
2449  }
2450 
2451  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILELISTINGREQ, faimtest_getfile_listingreq, 0);
2452  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ,  faimtest_getfile_filereq, 0);
2453  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILESEND, faimtest_getfile_filesend, 0);
2454  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILECOMPLETE, faimtest_getfile_complete, 0);     
2455  aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEDISCONNECT, faimtest_getfile_disconnect, 0);     
2456 
2457  /* printf("getfile connect succeeded, handlers added.\n"); */
2458 
2459  return;
2460}
2461
2462void directim_start(aim_session_t *sess, const char *sn)
2463{
2464  aim_conn_t *newconn;
2465 
2466  /* printf("opening directim to %s\n", sn); */
2467  newconn = aim_directim_initiate(sess, sn);
2468  if (!newconn || (newconn->fd == -1)) {
2469    /* printf("connection failed!\n"); */
2470    if (newconn) aim_conn_kill(sess, &newconn);
2471  } else {
2472    aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE, faimtest_directim_initiate, 0);
2473  }
2474  return;
2475}
2476
2477void directim_requested(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args)
2478{
2479  aim_conn_t *newconn;
2480 
2481  /* printf("OFT: DirectIM: request from %s (%s/%s/%s)\n", userinfo->sn, args->clientip, args->clientip2, args->verifiedip); */
2482 
2483  newconn = aim_directim_connect(sess, userinfo->sn, args->clientip, args->cookie);
2484  if (!newconn || (newconn->fd == -1)) {
2485    /* printf("icbm: imimage: could not connect\n"); */
2486    if (newconn) aim_conn_kill(sess, &newconn);
2487  } else {
2488    aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, directim_incoming, 0);
2489    aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, directim_typing, 0);
2490    /* printf("OFT: DirectIM: connected to %s\n", userinfo->sn); */
2491    aim_send_im_direct(sess, newconn, "goodday");
2492  }
2493}
2494
2495
2496/****************************************/
2497
2498/*
2499static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) {
2500        struct gaim_connection *gc = sess->aux_data;
2501        struct oscar_data *od = gc->proto_data;
2502        aim_userinfo_t *info;
2503        time_t time_idle = 0, signon = 0;
2504        int type = 0;
2505        int caps = 0;
2506        char *tmp;
2507
2508        va_list ap;
2509        va_start(ap, fr);
2510        info = va_arg(ap, aim_userinfo_t *);
2511        va_end(ap);
2512
2513        if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES)
2514                caps = info->capabilities;
2515        if (info->flags & AIM_FLAG_ACTIVEBUDDY)
2516                type |= UC_AB;
2517
2518        if ((!od->icq) && (info->present & AIM_USERINFO_PRESENT_FLAGS)) {
2519                        if (info->flags & AIM_FLAG_UNCONFIRMED)
2520                                type |= UC_UNCONFIRMED;
2521                        if (info->flags & AIM_FLAG_ADMINISTRATOR)
2522                                type |= UC_ADMIN;
2523                        if (info->flags & AIM_FLAG_AOL)
2524                                type |= UC_AOL;
2525                        if (info->flags & AIM_FLAG_FREE)
2526                                type |= UC_NORMAL;
2527                        if (info->flags & AIM_FLAG_AWAY)
2528                                type |= UC_UNAVAILABLE;
2529                        if (info->flags & AIM_FLAG_WIRELESS)
2530                                type |= UC_WIRELESS;
2531        }
2532        if (info->present & AIM_USERINFO_PRESENT_ICQEXTSTATUS) {
2533                type = (info->icqinfo.status << 16);
2534                if (!(info->icqinfo.status & AIM_ICQ_STATE_CHAT) &&
2535                      (info->icqinfo.status != AIM_ICQ_STATE_NORMAL)) {
2536                        type |= UC_UNAVAILABLE;
2537                }
2538        }
2539
2540        if (caps & AIM_CAPS_ICQ)
2541                caps ^= AIM_CAPS_ICQ;
2542
2543        if (info->present & AIM_USERINFO_PRESENT_IDLE) {
2544                time(&time_idle);
2545                time_idle -= info->idletime*60;
2546        }
2547
2548        if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)
2549                signon = time(NULL) - info->sessionlen;
2550
2551        tmp = g_strdup(normalize(gc->username));
2552        if (!strcmp(tmp, normalize(info->sn)))
2553                g_snprintf(gc->displayname, sizeof(gc->displayname), "%s", info->sn);
2554        g_free(tmp);
2555
2556        serv_got_update(gc, info->sn, 1, info->warnlevel/10, signon,
2557                        time_idle, type, caps);
2558
2559        return 1;
2560}
2561*/
Note: See TracBrowser for help on using the repository browser.