--- /dev/null
+
+Anyone else want to be in here?
+
+---
+
+N: Adam Fritzler
+H: mid
+E: mid@auk.cx
+W: http://www.auk.cx/~mid,http://www.auk.cx/faim
+D: Wrote most of the wap of crap that you see before you.
+
+N: Josh Myer
+E: josh@joshisanerd.com
+D: [I'm sure he did something -mid]
+
+N: Daniel Reed
+H: n, linuxkitty
+E: n@ml.org
+W: http://users.n.ml.org/n/
+D: Fixed aim_snac.c
+
+N: Eric Warmenhoven
+E: warmenhoven@linux.com
+D: Some OFT info, author of the faim interface for gaim
+
+N: Brock Wilcox
+H: awwaiid
+E: awwaiid@auk.cx
+D: Figured out original password roasting
+
+
No release numbers
------------------
+ - The week prior to Fri Jun 16 19:37:09 UTC 2000
+ - Rethought the rendezvous stuff. DEFINIT WORK IN PROGRESS
+ - Do not bother trying to use this. This will probably break
+ your clients. You may or may not want to fix them, since
+ I may change it again soon.
+ - I REPEAT: This really is a developer-only version. It barely
+ compiles. I'm just committing it so I don't have so many
+ trees floating around.
+ - Added stuff to support OFT as well as OSCAR protocols
+ - Added aim_send_im_direct() for directim ("IM Image")
+ - Added caps getting/putting routines
+ - Added more aim_login fixes to avoid more AOL stupidity
+ - This is the same as went to libfaim-devel yesterday, so don't upgrade
+ just to get these changes.
+ - Removed aimicq_encode_password -- now use the same table
+ for both ICQ and AIM
+ - Added AUTHORS
+
- Tue Jun 6 01:36:48 UTC 2000
- Inverted gethostbyname2() check. Not sure how that ended up
in that state.
struct command_tx_struct *newpacket;
int curbyte=0;
- if (!(newpacket = aim_tx_new(0x0001, conn, 4+2+2+AIM_COOKIELEN)))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0001, conn, 4+2+2+AIM_COOKIELEN)))
return -1;
newpacket->lock = 1;
struct command_tx_struct *newpacket;
int curbyte = 0;
- if (!(newpacket = aim_tx_new(0x0002, conn, 26)))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 26)))
return -1;
newpacket->lock = 1;
struct command_tx_struct *newpacket;
int i;
- if (!(newpacket = aim_tx_new(0x0002, conn, 10+4+strlen(current)+4+strlen(new))))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+4+strlen(current)+4+strlen(new))))
return -1;
newpacket->lock = 1;
if(!sn)
return -1;
- if (!(newpacket = aim_tx_new(0x0002, conn, 10+1+strlen(sn))))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+1+strlen(sn))))
return -1;
newpacket->lock = 1;
if(!sn)
return -1;
- if (!(newpacket = aim_tx_new(0x0002, conn, 10+1+strlen(sn))))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+1+strlen(sn))))
return -1;
newpacket->lock = 1;
if (!sess || !conn || !msg)
return 0;
- if (!(newpacket = aim_tx_new(0x0002, conn, 1152)))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
return -1;
newpacket->lock = 1; /* lock struct */
if (!sess || !conn || !roomname)
return 0;
- if (!(newpacket = aim_tx_new(0x0002, conn, 10+9+strlen(roomname)+2)))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+9+strlen(roomname)+2)))
return -1;
newpacket->lock = 1;
struct command_tx_struct *newpacket;
int i;
- if (!(newpacket = aim_tx_new(0x0002, conn, 0x20)))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 0x20)))
return -1;
newpacket->lock = 1;
if (!sess || !conn || !sn || !msg || !roomname)
return 0;
- if (!(newpacket = aim_tx_new(0x0002, conn, 1152+strlen(sn)+strlen(roomname)+strlen(msg))))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152+strlen(sn)+strlen(roomname)+strlen(msg))))
return -1;
newpacket->lock = 1;
struct command_tx_struct *newpacket;
int i;
- if (!(newpacket = aim_tx_new(0x0002, conn, 0x20)))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 0x20)))
return -1;
newpacket->lock = 1;
int i;
struct aim_snac_t snac;
- if (!(newpacket = aim_tx_new(0x0002, conn, 10+12+strlen("invite")+strlen(name))))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+12+strlen("invite")+strlen(name))))
return -1;
newpacket->lock = 1;
if (strlen(msg) >= MAXMSGLEN)
return -1;
- if (!(newpacket = aim_tx_new(0x0002, conn, strlen(msg)+256)))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, strlen(msg)+256)))
return -1;
newpacket->lock = 1; /* lock struct */
return (sess->snac_nextid++);
}
+struct aim_directim_priv {
+ unsigned char cookie[8];
+ char sn[MAXSNLEN+1];
+};
+
+int aim_send_im_direct(struct aim_session_t *sess,
+ struct aim_conn_t *conn,
+ char *msg)
+{
+ struct command_tx_struct *newpacket;
+ struct aim_directim_priv *priv = NULL;
+ int i;
+
+ if (strlen(msg) >= MAXMSGLEN)
+ return -1;
+
+ if (!sess || !conn || (conn->type != AIM_CONN_TYPE_RENDEZVOUS) || !conn->priv) {
+ printf("faim: directim: invalid arguments\n");
+ return -1;
+ }
+
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OFT, 0x0001, conn, strlen(msg)))) {
+ printf("faim: directim: tx_new failed\n");
+ return -1;
+ }
+
+ newpacket->lock = 1; /* lock struct */
+
+ priv = (struct aim_directim_priv *)conn->priv;
+
+ newpacket->hdr.oft.hdr2len = 0x44;
+
+ if (!(newpacket->hdr.oft.hdr2 = malloc(newpacket->hdr.oft.hdr2len))) {
+ free(newpacket);
+ return -1;
+ }
+
+ i = 0;
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0006);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+
+ i += aimutil_putstr(newpacket->hdr.oft.hdr2+i, priv->cookie, 8);
+
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+
+ i += aimutil_put32(newpacket->hdr.oft.hdr2+i, strlen(msg));
+
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+
+ i += aimutil_putstr(newpacket->hdr.oft.hdr2+i, sess->logininfo.screen_name, strlen(sess->logininfo.screen_name));
+
+ i = 52;
+ i += aimutil_put8(newpacket->hdr.oft.hdr2+i, 0x00);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+ i += aimutil_put16(newpacket->hdr.oft.hdr2+i, 0x0000);
+
+ memcpy(newpacket->data, msg, strlen(msg));
+
+ newpacket->lock = 0;
+
+ aim_tx_enqueue(sess, newpacket);
+
+ return 0;
+}
+
/*
* It can easily be said that parsing ICBMs is THE single
* most difficult thing to do in the in AIM protocol. In
struct aim_tlv_t *block1;
struct aim_tlvlist_t *list2;
struct aim_tlv_t *tmptlv;
- struct aim_tlv_t *miscinfo;
unsigned short reqclass = 0;
- int a;
+ unsigned short status = 0;
/* Class. */
if ((tmptlv = aim_gettlv(tlvlist, 0x0001, 1)))
return 1; /* major problem */
}
- a = 0x1a; /* skip -- not sure what this information is! */
+ /*
+ * First two bytes represent the status of the connection.
+ *
+ * 0 is a request, 2 is an accept
+ */
+ status = aimutil_get16(block1->value+0);
+
+ /*
+ * Next comes the cookie. Should match the ICBM cookie.
+ */
+ if (memcmp(block1->value+2, cookie, 8) != 0)
+ printf("faim: rend: warning cookies don't match!\n");
/*
- * XXX: Ignore if there's no data, only cookie information.
+ * The next 16bytes are a capability block so we can
+ * identify what type of rendezvous this is.
*
- * Its probably just an accepted invitation or something.
- *
+ * Thanks to Eric Warmenhoven <warmenhoven@linux.com> (of GAIM)
+ * for pointing some of this out to me. In fact, a lot of
+ * the client-to-client info comes from the work of the GAIM
+ * developers. Thanks!
+ *
+ * Read off one capability string and we should have it ID'd.
+ *
*/
- if (block1->length <= 0x1a) {
+ reqclass = aim_getcap(block1->value+2+8, 0x10);
+ if (reqclass == 0x0000) {
+ printf("faim: rend: no ID block\n");
aim_freetlvchain(&tlvlist);
return 1;
}
- list2 = aim_readtlvchain(block1->value+a, block1->length-a);
-
- if (!(miscinfo = aim_gettlv(list2, 0x2711, 1))) {
+ /*
+ * What follows may be TLVs or nothing, depending on the
+ * purpose of the message.
+ *
+ * Ack packets for instance have nothing more to them.
+ */
+ list2 = aim_readtlvchain(block1->value+2+8+16, block1->length-2-8-16);
+
+ if (!list2 || ((reqclass != AIM_CAPS_IMIMAGE) && !(aim_gettlv(list2, 0x2711, 1)))) {
struct aim_msgcookie_t *cook;
if ((cook = aim_uncachecookie(sess, cookie)) == NULL) {
- printf("faim: no 0x2711 info TLV in rendezvous and its not in cache!\n");
+ printf("faim: non-data rendezvous thats not in cache!\n");
aim_freetlvchain(&list2);
aim_freetlvchain(&tlvlist);
return 1;
}
- if (cook->type == 1) {
+ if (cook->type == AIM_CAPS_SENDFILE) {
struct aim_filetransfer_t *ft;
if (cook->data) {
if ((errortlv = aim_gettlv(list2, 0x000b, 1))) {
errorcode = aimutil_get16(errortlv->value);
}
- printf("faim: transfer from %s (%s) for %s cancelled (error code %d)\n", ft->sender, ft->ip, ft->filename, errorcode);
+ if (errorcode) {
+ printf("faim: transfer from %s (%s) for %s cancelled (error code %d)\n", ft->sender, ft->ip, ft->filename, errorcode);
+ } else if (status == 0x0002) { /* connection accepted */
+ printf("faim: transfer from %s (%s) for %s accepted\n", ft->sender, ft->ip, ft->filename);
+ }
free(cook->data);
} else {
printf("faim: not data attached to file transfer\n");
}
-
+ } else if (cook->type == AIM_CAPS_VOICE) {
+ printf("faim: voice request cancelled\n");
} else {
printf("faim: unknown cookie cache type %d\n", cook->type);
}
free(cook);
+ if (list2)
+ aim_freetlvchain(&list2);
+ aim_freetlvchain(&tlvlist);
return 1;
}
-
/*
- * Parse the first two bytes of the 0x2711 TLV.
- *
- * This can be interpretted in a couple ways.
- *
- * It could be said that its a service type or some such and
- * that voice is 0, file transfer is 1, and chat is 4 (and 5).
- *
- * Or it could be said that its an exchange value. Exchanges
- * four and five are for chat, voice is on exchange zero and
- * file transfer is done on exchange 1.
- *
- * It should work out the same no how its thought of.
- *
+ * The rest of the handling depends on what type it is.
*/
- reqclass = aimutil_get16(miscinfo->value+0);
-
- switch (reqclass) {
- case AIM_RENDEZVOUS_VOICE: {
+ if (reqclass & AIM_CAPS_BUDDYICON) {
+ printf("faim: rend: buddy icon!\n");
+ } else if (reqclass & AIM_CAPS_VOICE) {
+ struct aim_msgcookie_t cachedcook;
+
+ printf("faim: rend: voice!\n");
+
+ memcpy(cachedcook.cookie, cookie, 8);
+ cachedcook.type = AIM_CAPS_VOICE;
+ cachedcook.data = NULL;
+ if (aim_cachecookie(sess, &cachedcook) != 0)
+ printf("faim: ERROR caching message cookie\n");
/* XXX: implement all this */
reqclass,
&userinfo);
}
- break;
- }
- case AIM_RENDEZVOUS_FILETRANSFER: {
+ } else if (reqclass & AIM_CAPS_IMIMAGE) {
char ip[30];
- char *desc = NULL;
struct aim_msgcookie_t cachedcook;
- struct aim_filetransfer_t *ft;
memset(ip, 0, sizeof(ip));
aimutil_get8(iptlv->value+1),
aimutil_get8(iptlv->value+2),
aimutil_get8(iptlv->value+3),
- aimutil_get16(porttlv->value));
+ 4443 /*aimutil_get16(porttlv->value)*/);
}
- if (aim_gettlv(list2, 0x000c, 1)) {
- desc = aim_gettlv_str(list2, 0x000c, 1);
- }
-
- printf("faim: rend: file transfer request from %s for %s: %s (%s)\n",
+ printf("faim: rend: directIM request from %s (%s)\n",
userinfo.sn,
- miscinfo->value+8,
- desc,
ip);
+
+ {
+ struct aim_conn_t *newconn;
+
+ newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, ip);
+ if (!newconn || (newconn->fd == -1)) {
+ printf("could not connect to %s\n", ip);
+ perror("aim_newconn");
+ aim_conn_kill(sess, &newconn);
+ } else {
+ struct aim_directim_priv *priv;
+ priv = (struct aim_directim_priv *)malloc(sizeof(struct aim_directim_priv));
+ memcpy(priv->cookie, cookie, 8);
+ strncpy(priv->sn, userinfo.sn, MAXSNLEN);
+ newconn->priv = priv;
+ printf("faim: connected to peer (fd = %d)\n", newconn->fd);
+ }
+ }
+#if 0
memcpy(cachedcook.cookie, cookie, 8);
- memcpy(cachedcook.extended, block1->value+10, 16);
ft = malloc(sizeof(struct aim_filetransfer_t));
strncpy(ft->sender, userinfo.sn, sizeof(ft->sender));
strncpy(ft->ip, ip, sizeof(ft->ip));
ft->filename = strdup(miscinfo->value+8);
- cachedcook.type = 1;
+ cachedcook.type = AIM_CAPS_SENDFILE;
cachedcook.data = ft;
if (aim_cachecookie(sess, &cachedcook) != 0)
printf("faim: ERROR caching message cookie\n");
-
-
- aim_denytransfer(sess, command->conn, ft->sender, cookie, 0);
+#endif
- free(desc);
-
- i = 1;
- break;
- }
- case AIM_RENDEZVOUS_FILETRANSFER_GET: {
- printf("faim: file get request (unsupported)\n");
- i = 1;
- break;
- }
- case AIM_RENDEZVOUS_CHAT_EX3:
- case AIM_RENDEZVOUS_CHAT_EX4:
- case AIM_RENDEZVOUS_CHAT_EX5: {
+
+ } else if (reqclass & AIM_CAPS_CHAT) {
+ struct aim_tlv_t *miscinfo;
struct aim_chat_roominfo roominfo;
char *msg=NULL,*encoding=NULL,*lang=NULL;
+ miscinfo = aim_gettlv(list2, 0x2711, 1);
aim_chat_readroominfo(miscinfo->value, &roominfo);
if (aim_gettlv(list2, 0x000c, 1))
free(msg);
free(encoding);
free(lang);
- break;
- }
- default: {
- printf("faim: rendezvous: unknown rend class 0x%04x\n", reqclass);
+ } else if (reqclass & AIM_CAPS_GETFILE) {
+ printf("faim: rend: getfile!\n");
+ } else if (reqclass & AIM_CAPS_SENDFILE) {
+ char ip[30];
+ char *desc = NULL;
+ struct aim_msgcookie_t cachedcook;
+ struct aim_filetransfer_t *ft;
+ struct aim_tlv_t *miscinfo;
+
+ memset(ip, 0, sizeof(ip));
+
+ miscinfo = aim_gettlv(list2, 0x2711, 1);
+
+ if (aim_gettlv(list2, 0x0003, 1) && aim_gettlv(list2, 0x0003, 1)) {
+ struct aim_tlv_t *iptlv, *porttlv;
+
+ iptlv = aim_gettlv(list2, 0x0003, 1);
+ porttlv = aim_gettlv(list2, 0x0005, 1);
+
+ snprintf(ip, sizeof(ip)-1, "%d.%d.%d.%d:%d",
+ aimutil_get8(iptlv->value+0),
+ aimutil_get8(iptlv->value+1),
+ aimutil_get8(iptlv->value+2),
+ aimutil_get8(iptlv->value+3),
+ aimutil_get16(porttlv->value));
+ }
+
+ if (aim_gettlv(list2, 0x000c, 1)) {
+ desc = aim_gettlv_str(list2, 0x000c, 1);
+ }
+
+ printf("faim: rend: file transfer request from %s for %s: %s (%s)\n",
+ userinfo.sn,
+ miscinfo->value+8,
+ desc,
+ ip);
+
+ memcpy(cachedcook.cookie, cookie, 8);
+
+ ft = malloc(sizeof(struct aim_filetransfer_t));
+ strncpy(ft->sender, userinfo.sn, sizeof(ft->sender));
+ strncpy(ft->ip, ip, sizeof(ft->ip));
+ ft->filename = strdup(miscinfo->value+8);
+ cachedcook.type = AIM_CAPS_SENDFILE;
+ cachedcook.data = ft;
+
+ if (aim_cachecookie(sess, &cachedcook) != 0)
+ printf("faim: ERROR caching message cookie\n");
+
+
+ aim_accepttransfer(sess, command->conn, ft->sender, cookie, AIM_CAPS_SENDFILE);
+
+ free(desc);
+
i = 1;
- break;
+ } else {
+ printf("faim: rend: unknown rendezvous 0x%04x\n", reqclass);
}
- } /* switch */
aim_freetlvchain(&list2);
}
return i;
}
+u_long aim_accepttransfer(struct aim_session_t *sess,
+ struct aim_conn_t *conn,
+ char *sender,
+ char *cookie,
+ unsigned short rendid)
+{
+ struct command_tx_struct *newpacket;
+ int curbyte, i;
+
+ if(!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+8+2+1+strlen(sender)+4+2+8+16)))
+ return -1;
+
+ newpacket->lock = 1;
+
+ curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0006, 0x0000, sess->snac_nextid);
+ for (i = 0; i < 8; i++)
+ curbyte += aimutil_put8(newpacket->data+curbyte, cookie[i]);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
+ curbyte += aimutil_put8(newpacket->data+curbyte, strlen(sender));
+ curbyte += aimutil_putstr(newpacket->data+curbyte, sender, strlen(sender));
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x001a);
+ curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002 /* accept */);
+ for (i = 0; i < 8; i++)
+ curbyte += aimutil_put8(newpacket->data+curbyte, cookie[i]);
+ curbyte += aim_putcap(newpacket->data+curbyte, 0x10, rendid);
+
+ newpacket->lock = 0;
+ aim_tx_enqueue(sess, newpacket);
+
+ return (sess->snac_nextid++);
+}
+
/*
* Possible codes:
* AIM_TRANSFER_DENY_NOTSUPPORTED -- "client does not support"
struct command_tx_struct *newpacket;
int curbyte, i;
- if(!(newpacket = aim_tx_new(0x0002, conn, 10+8+2+1+strlen(sender)+6)))
+ if(!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+8+2+1+strlen(sender)+6)))
return -1;
newpacket->lock = 1;
struct command_tx_struct *newpacket;
int curbyte;
- if(!(newpacket = aim_tx_new(0x0002, conn, 10+16)))
+ if(!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+16)))
return -1;
newpacket->lock = 1;
if (!sess || !conn || !sn)
return 0;
- if (!(newpacket = aim_tx_new(0x0002, conn, 12+1+strlen(sn))))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 12+1+strlen(sn))))
return -1;
newpacket->lock = 1;
0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}
};
+u_short aim_getcap(unsigned char *capblock, int buflen)
+{
+ u_short ret = 0;
+ int y;
+ int offset = 0;
+
+ while (offset < buflen) {
+ for(y=0; y < (sizeof(aim_caps)/0x10); y++) {
+ if (memcmp(&aim_caps[y], capblock+offset, 0x10) == 0) {
+ switch(y) {
+ case 0: ret |= AIM_CAPS_BUDDYICON; break;
+ case 1: ret |= AIM_CAPS_VOICE; break;
+ case 2: ret |= AIM_CAPS_IMIMAGE; break;
+ case 3: ret |= AIM_CAPS_CHAT; break;
+ case 4: ret |= AIM_CAPS_GETFILE; break;
+ case 5: ret |= AIM_CAPS_SENDFILE; break;
+ default: ret |= 0xff00; break;
+ }
+ }
+ }
+ offset += 0x10;
+ }
+ return ret;
+}
+
+int aim_putcap(unsigned char *capblock, int buflen, u_short caps)
+{
+ int offset = 0;
+
+ if (!capblock)
+ return -1;
+
+ if ((caps & AIM_CAPS_BUDDYICON) && (offset < buflen)) {
+ memcpy(capblock+offset, aim_caps[0], sizeof(aim_caps[0]));
+ offset += sizeof(aim_caps[1]);
+ }
+ if ((caps & AIM_CAPS_VOICE) && (offset < buflen)) {
+ memcpy(capblock+offset, aim_caps[1], sizeof(aim_caps[1]));
+ offset += sizeof(aim_caps[1]);
+ }
+ if ((caps & AIM_CAPS_IMIMAGE) && (offset < buflen)) {
+ memcpy(capblock+offset, aim_caps[2], sizeof(aim_caps[2]));
+ offset += sizeof(aim_caps[2]);
+ }
+ if ((caps & AIM_CAPS_CHAT) && (offset < buflen)) {
+ memcpy(capblock+offset, aim_caps[3], sizeof(aim_caps[3]));
+ offset += sizeof(aim_caps[3]);
+ }
+ if ((caps & AIM_CAPS_GETFILE) && (offset < buflen)) {
+ memcpy(capblock+offset, aim_caps[4], sizeof(aim_caps[4]));
+ offset += sizeof(aim_caps[4]);
+ }
+ if ((caps & AIM_CAPS_SENDFILE) && (offset < buflen)) {
+ memcpy(capblock+offset, aim_caps[5], sizeof(aim_caps[5]));
+ offset += sizeof(aim_caps[5]);
+ }
+
+ return offset;
+}
+
/*
* AIM is fairly regular about providing user info. This
* is a generic routine to extract it in its standard form.
* actual decoding. See comment on aim_bos_setprofile()
* in aim_misc.c about the capability block, its the same.
*
- * Ignore.
- *
*/
case 0x000d:
{
- int z,y;
int len;
len = aimutil_get16(buf+i+2);
if (!len)
break;
-
- for (z = 0; z < len; z+=0x10) {
- for(y=0; y < 6; y++) {
- if (memcmp(&aim_caps[y], buf+i+4+z, 0x10) == 0) {
- switch(y) {
- case 0: outinfo->capabilities |= AIM_CAPS_BUDDYICON; break;
- case 1: outinfo->capabilities |= AIM_CAPS_VOICE; break;
- case 2: outinfo->capabilities |= AIM_CAPS_IMIMAGE; break;
- case 3: outinfo->capabilities |= AIM_CAPS_CHAT; break;
- case 4: outinfo->capabilities |= AIM_CAPS_GETFILE; break;
- case 5: outinfo->capabilities |= AIM_CAPS_SENDFILE; break;
- default: outinfo->capabilities |= 0xff00; break;
- }
- }
- }
- }
+
+ outinfo->capabilities = aim_getcap(buf+i+4, len);
}
break;
if (!sess || !conn || !info)
return 0;
- if (!(tx = aim_tx_new(0x0002, conn, 1152)))
+ if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
return -1;
tx->lock = 1;
if (!sess || !conn || !sn)
return 0;
- if (!(tx = aim_tx_new(0x0002, conn, 10+1+strlen(sn))))
+ if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+1+strlen(sn))))
return -1;
tx->lock = 1;
struct command_tx_struct *newpacket;
- if (!(newpacket = aim_tx_new(0x0001, conn, 4)))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0001, conn, 4)))
return -1;
newpacket->lock = 1;
struct command_tx_struct *newpacket;
- if (!(newpacket = aim_tx_new(0x0002, conn, 10+2+2+strlen(sn))))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+2+2+strlen(sn))))
return -1;
newpacket->lock = 1;
if (!clientinfo || !sn || !password)
return -1;
- if (!(newpacket = aim_tx_new(0x0002, conn, 1152)))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
return -1;
/*
}
newpacket->lock = 1;
- newpacket->type = 0x01;
+ newpacket->hdr.oscar.type = 0x01;
curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002);
curbyte += aimutil_put16(newpacket->data+curbyte, strlen(password));
password_encoded = (char *) malloc(strlen(password));
- if (icqmode)
- aimicq_encode_password(password, password_encoded);
- else
- aim_encode_password(password, password_encoded);
+ aim_encode_password(password, password_encoded);
curbyte += aimutil_putstr(newpacket->data+curbyte, password_encoded, strlen(password));
free(password_encoded);
- curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, 0x010a /*0x0004*/);
-
if (strlen(clientinfo->clientstring)) {
curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
curbyte += aimutil_put16(newpacket->data+curbyte, strlen(clientinfo->clientstring));
curbyte += aimutil_putstr(newpacket->data+curbyte, clientinfo->clientstring, strlen(clientinfo->clientstring));
}
+ curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, /*0x010a*/ 0x0004);
curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0017, clientinfo->major /*0x0001*/);
curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0018, clientinfo->minor /*0x0001*/);
curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0019, 0x0001);
int aim_encode_password(const char *password, u_char *encoded)
{
u_char encoding_table[] = {
+#if 0 /* old v1 table */
0xf3, 0xb3, 0x6c, 0x99,
0x95, 0x3f, 0xac, 0xb6,
0xc5, 0xfa, 0x6b, 0x63,
0x69, 0x6c, 0xc3, 0x9f
- };
-
- int i;
-
- for (i = 0; i < strlen(password); i++)
- encoded[i] = (password[i] ^ encoding_table[i]);
-
- return 0;
-}
-
-/*
- * They changed the hash slightly for ICQ.
- * This new hash may work for AIM too (though
- * the max password length for ICQ is only
- * eight characters, where its 16 with AIM).
- *
- */
-int aimicq_encode_password(const char *password, u_char *encoded)
-{
- u_char encoding_table[] = {
+#else /* v2.1 table, also works for ICQ */
0xf3, 0x26, 0x81, 0xc4,
- 0x39, 0x86, 0xdb, 0x92
+ 0x39, 0x86, 0xdb, 0x92,
+ 0x71, 0xa3, 0xb9, 0xe6,
+ 0x53, 0x7a, 0x95, 0x7c
+#endif
};
int i;
-
- if (strlen(password) > 8)
- return -1;
-
+
for (i = 0; i < strlen(password); i++)
encoded[i] = (password[i] ^ encoding_table[i]);
* If we have both an IP number (0x0005) and a cookie (0x0006),
* then the login was successful.
*/
- else if (aim_gettlv(tlvlist, 0x0005, 1) && aim_gettlv(tlvlist, 0x0006, 1)) {
+ else if (aim_gettlv(tlvlist, 0x0005, 1) && aim_gettlv(tlvlist, 0x0006, 1)
+ /*aim_gettlv(tlvlist, 0x0006, 1)->length*/) {
struct aim_tlv_t *tmptlv;
/*
struct command_tx_struct *tx;
struct aim_tlvlist_t *tlvlist = NULL;
- if (!(tx = aim_tx_new(0x0004, conn, 1152)))
+ if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0004, conn, 1152)))
return -1;
tx->lock = 1;
struct command_tx_struct *tx;
int i = 0;
- if (!(tx = aim_tx_new(0x0002, conn, 10+0x22)))
+ if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+0x22)))
return -1;
tx->lock = 1;
struct aim_tlvlist_t *tlvlist = NULL;
int i = 0;
- if (!(tx = aim_tx_new(0x0002, conn, 1152)))
+ if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
return -1;
tx->lock = 1;
listcount = aimutil_itemcnt(localcpy, '&');
packlen = aimutil_tokslen(localcpy, 99, '&') + listcount + 9;
- if (!(newpacket = aim_tx_new(0x0002, conn, packlen)))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, packlen)))
return -1;
newpacket->lock = 1;
#endif
free(localcpy);
- if (!(newpacket = aim_tx_new(0x0002, conn, packet_login_phase3c_hi_b_len - 6)))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, packet_login_phase3c_hi_b_len - 6)))
return -1;
newpacket->lock = 1;
* Gives BOS your profile.
*
*
- * The large data chunk given here is of unknown decoding.
- * What I do know is that each 0x20 byte repetition
- * represents a capability. People with only the
- * first two reptitions can support normal messaging
- * and chat (client version 2.0 or 3.0). People with
- * the third as well can also support voice chat (client
- * version 3.5 or higher). IOW, if we don't send this,
- * we won't get chat invitations (get "software doesn't
- * support chat" error).
- *
- * This data is broadcast along with your oncoming
- * buddy command to everyone who has you on their
- * buddy list, as a type 0x0002 TLV.
- *
*/
u_long aim_bos_setprofile(struct aim_session_t *sess,
struct aim_conn_t *conn,
unsigned int caps)
{
struct command_tx_struct *newpacket;
- int i = 0;
+ int i = 0, tmp, caplen;
- if (!(newpacket = aim_tx_new(0x0002, conn, 1152+strlen(profile)+1+(awaymsg?strlen(awaymsg):0))))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152+strlen(profile)+1+(awaymsg?strlen(awaymsg):0))))
return -1;
i += aim_putsnac(newpacket->data, 0x0002, 0x004, 0x0000, sess->snac_nextid);
i += aim_puttlv_str(newpacket->data+i, 0x0004, 0x0000, NULL);
/* Capability information. */
- {
- int isave;
- i += aimutil_put16(newpacket->data+i, 0x0005);
- isave = i;
- i += aimutil_put16(newpacket->data+i, 0);
- if (caps & AIM_CAPS_BUDDYICON)
- i += aimutil_putstr(newpacket->data+i, aim_caps[0], 0x10);
- if (caps & AIM_CAPS_VOICE)
- i += aimutil_putstr(newpacket->data+i, aim_caps[1], 0x10);
- if (caps & AIM_CAPS_IMIMAGE)
- i += aimutil_putstr(newpacket->data+i, aim_caps[2], 0x10);
- if (caps & AIM_CAPS_CHAT)
- i += aimutil_putstr(newpacket->data+i, aim_caps[3], 0x10);
- if (caps & AIM_CAPS_GETFILE)
- i += aimutil_putstr(newpacket->data+i, aim_caps[4], 0x10);
- if (caps & AIM_CAPS_SENDFILE)
- i += aimutil_putstr(newpacket->data+i, aim_caps[5], 0x10);
- aimutil_put16(newpacket->data+isave, i-isave-2);
- }
+
+ tmp = (i += aimutil_put16(newpacket->data+i, 0x0005));
+ i += aimutil_put16(newpacket->data+i, 0x0000); /* rewritten later */
+ i += (caplen = aim_putcap(newpacket->data+i, 512, caps));
+ aimutil_put16(newpacket->data+tmp, caplen); /* rewrite TLV size */
+
newpacket->commandlen = i;
aim_tx_enqueue(sess, newpacket);
int command_2_len = 0x52;
struct command_tx_struct *newpacket;
- if (!(newpacket = aim_tx_new(0x0002, conn, command_2_len)))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, command_2_len)))
return -1;
newpacket->lock = 1;
if (conn->type != AIM_CONN_TYPE_BOS)
packlen += 2;
- if(!(newpacket = aim_tx_new(0x0002, conn, packlen)));
+ if(!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, packlen)));
newpacket->lock = 1;
{
struct command_tx_struct *newpacket;
- if (!(newpacket = aim_tx_new(0x0002, conn, 12)))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 12)))
return -1;
newpacket->lock = 1;
struct command_tx_struct *newpacket;
int i;
- if (!(newpacket = aim_tx_new(0x0002, conn, 10 + (4*11))))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10 + (4*11))))
return -1;
newpacket->lock = 1;
{
struct command_tx_struct *newpacket;
- if (!(newpacket = aim_tx_new(0x0002, conn, 10)))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10)))
return 0;
newpacket->lock = 1;
if (!longdata)
return aim_genericreq_n(sess, conn, family, subtype);
- if (!(newpacket = aim_tx_new(0x0002, conn, 10+sizeof(u_long))))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+sizeof(u_long))))
return -1;
newpacket->lock = 1;
if (!shortdata)
return aim_genericreq_n(sess, conn, family, subtype);
- if (!(newpacket = aim_tx_new(0x0002, conn, 10+sizeof(u_short))))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+sizeof(u_short))))
return -1;
newpacket->lock = 1;
if (workingPtr->handled)
continue;
+ /*
+ * This is a debugging/sanity check only and probably could/should be removed
+ * for stable code.
+ */
+ if (((workingPtr->hdrtype == AIM_FRAMETYPE_OFT) &&
+ (workingPtr->conn->type != AIM_CONN_TYPE_RENDEZVOUS)) ||
+ ((workingPtr->hdrtype == AIM_FRAMETYPE_OSCAR) &&
+ (workingPtr->conn->type == AIM_CONN_TYPE_RENDEZVOUS))) {
+ printf("faim: rxhandlers: incompatible frame type %d on connection type 0x%04x\n", workingPtr->hdrtype, workingPtr->conn->type);
+ workingPtr->handled = 1;
+ continue;
+ }
+
switch(workingPtr->conn->type) {
case -1:
/*
u_short family;
u_short subtype;
- if (workingPtr->type == 0x04) {
+ if (workingPtr->hdr.oscar.type == 0x04) {
workingPtr->handled = aim_negchan_middle(sess, workingPtr);
break;
}
}
break;
}
+ case AIM_CONN_TYPE_RENDEZVOUS: {
+ /* make sure that we only get OFT frames on these connections */
+ if (workingPtr->hdrtype != AIM_FRAMETYPE_OFT) {
+ printf("faim: internal error: non-OFT frames on OFT connection\n");
+ workingPtr->handled = 1; /* get rid of it */
+ break;
+ }
+
+ /* XXX: implement this */
+ printf("faim: OFT frame!\n");
+
+ break;
+ }
default:
- printf("\ninternal error: unknown connection type (very bad.) (type = %d, fd = %d, channel = %02x, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->type, workingPtr->commandlen);
+ printf("\ninternal error: unknown connection type (very bad.) (type = %d, fd = %d, commandlen = %02x)\n\n", workingPtr->conn->type, workingPtr->conn->fd, workingPtr->commandlen);
workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr);
break;
}
*/
int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn)
{
- u_char generic[6];
+ unsigned char generic[6];
struct command_rx_struct *newrx = NULL;
if (!sess || !conn)
* Rendezvous (client-client) connections do not speak
* FLAP, so this function will break on them.
*/
- if (conn->type > 0x01000)
- return 0;
+ if (conn->type == AIM_CONN_TYPE_RENDEZVOUS)
+ return aim_get_command_rendezvous(sess, conn);
/*
* Read FLAP header. Six bytes:
faim_mutex_unlock(&conn->active);
return -1;
}
- faim_mutex_unlock(&conn->active);
/*
* This shouldn't happen unless the socket breaks, the server breaks,
*/
if (generic[0] != 0x2a) {
faimdprintf(1, "Bad incoming data!");
+ faim_mutex_unlock(&conn->active);
return -1;
}
/* allocate a new struct */
- newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct));
- if (!newrx)
+ if (!(newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct)))) {
+ faim_mutex_unlock(&conn->active);
return -1;
+ }
memset(newrx, 0x00, sizeof(struct command_rx_struct));
newrx->lock = 1; /* lock the struct */
+ /* we're doing OSCAR if we're here */
+ newrx->hdrtype = AIM_FRAMETYPE_OSCAR;
+
/* store channel -- byte 2 */
- newrx->type = (char) generic[1];
+ newrx->hdr.oscar.type = (char) generic[1];
/* store seqnum -- bytes 3 and 4 */
- newrx->seqnum = aimutil_get16(generic+2);
+ newrx->hdr.oscar.seqnum = aimutil_get16(generic+2);
/* store commandlen -- bytes 5 and 6 */
newrx->commandlen = aimutil_get16(generic+4);
newrx->nofree = 0; /* free by default */
/* malloc for data portion */
- newrx->data = (u_char *) malloc(newrx->commandlen);
- if (!newrx->data) {
+ if (!(newrx->data = (u_char *) malloc(newrx->commandlen))) {
free(newrx);
+ faim_mutex_unlock(&conn->active);
return -1;
}
/* read the data portion of the packet */
- faim_mutex_lock(&conn->active);
if (read(conn->fd, newrx->data, newrx->commandlen) < newrx->commandlen){
free(newrx->data);
free(newrx);
return 0;
}
+int aim_get_command_rendezvous(struct aim_session_t *sess, struct aim_conn_t *conn)
+{
+ unsigned char hdrbuf1[6];
+ unsigned char *hdr = NULL;
+ int hdrlen, hdrtype;
+ int payloadlength = 0;
+ int flags = 0;
+ char *snptr = NULL;
+
+ if (read(conn->fd, hdrbuf1, 6) < 6) {
+ perror("read");
+ printf("faim: rend: read error\n");
+ aim_conn_kill(sess, &conn);
+ return -1;
+ }
+
+ hdrlen = aimutil_get16(hdrbuf1+4);
+
+ hdrlen -= 6;
+ hdr = malloc(hdrlen);
+
+ faim_mutex_lock(&conn->active);
+ if (read(conn->fd, hdr, hdrlen) < hdrlen) {
+ perror("read");
+ printf("faim: rend: read2 error\n");
+ free(hdr);
+ faim_mutex_unlock(&conn->active);
+ aim_conn_kill(sess, &conn);
+ return -1;
+ }
+
+ hdrtype = aimutil_get16(hdr);
+
+ switch (hdrtype) {
+ case 0x0001: {
+ payloadlength = aimutil_get32(hdr+22);
+ flags = aimutil_get16(hdr+32);
+ snptr = hdr+38;
+
+ printf("OFT frame: %04x / %04x / %04x / %s\n", hdrtype, payloadlength, flags, snptr);
+
+ if (flags == 0x000e) {
+ printf("directim: %s has started typing\n", snptr);
+ } else if ((flags == 0x0000) && payloadlength) {
+ unsigned char *buf;
+ buf = malloc(payloadlength+1);
+
+ /* XXX theres got to be a better way */
+ faim_mutex_lock(&conn->active);
+ if (recv(conn->fd, buf, payloadlength, MSG_WAITALL) < payloadlength) {
+ perror("read");
+ printf("faim: rend: read3 error\n");
+ free(buf);
+ faim_mutex_unlock(&conn->active);
+ aim_conn_kill(sess, &conn);
+ return -1;
+ }
+ faim_mutex_unlock(&conn->active);
+ buf[payloadlength] = '\0';
+ printf("directim: %s/%04x/%04x/%s\n", snptr, payloadlength, flags, buf);
+ aim_send_im_direct(sess, conn, buf);
+ free(buf);
+ }
+ break;
+ }
+ default:
+ printf("OFT frame: type %04x\n", hdrtype);
+ /* data connection may be unreliable here */
+ break;
+ } /* switch */
+
+ free(hdr);
+
+ return 0;
+}
+
/*
* Purge recieve queue of all handled commands (->handled==1). Also
* allows for selective freeing using ->nofree so that the client can
sess->queue_incoming = NULL;
if (!tmp->nofree) {
+ if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
+ free(tmp->hdr.oft.hdr2);
free(tmp->data);
free(tmp);
} else
tmp = cur->next;
cur->next = tmp->next;
if (!tmp->nofree) {
+ if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
+ free(tmp->hdr.oft.hdr2);
free(tmp->data);
free(tmp);
} else
if (!address)
return -1;
- if (!(newpacket = aim_tx_new(0x0002, conn, 10+strlen(address))))
+ if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+strlen(address))))
return -1;
newpacket->lock = 1;
*
* Right now, that is. If/when we implement a pool of transmit
* frames, this will become the request-an-unused-frame part.
+ *
+ * framing = AIM_FRAMETYPE_OFT/OSCAR
+ * chan = channel for OSCAR, hdrtype for OFT
+ *
*/
-struct command_tx_struct *aim_tx_new(int chan, struct aim_conn_t *conn, int datalen)
+struct command_tx_struct *aim_tx_new(unsigned short framing, int chan, struct aim_conn_t *conn, int datalen)
{
struct command_tx_struct *new;
memset(new, 0, sizeof(struct command_tx_struct));
new->conn = conn;
- new->type = chan;
if(datalen) {
new->data = (u_char *)malloc(datalen);
new->commandlen = datalen;
+ } else
+ new->data = NULL;
+
+ new->hdrtype = framing;
+ if (new->hdrtype == AIM_FRAMETYPE_OSCAR) {
+ new->hdr.oscar.type = chan;
+ } else if (new->hdrtype == AIM_FRAMETYPE_OFT) {
+ new->hdr.oft.type = chan;
+ new->hdr.oft.hdr2len = 0; /* this will get setup by caller */
+ } else {
+ printf("tx_new: unknown framing\n");
}
return new;
newpacket->conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS);
}
- /* assign seqnum */
- newpacket->seqnum = aim_get_next_txseqnum(newpacket->conn);
+ if (newpacket->hdrtype == AIM_FRAMETYPE_OSCAR) {
+ /* assign seqnum */
+ newpacket->hdr.oscar.seqnum = aim_get_next_txseqnum(newpacket->conn);
+ }
/* set some more fields */
newpacket->lock = 1; /* lock */
newpacket->sent = 0; /* not sent yet */
return -1;
}
- newpacket->seqnum = aim_get_next_txseqnum(newpacket->conn);
+ if (newpacket->hdrtype == AIM_FRAMETYPE_OSCAR)
+ newpacket->hdr.oscar.seqnum = aim_get_next_txseqnum(newpacket->conn);
newpacket->lock = 1; /* lock */
newpacket->sent = 0; /* not sent yet */
faimdprintf(2, "aim_tx_flushqueue(): queue empty");
else {
for (cur = sess->queue_outgoing; cur; cur = cur->next) {
- faimdprintf(2, "\t %2x %4x %4x %1d %1d\n",
- cur->type, cur->seqnum,
+ faimdprintf(2, "\t %2x %2x %4x %4x %1d %1d\n",
+ cur->hdrtype,
+ (cur->hdrtype==AIM_FRAMETYPE_OFT)?cur->hdr.oft.type:cur->hdr.oscar.type,
+ (cur->hdrtype==AIM_FRAMETYPE_OSCAR)?cur->seqnum:0,
cur->commandlen, cur->lock,
cur->sent);
}
*/
int aim_tx_sendframe(struct command_tx_struct *cur)
{
- u_char *curPacket;
+ int buflen = 0;
+ unsigned char *curPacket;
if (!cur)
return -1; /* fatal */
cur->lock = 1; /* lock the struct */
+ if (cur->hdrtype == AIM_FRAMETYPE_OSCAR)
+ buflen = cur->commandlen + 6;
+ else if (cur->hdrtype == AIM_FRAMETYPE_OFT)
+ buflen = cur->hdr.oft.hdr2len + 8;
+ else {
+ cur->lock = 0;
+ return -1;
+ }
+
/* allocate full-packet buffer */
- curPacket = (char *) malloc(cur->commandlen + 6);
+ if (!(curPacket = (unsigned char *) malloc(buflen))) {
+ cur->lock = 0;
+ return -1;
+ }
- /* command byte */
- curPacket[0] = 0x2a;
+ if (cur->hdrtype == AIM_FRAMETYPE_OSCAR) {
+ /* command byte */
+ curPacket[0] = 0x2a;
- /* type/family byte */
- curPacket[1] = cur->type;
+ /* type/family byte */
+ curPacket[1] = cur->hdr.oscar.type;
- /* bytes 3+4: word: FLAP sequence number */
- aimutil_put16(curPacket+2, cur->seqnum);
+ /* bytes 3+4: word: FLAP sequence number */
+ aimutil_put16(curPacket+2, cur->hdr.oscar.seqnum);
- /* bytes 5+6: word: SNAC len */
- aimutil_put16(curPacket+4, cur->commandlen);
+ /* bytes 5+6: word: SNAC len */
+ aimutil_put16(curPacket+4, cur->commandlen);
- /* bytes 7 and on: raw: SNAC data */ /* XXX: ye gods! get rid of this! */
- memcpy(&(curPacket[6]), cur->data, cur->commandlen);
-
- /* full image of raw packet data now in curPacket */
+ /* bytes 7 and on: raw: SNAC data */ /* XXX: ye gods! get rid of this! */
+ memcpy(&(curPacket[6]), cur->data, cur->commandlen);
+
+ } else if (cur->hdrtype == AIM_FRAMETYPE_OFT) {
+ int z = 0;
+
+ z += aimutil_put8(curPacket+z, 0x4f);
+ z += aimutil_put8(curPacket+z, 0x44);
+ z += aimutil_put8(curPacket+z, 0x43);
+ z += aimutil_put8(curPacket+z, 0x32);
+
+ z += aimutil_put16(curPacket+z, cur->hdr.oft.hdr2len + 8);
+ z += aimutil_put16(curPacket+z, cur->hdr.oft.type);
+
+ memcpy(curPacket+z, cur->hdr.oft.hdr2, cur->hdr.oft.hdr2len);
+ }
+
+ /*
+ * For OSCAR, a full image of the raw packet data now in curPacket.
+ * For OFT, an image of just the bloated header is in curPacket,
+ * since OFT allows us to do the data in a different write (yay!).
+ */
faim_mutex_lock(&cur->conn->active);
- if ( (u_int)write(cur->conn->fd, curPacket, (cur->commandlen + 6)) != (cur->commandlen + 6)) {
+ if ( (u_int)write(cur->conn->fd, curPacket, buflen) != buflen) {
faim_mutex_unlock(&cur->conn->active);
- printf("\nWARNING: Error in sending packet 0x%4x -- will try again next time\n\n", cur->seqnum);
+ printf("\nWARNING: Error in sending packet -- will try again next time\n\n");
cur->sent = 0; /* mark it unsent */
return 0; /* bail out -- continuable error */
- } else {
- faimdprintf(2, "\nSENT 0x%4x\n\n", cur->seqnum);
-
- cur->sent = 1; /* mark the struct as sent */
- cur->conn->lastactivity = time(NULL);
}
+
+ if ((cur->hdrtype == AIM_FRAMETYPE_OFT) && cur->commandlen) {
+ if (write(cur->conn->fd, cur->data, cur->commandlen) != cur->commandlen) {
+ /*
+ * Theres nothing we can do about this since we've already sent the
+ * header! The connection is unstable.
+ */
+ }
+ }
+
+ cur->sent = 1; /* mark the struct as sent */
+ cur->conn->lastactivity = time(NULL);
+
faim_mutex_unlock(&cur->conn->active);
#if debug > 2
if (!sess->queue_outgoing->lock && sess->queue_outgoing->sent) {
tmp = sess->queue_outgoing;
sess->queue_outgoing = NULL;
+ if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
+ free(tmp->hdr.oft.hdr2);
free(tmp->data);
free(tmp);
}
if (!cur->next->lock && cur->next->sent) {
tmp = cur->next;
cur->next = tmp->next;
+ if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
+ free(tmp->hdr.oft.hdr2);
free(tmp->data);
free(tmp);
}
* with utterly oversized instant messages!
*
*/
-#define MAXMSGLEN 7988
+#define MAXMSGLEN 7987
/*
* Current Maximum Length for Chat Room Messages
#define AIM_CONN_STATUS_RESOLVERR 0x0080
#define AIM_CONN_STATUS_CONNERR 0x0040
+#define AIM_FRAMETYPE_OSCAR 0x0000
+#define AIM_FRAMETYPE_OFT 0x0001
+
struct aim_conn_t {
int fd;
int type;
/* struct for incoming commands */
struct command_rx_struct {
- /* byte 1 assumed to always be 0x2a */
- char type; /* type code (byte 2) */
- u_int seqnum; /* sequence number (bytes 3 and 4) */
- u_int commandlen; /* total packet len - 6 (bytes 5 and 6) */
- u_char *data; /* packet data (from 7 byte on) */
- u_int lock; /* 0 = open, !0 = locked */
- u_int handled; /* 0 = new, !0 = been handled */
- u_int nofree; /* 0 = free data on purge, 1 = only unlink */
+ unsigned char hdrtype; /* defines which piece of the union to use */
+ union {
+ struct {
+ char type;
+ unsigned short seqnum;
+ } oscar;
+ struct {
+ unsigned short type;
+ unsigned short hdr2len;
+ unsigned char *hdr2; /* rest of bloated header */
+ } oft;
+ } hdr;
+ unsigned short commandlen; /* total payload length */
+ unsigned char *data; /* packet data (from 7 byte on) */
+ unsigned char lock; /* 0 = open, !0 = locked */
+ unsigned char handled; /* 0 = new, !0 = been handled */
+ unsigned char nofree; /* 0 = free data on purge, 1 = only unlink */
struct aim_conn_t *conn; /* the connection it came in on... */
struct command_rx_struct *next; /* ptr to next struct in list */
};
/* struct for outgoing commands */
struct command_tx_struct {
- /* byte 1 assumed to be 0x2a */
- char type; /* type/family code */
- u_int seqnum; /* seqnum dynamically assigned on tx */
- u_int commandlen; /* SNAC length */
- u_char *data; /* packet data */
+ unsigned char hdrtype; /* defines which piece of the union to use */
+ union {
+ struct {
+ unsigned char type;
+ unsigned short seqnum;
+ } oscar;
+ struct {
+ unsigned short type;
+ unsigned short hdr2len;
+ unsigned char *hdr2;
+ } oft;
+ } hdr;
+ u_int commandlen;
+ u_char *data;
u_int lock; /* 0 = open, !0 = locked */
u_int sent; /* 0 = pending, !0 = has been sent */
struct aim_conn_t *conn;
int aim_parse_missed_im(struct aim_session_t *, struct command_rx_struct *, ...);
int aim_parse_last_bad(struct aim_session_t *, struct command_rx_struct *, ...);
-struct command_tx_struct *aim_tx_new(int, struct aim_conn_t *, int);
+
+struct command_tx_struct *aim_tx_new(unsigned short framing, int chan, struct aim_conn_t *conn, int datalen);
int aim_tx_enqueue__queuebased(struct aim_session_t *, struct command_tx_struct *);
int aim_tx_enqueue__immediate(struct aim_session_t *, struct command_tx_struct *);
#define aim_tx_enqueue(x, y) ((*(x->tx_enqueue))(x, y))
#define AIM_CAPS_CHAT 0x08
#define AIM_CAPS_GETFILE 0x10
#define AIM_CAPS_SENDFILE 0x20
+
extern u_char aim_caps[6][16];
+u_short aim_getcap(unsigned char *capblock, int buflen);
+int aim_putcap(unsigned char *capblock, int buflen, u_short caps);
#define AIM_GETINFO_GENERALINFO 0x00001
#define AIM_GETINFO_AWAYMESSAGE 0x00003
-#define AIM_RENDEZVOUS_VOICE 0x0000
-#define AIM_RENDEZVOUS_FILETRANSFER 0x0001
-#define AIM_RENDEZVOUS_CHAT_EX3 0x0003
-#define AIM_RENDEZVOUS_CHAT_EX4 0x0004
-#define AIM_RENDEZVOUS_CHAT_EX5 0x0005
-#define AIM_RENDEZVOUS_FILETRANSFER_GET 0x0012
-
struct aim_msgcookie_t {
unsigned char cookie[8];
- unsigned char extended[16];
int type;
void *data;
time_t addtime;
#define AIM_TRANSFER_DENY_DECLINE 0x0001
#define AIM_TRANSFER_DENY_NOTACCEPTING 0x0002
u_long aim_denytransfer(struct aim_session_t *sess, struct aim_conn_t *conn, char *sender, char *cookie, unsigned short code);
+u_long aim_accepttransfer(struct aim_session_t *sess, struct aim_conn_t *conn, char *sender, char *cookie, unsigned short rendid);
u_long aim_getinfo(struct aim_session_t *, struct aim_conn_t *, const char *, unsigned short);
int aim_extractuserinfo(u_char *, struct aim_userinfo_s *);
struct aim_conn_t *authconn = NULL, *waitingconn = NULL;
int keepgoing = 1, stayconnected = 1;
-#if 0
+#if 1
/* Use something like this for AIM */
- struct client_info_s info = {"FAIMtest (Hi guys!)", 3, 5, 1670, "us", "en"};
+ struct client_info_s info = {"Boo", 2, 1, 0, "us", "en"};
#else
/* or something exactly like this for ICQ and AIM */
struct client_info_s info = {"Random String (libfaim)", 4, 30, 3141, "us", "en"};
printf("\nTrying to reconnect in 2 seconds...\n");
sleep(2);
goto enter;
- }
+ }
/* Get out */
exit(0);
/* send the buddy list and profile (required, even if empty) */
aim_bos_setbuddylist(sess, command->conn, buddies);
- aim_bos_setprofile(sess, command->conn, profile, NULL, AIM_CAPS_CHAT);
+ aim_bos_setprofile(sess, command->conn, profile, NULL, AIM_CAPS_BUDDYICON | AIM_CAPS_CHAT | AIM_CAPS_VOICE | AIM_CAPS_GETFILE | AIM_CAPS_SENDFILE | AIM_CAPS_IMIMAGE);
/* send final login command (required) */
aim_bos_clientready(sess, command->conn); /* tell BOS we're ready to go live */
printf("faimtest: icbm: membersince = %lu\n", userinfo->membersince);
printf("faimtest: icbm: onlinesince = %lu\n", userinfo->onlinesince);
printf("faimtest: icbm: idletime = 0x%04x\n", userinfo->idletime);
+ printf("faimtest: icbm: capabilities = 0x%04x\n", userinfo->capabilities);
printf("faimtest: icbm: icbmflags = ");
if (icbmflags & AIM_IMFLAGS_AWAY)
printf("faimtest: icbm: message: %s\n", msg);
if (msg) {
- tmpstr = index(msg, '>');
- if (tmpstr != NULL)
- tmpstr+=1;
- else
- tmpstr = msg;
+ int i = 0;
+
+ while (msg[i] == '<') {
+ if (msg[i] == '<') {
+ while (msg[i] != '>')
+ i++;
+ i++;
+ }
+ }
+ tmpstr = msg+i;
+
+ printf("tmpstr = %s\n", tmpstr);
if ( (strlen(tmpstr) >= 10) &&
(!strncmp(tmpstr, "disconnect", 10)) ) {
else if (!strncmp(tmpstr, "getinfo", 7)) {
aim_getinfo(sess, command->conn, "75784102", AIM_GETINFO_GENERALINFO);
aim_getinfo(sess, command->conn, "15853637", AIM_GETINFO_AWAYMESSAGE);
+ } else if (!strncmp(tmpstr, "sendmsg", 7)) {
+ int i;
+ i = atoi(tmpstr+8);
+ if (i < 10000) {
+ char *newbuf;
+ int z;
+
+ newbuf = malloc(i+1);
+ for (z = 0; z < i; z++) {
+ newbuf[z] = (z % 10)+0x30;
+ }
+ newbuf[i] = '\0';
+ aim_send_im(sess, command->conn, userinfo->sn, 0, newbuf);
+ free(newbuf);
+ }
} else {
printf("unknown command.\n");
+ aim_add_buddy(sess, command->conn, userinfo->sn);
}
}
reqclass = va_arg(ap, unsigned short);
switch (reqclass) {
- case AIM_RENDEZVOUS_VOICE: {
+ case AIM_CAPS_VOICE: {
userinfo = va_arg(ap, struct aim_userinfo_s *);
va_end(ap);
break;
}
- case AIM_RENDEZVOUS_FILETRANSFER: {
- printf("faimtset: file transfer!\n");
+ case AIM_CAPS_GETFILE: {
+ printf("faimtset: get file!\n");
break;
}
- case AIM_RENDEZVOUS_CHAT_EX3:
- case AIM_RENDEZVOUS_CHAT_EX4:
- case AIM_RENDEZVOUS_CHAT_EX5: {
+ case AIM_CAPS_SENDFILE: {
+ printf("faimtest: send file!\n");
+ break;
+ }
+ case AIM_CAPS_CHAT: {
char *msg,*encoding,*lang;
struct aim_chat_roominfo *roominfo;
userinfo = va_arg(ap, struct aim_userinfo_s *);
va_end(ap);
- printf("\n%s is now online (class: %04x = %s%s%s%s%s%s%s%s)\n", userinfo->sn, userinfo->class,
+ printf("\n%s is now online (class: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n",
+ userinfo->sn, userinfo->class,
(userinfo->class&AIM_CLASS_TRIAL)?" TRIAL":"",
(userinfo->class&AIM_CLASS_UNKNOWN2)?" UNKNOWN2":"",
(userinfo->class&AIM_CLASS_AOL)?" AOL":"",
(userinfo->class&AIM_CLASS_FREE)?" FREE":"",
(userinfo->class&AIM_CLASS_AWAY)?" AWAY":"",
(userinfo->class&AIM_CLASS_UNKNOWN40)?" UNKNOWN40":"",
- (userinfo->class&AIM_CLASS_UNKNOWN80)?" UNKNOWN80":"");
-
+ (userinfo->class&AIM_CLASS_UNKNOWN80)?" UNKNOWN80":"",
+ userinfo->capabilities);
return 1;
}