source: aim.c @ 290f290

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