source: aim.c @ ae4cd12

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