/** * aim_gettlv8 - Retrieve the Nth TLV in chain as a 8bit integer. * @list: Source TLV chain * @type: TLV type to search for * @nth: Index of TLV to return * * Same as aim_gettlv(), except that the return value is a * 8bit integer instead of an aim_tlv_t. * */ faim_internal fu8_t aim_gettlv8(aim_tlvlist_t *list, const fu16_t t, const int n) { aim_tlv_t *tlv; if (!(tlv = aim_gettlv(list, t, n))) return 0; /* erm */ return aimutil_get8(tlv->value); }
guint8 byte_stream_get8(ByteStream *bs) { if (byte_stream_empty(bs) < 1) return 0; /* XXX throw an exception */ bs->offset++; return aimutil_get8(bs->data + bs->offset - 1); }
faim_internal fu8_t aimbs_get8(aim_bstream_t *bs) { if (aim_bstream_empty(bs) < 1) return 0; /* XXX throw an exception */ bs->offset++; return aimutil_get8(bs->data + bs->offset - 1); }
guint8 aimbs_get8(aim_bstream_t *bs) { if (aim_bstream_empty(bs) < 1) { return 0; /* XXX throw an exception */ } bs->offset++; return aimutil_get8(bs->data + bs->offset - 1); }
/** * Read in all available data on the socket for a given connection. * All complete FLAPs handled immedate after they're received. * Incomplete FLAP data is stored locally and appended to the next * time this callback is triggered. * * This is called by flap_connection_recv_cb and * flap_connection_recv_cb_ssl for unencrypted/encrypted connections. */ static void flap_connection_recv(FlapConnection *conn) { gpointer buf; gsize buflen; gssize read; /* Read data until we run out of data and break out of the loop */ while (TRUE) { /* Start reading a new FLAP */ if (conn->buffer_incoming.data.data == NULL) { buf = conn->header + conn->header_received; buflen = 6 - conn->header_received; /* Read the first 6 bytes (the FLAP header) */ if (conn->gsc) read = purple_ssl_read(conn->gsc, buf, buflen); else read = recv(conn->fd, buf, buflen, 0); /* Check if the FLAP server closed the connection */ if (read == 0) { flap_connection_schedule_destroy(conn, OSCAR_DISCONNECT_REMOTE_CLOSED, NULL); break; } /* If there was an error then close the connection */ if (read < 0) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) /* No worries */ break; /* Error! */ flap_connection_schedule_destroy(conn, OSCAR_DISCONNECT_LOST_CONNECTION, g_strerror(errno)); break; } conn->od->gc->last_received = time(NULL); /* If we don't even have a complete FLAP header then do nothing */ conn->header_received += read; if (conn->header_received < 6) break; /* All FLAP frames must start with the byte 0x2a */ if (aimutil_get8(&conn->header[0]) != 0x2a) { flap_connection_schedule_destroy(conn, OSCAR_DISCONNECT_INVALID_DATA, NULL); break; } /* Initialize a new temporary FlapFrame for incoming data */ conn->buffer_incoming.channel = aimutil_get8(&conn->header[1]); conn->buffer_incoming.seqnum = aimutil_get16(&conn->header[2]); conn->buffer_incoming.data.len = aimutil_get16(&conn->header[4]); conn->buffer_incoming.data.data = g_new(guint8, conn->buffer_incoming.data.len); conn->buffer_incoming.data.offset = 0; } buflen = conn->buffer_incoming.data.len - conn->buffer_incoming.data.offset; if (buflen) { buf = &conn->buffer_incoming.data.data[conn->buffer_incoming.data.offset]; /* Read data into the temporary FlapFrame until it is complete */ if (conn->gsc) read = purple_ssl_read(conn->gsc, buf, buflen); else read = recv(conn->fd, buf, buflen, 0); /* Check if the FLAP server closed the connection */ if (read == 0) { flap_connection_schedule_destroy(conn, OSCAR_DISCONNECT_REMOTE_CLOSED, NULL); break; } if (read < 0) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) /* No worries */ break; /* Error! */ flap_connection_schedule_destroy(conn, OSCAR_DISCONNECT_LOST_CONNECTION, g_strerror(errno)); break; } conn->buffer_incoming.data.offset += read; if (conn->buffer_incoming.data.offset < conn->buffer_incoming.data.len) /* Waiting for more data to arrive */ break; } /* We have a complete FLAP! Handle it and continue reading */ byte_stream_rewind(&conn->buffer_incoming.data); parse_flap(conn->od, conn, &conn->buffer_incoming); conn->lastactivity = time(NULL); g_free(conn->buffer_incoming.data.data); conn->buffer_incoming.data.data = NULL; conn->header_received = 0; } }
static int incomingim_ch2(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, aim_tlvlist_t *tlvlist, guint8 *cookie) { aim_rxcallback_t userfunc; aim_tlv_t *block1, *servdatatlv; aim_tlvlist_t *list2; struct aim_incomingim_ch2_args args; aim_bstream_t bbs, sdbs, *sdbsptr = NULL; guint8 *cookie2; int ret = 0; char clientip1[30] = {""}; char clientip2[30] = {""}; char verifiedip[30] = {""}; memset(&args, 0, sizeof(args)); /* * There's another block of TLVs embedded in the type 5 here. */ block1 = aim_gettlv(tlvlist, 0x0005, 1); aim_bstream_init(&bbs, block1->value, block1->length); /* * First two bytes represent the status of the connection. * * 0 is a request, 1 is a deny (?), 2 is an accept */ args.status = aimbs_get16(&bbs); /* * Next comes the cookie. Should match the ICBM cookie. */ cookie2 = aimbs_getraw(&bbs, 8); if (memcmp(cookie, cookie2, 8) != 0) imcb_error(sess->aux_data, "rend: warning cookies don't match!"); memcpy(args.cookie, cookie2, 8); g_free(cookie2); /* * The next 16bytes are a capability block so we can * identify what type of rendezvous this is. */ args.reqclass = aim_getcap(sess, &bbs, 0x10); /* * 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(&bbs); /* * IP address from the perspective of the client. */ if (aim_gettlv(list2, 0x0002, 1)) { aim_tlv_t *iptlv; iptlv = aim_gettlv(list2, 0x0002, 1); g_snprintf(clientip1, sizeof(clientip1), "%d.%d.%d.%d", aimutil_get8(iptlv->value+0), aimutil_get8(iptlv->value+1), aimutil_get8(iptlv->value+2), aimutil_get8(iptlv->value+3)); } /* * Secondary IP address from the perspective of the client. */ if (aim_gettlv(list2, 0x0003, 1)) { aim_tlv_t *iptlv; iptlv = aim_gettlv(list2, 0x0003, 1); g_snprintf(clientip2, sizeof(clientip2), "%d.%d.%d.%d", aimutil_get8(iptlv->value+0), aimutil_get8(iptlv->value+1), aimutil_get8(iptlv->value+2), aimutil_get8(iptlv->value+3)); } /* * Verified IP address (from the perspective of Oscar). * * This is added by the server. */ if (aim_gettlv(list2, 0x0004, 1)) { aim_tlv_t *iptlv; iptlv = aim_gettlv(list2, 0x0004, 1); g_snprintf(verifiedip, sizeof(verifiedip), "%d.%d.%d.%d", aimutil_get8(iptlv->value+0), aimutil_get8(iptlv->value+1), aimutil_get8(iptlv->value+2), aimutil_get8(iptlv->value+3)); } /* * Port number for something. */ if (aim_gettlv(list2, 0x0005, 1)) args.port = aim_gettlv16(list2, 0x0005, 1); /* * Error code. */ if (aim_gettlv(list2, 0x000b, 1)) args.errorcode = aim_gettlv16(list2, 0x000b, 1); /* * Invitation message / chat description. */ if (aim_gettlv(list2, 0x000c, 1)) args.msg = aim_gettlv_str(list2, 0x000c, 1); /* * Character set. */ if (aim_gettlv(list2, 0x000d, 1)) args.encoding = aim_gettlv_str(list2, 0x000d, 1); /* * Language. */ if (aim_gettlv(list2, 0x000e, 1)) args.language = aim_gettlv_str(list2, 0x000e, 1); /* Unknown -- two bytes = 0x0001 */ if (aim_gettlv(list2, 0x000a, 1)) ; /* Unknown -- no value */ if (aim_gettlv(list2, 0x000f, 1)) ; if (strlen(clientip1)) args.clientip = (char *)clientip1; if (strlen(clientip2)) args.clientip2 = (char *)clientip2; if (strlen(verifiedip)) args.verifiedip = (char *)verifiedip; /* * This is must be present in PROPOSALs, but will probably not * exist in CANCELs and ACCEPTs. * * Service Data blocks are module-specific in format. */ if ((servdatatlv = aim_gettlv(list2, 0x2711 /* 10001 */, 1))) { aim_bstream_init(&sdbs, servdatatlv->value, servdatatlv->length); sdbsptr = &sdbs; } if (args.reqclass & AIM_CAPS_ICQSERVERRELAY) incomingim_ch2_icqserverrelay(sess, mod, rx, snac, userinfo, &args, sdbsptr); else if (args.reqclass & AIM_CAPS_CHAT) incomingim_ch2_chat(sess, mod, rx, snac, userinfo, &args, sdbsptr); if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) ret = userfunc(sess, rx, channel, userinfo, &args); if (args.destructor) ((ch2_args_destructor_t)args.destructor)(sess, &args); g_free((char *)args.msg); g_free((char *)args.encoding); g_free((char *)args.language); aim_freetlvchain(&list2); return ret; }