source: aim.c @ aa5f725

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