/** * aim_addtlvtochain8 - Add a 8bit integer to a TLV chain * @list: Destination chain * @type: TLV type to add * @val: Value to add * * Adds a one-byte unsigned integer to a TLV chain. * */ faim_internal int aim_addtlvtochain8(aim_tlvlist_t **list, const fu16_t t, const fu8_t v) { fu8_t v8[1]; aimutil_put8(v8, v); return aim_addtlvtochain_raw(list, t, 1, v8); }
/** * aim_puttlv_8 - Write a one-byte TLV. * @buf: Destination buffer * @t: TLV type * @v: Value * * Writes a TLV with a one-byte integer value portion. * */ faim_export int aim_puttlv_8(fu8_t *buf, const fu16_t t, const fu8_t v) { fu8_t v8[1]; aimutil_put8(v8, v); return aim_puttlv_raw(buf, t, 1, v8); }
int byte_stream_put8(ByteStream *bs, guint8 v) { if (byte_stream_empty(bs) < 1) return 0; /* XXX throw an exception */ bs->offset += aimutil_put8(bs->data + bs->offset, v); return 1; }
faim_internal int aimbs_put8(aim_bstream_t *bs, fu8_t v) { if (aim_bstream_empty(bs) < 1) return 0; /* XXX throw an exception */ bs->offset += aimutil_put8(bs->data + bs->offset, v); return 1; }
int aimbs_put8(aim_bstream_t *bs, guint8 v) { if (aim_bstream_empty(bs) < 1) { return 0; /* XXX throw an exception */ } bs->offset += aimutil_put8(bs->data + bs->offset, v); return 1; }
/* * Send a Chat Message. * * Possible flags: * AIM_CHATFLAGS_NOREFLECT -- Unset the flag that requests messages * should be sent to their sender. * AIM_CHATFLAGS_AWAY -- Mark the message as an autoresponse * (Note that WinAIM does not honor this, * and displays the message as normal.) * * XXX convert this to use tlvchains */ faim_export int aim_chat_send_im(aim_session_t *sess, aim_conn_t *conn, fu16_t flags, const char *msg, int msglen) { int i; aim_frame_t *fr; aim_msgcookie_t *cookie; aim_snacid_t snacid; fu8_t ckstr[8]; aim_tlvlist_t *otl = NULL, *itl = NULL; if (!sess || !conn || !msg || (msglen <= 0)) return 0; if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) return -ENOMEM; snacid = aim_cachesnac(sess, 0x000e, 0x0005, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x000e, 0x0005, 0x0000, snacid); /* * Generate a random message cookie. * * XXX mkcookie should generate the cookie and cache it in one * operation to preserve uniqueness. * */ for (i = 0; i < sizeof(ckstr); i++) aimutil_put8(ckstr+i, (fu8_t) rand()); cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_CHAT, NULL); cookie->data = NULL; /* XXX store something useful here */ aim_cachecookie(sess, cookie); for (i = 0; i < sizeof(ckstr); i++) aimbs_put8(&fr->data, ckstr[i]); /* * Channel ID. */ aimbs_put16(&fr->data, 0x0003); /* * Type 1: Flag meaning this message is destined to the room. */ aim_addtlvtochain_noval(&otl, 0x0001); /* * Type 6: Reflect */ if (!(flags & AIM_CHATFLAGS_NOREFLECT)) aim_addtlvtochain_noval(&otl, 0x0006); /* * Type 7: Autoresponse */ if (flags & AIM_CHATFLAGS_AWAY) aim_addtlvtochain_noval(&otl, 0x0007); /* * SubTLV: Type 1: Message */ aim_addtlvtochain_raw(&itl, 0x0001, strlen(msg), msg); /* * Type 5: Message block. Contains more TLVs. * * This could include other information... We just * put in a message TLV however. * */ aim_addtlvtochain_frozentlvlist(&otl, 0x0005, &itl); aim_writetlvchain(&fr->data, &otl); aim_freetlvchain(&itl); aim_freetlvchain(&otl); aim_tx_enqueue(sess, fr); return 0; }
/* * conn must be a BOS connection! */ faim_export int aim_chat_invite(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *msg, fu16_t exchange, const char *roomname, fu16_t instance) { int i; aim_frame_t *fr; aim_msgcookie_t *cookie; struct aim_invite_priv *priv; fu8_t ckstr[8]; aim_snacid_t snacid; aim_tlvlist_t *otl = NULL, *itl = NULL; fu8_t *hdr; int hdrlen; aim_bstream_t hdrbs; if (!sess || !conn || !sn || !msg || !roomname) return -EINVAL; if (conn->type != AIM_CONN_TYPE_BOS) return -EINVAL; if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152+strlen(sn)+strlen(roomname)+strlen(msg)))) return -ENOMEM; snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, sn, strlen(sn)+1); aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); /* * Cookie */ for (i = 0; i < sizeof(ckstr); i++) aimutil_put8(ckstr, (fu8_t) rand()); /* XXX should be uncached by an unwritten 'invite accept' handler */ if ((priv = malloc(sizeof(struct aim_invite_priv)))) { priv->sn = strdup(sn); priv->roomname = strdup(roomname); priv->exchange = exchange; priv->instance = instance; } if ((cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_INVITE, priv))) aim_cachecookie(sess, cookie); else free(priv); for (i = 0; i < sizeof(ckstr); i++) aimbs_put8(&fr->data, ckstr[i]); /* * Channel (2) */ aimbs_put16(&fr->data, 0x0002); /* * Dest sn */ aimbs_put8(&fr->data, strlen(sn)); aimbs_putraw(&fr->data, sn, strlen(sn)); /* * TLV t(0005) * * Everything else is inside this TLV. * * Sigh. AOL was rather inconsistent right here. So we have * to play some minor tricks. Right inside the type 5 is some * raw data, followed by a series of TLVs. * */ hdrlen = 2+8+16+6+4+4+strlen(msg)+4+2+1+strlen(roomname)+2; hdr = malloc(hdrlen); aim_bstream_init(&hdrbs, hdr, hdrlen); aimbs_put16(&hdrbs, 0x0000); /* Unknown! */ aimbs_putraw(&hdrbs, ckstr, sizeof(ckstr)); /* I think... */ aim_putcap(&hdrbs, AIM_CAPS_CHAT); aim_addtlvtochain16(&itl, 0x000a, 0x0001); aim_addtlvtochain_noval(&itl, 0x000f); aim_addtlvtochain_raw(&itl, 0x000c, strlen(msg), msg); aim_addtlvtochain_chatroom(&itl, 0x2711, exchange, roomname, instance); aim_writetlvchain(&hdrbs, &itl); aim_addtlvtochain_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr); aim_writetlvchain(&fr->data, &otl); free(hdr); aim_freetlvchain(&itl); aim_freetlvchain(&otl); aim_tx_enqueue(sess, fr); return 0; }
/** * aim_proxyconnect - An extrememly quick and dirty SOCKS5 interface. * @sess: Session to connect * @host: Host to connect to * @port: Port to connect to * @statusret: Return value of the connection * * Attempts to connect to the specified host via the configured * proxy settings, if present. If no proxy is configured for * this session, the connection is done directly. * * XXX this is really awful. * */ static int aim_proxyconnect(aim_session_t *sess, const char *host, fu16_t port, fu32_t *statusret) { int fd = -1; if (strlen(sess->socksproxy.server)) { /* connecting via proxy */ int i; unsigned char buf[512]; struct sockaddr_in sa; struct hostent *hp; char *proxy; unsigned short proxyport = 1080; for(i=0;i<(int)strlen(sess->socksproxy.server);i++) { if (sess->socksproxy.server[i] == ':') { proxyport = atoi(&(sess->socksproxy.server[i+1])); break; } } proxy = (char *)malloc(i+1); strncpy(proxy, sess->socksproxy.server, i); proxy[i] = '\0'; if (!(hp = gethostbyname(proxy))) { faimdprintf(sess, 0, "proxyconnect: unable to resolve proxy name\n"); *statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR); return -1; } free(proxy); memset(&sa.sin_zero, 0, 8); sa.sin_port = htons(proxyport); memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); sa.sin_family = hp->h_addrtype; fd = socket(hp->h_addrtype, SOCK_STREAM, 0); if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) { faimdprintf(sess, 0, "proxyconnect: unable to connect to proxy\n"); close(fd); return -1; } i = 0; buf[0] = 0x05; /* SOCKS version 5 */ if (strlen(sess->socksproxy.username)) { buf[1] = 0x02; /* two methods */ buf[2] = 0x00; /* no authentication */ buf[3] = 0x02; /* username/password authentication */ i = 4; } else { buf[1] = 0x01; buf[2] = 0x00; i = 3; } if (write(fd, buf, i) < i) { *statusret = errno; close(fd); return -1; } if (read(fd, buf, 2) < 2) { *statusret = errno; close(fd); return -1; } if ((buf[0] != 0x05) || (buf[1] == 0xff)) { *statusret = EINVAL; close(fd); return -1; } /* check if we're doing username authentication */ if (buf[1] == 0x02) { i = aimutil_put8(buf, 0x01); /* version 1 */ i += aimutil_put8(buf+i, strlen(sess->socksproxy.username)); i += aimutil_putstr(buf+i, sess->socksproxy.username, strlen(sess->socksproxy.username)); i += aimutil_put8(buf+i, strlen(sess->socksproxy.password)); i += aimutil_putstr(buf+i, sess->socksproxy.password, strlen(sess->socksproxy.password)); if (write(fd, buf, i) < i) { *statusret = errno; close(fd); return -1; } if (read(fd, buf, 2) < 2) { *statusret = errno; close(fd); return -1; } if ((buf[0] != 0x01) || (buf[1] != 0x00)) { *statusret = EINVAL; close(fd); return -1; } } i = aimutil_put8(buf, 0x05); i += aimutil_put8(buf+i, 0x01); /* CONNECT */ i += aimutil_put8(buf+i, 0x00); /* reserved */ i += aimutil_put8(buf+i, 0x03); /* address type: host name */ i += aimutil_put8(buf+i, strlen(host)); i += aimutil_putstr(buf+i, host, strlen(host)); i += aimutil_put16(buf+i, port); if (write(fd, buf, i) < i) { *statusret = errno; close(fd); return -1; } if (read(fd, buf, 10) < 10) { *statusret = errno; close(fd); return -1; } if ((buf[0] != 0x05) || (buf[1] != 0x00)) { *statusret = EINVAL; close(fd); return -1; } } else { /* connecting directly */ struct sockaddr_in sa; struct hostent *hp; if (!(hp = gethostbyname(host))) { *statusret = (h_errno | AIM_CONN_STATUS_RESOLVERR); return -1; } memset(&sa, 0, sizeof(struct sockaddr_in)); sa.sin_port = htons(port); memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); sa.sin_family = hp->h_addrtype; fd = socket(hp->h_addrtype, SOCK_STREAM, 0); if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT) fcntl(fd, F_SETFL, O_NONBLOCK); /* XXX save flags */ if (connect(fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) { if (sess->flags & AIM_SESS_FLAGS_NONBLOCKCONNECT) { if ((errno == EINPROGRESS) || (errno == EINTR)) { if (statusret) *statusret |= AIM_CONN_STATUS_INPROGRESS; return fd; } } close(fd); fd = -1; } } return fd; }