faim_export int aim_icq_reqofflinemsgs(aim_session_t *sess) { aim_conn_t *conn; aim_frame_t *fr; aim_snacid_t snacid; int bslen; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) return -EINVAL; bslen = 2 + 4 + 2 + 2; if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) return -ENOMEM; snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid); /* For simplicity, don't bother using a tlvlist */ aimbs_put16(&fr->data, 0x0001); aimbs_put16(&fr->data, bslen); aimbs_putle16(&fr->data, bslen - 2); aimbs_putle32(&fr->data, atoi(sess->sn)); aimbs_putle16(&fr->data, 0x003c); /* I command thee. */ aimbs_putle16(&fr->data, snacid); /* eh. */ aim_tx_enqueue(sess, fr); return 0; }
/** * Subtype 0x0004 - Request someone's icon. * * @param sess The oscar session. * @param conn The icon connection for this session. * @param sn The screen name of the person who's icon you are requesting. * @param iconcsum The MD5 checksum of the icon you are requesting. * @param iconcsumlen Length of the MD5 checksum given above. Should be 10 bytes. * @return Return 0 if no errors, otherwise return the error number. */ faim_export int aim_bart_request(aim_session_t *sess, const char *sn, fu8_t iconcsumtype, const fu8_t *iconcsum, fu16_t iconcsumlen) { aim_conn_t *conn; aim_frame_t *fr; aim_snacid_t snacid; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0010)) || !sn || !strlen(sn) || !iconcsum || !iconcsumlen) return -EINVAL; if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 1+strlen(sn) + 4 + 1+iconcsumlen))) return -ENOMEM; snacid = aim_cachesnac(sess, 0x0010, 0x0004, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0010, 0x0004, 0x0000, snacid); /* Screen name */ aimbs_put8(&fr->data, strlen(sn)); aimbs_putraw(&fr->data, sn, strlen(sn)); /* Some numbers. You like numbers, right? */ aimbs_put8(&fr->data, 0x01); aimbs_put16(&fr->data, 0x0001); aimbs_put8(&fr->data, iconcsumtype); /* Icon string */ aimbs_put8(&fr->data, iconcsumlen); aimbs_putraw(&fr->data, iconcsum, iconcsumlen); aim_tx_enqueue(sess, fr); return 0; }
/** * answers status message requests * @param sess the oscar session * @param sender the guy whos asking * @param cookie message id which we are answering for * @param message away message * @param state our current away state the way icq requests it (0xE8 for away, 0xE9 occupied, ...) * @return 0 if no error */ int aim_send_im_ch2_statusmessage(aim_session_t *sess, const char *sender, const guint8 *cookie, const char *message, const guint8 state, const guint16 dc) { aim_conn_t *conn; aim_frame_t *fr; aim_snacid_t snacid; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) return -EINVAL; if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+8+2+1+strlen(sender)+2+0x1d+0x10+9+strlen(message)+1))) return -ENOMEM; snacid = aim_cachesnac(sess, 0x0004, 0x000b, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0004, 0x000b, 0x0000, snacid); aimbs_putraw(&fr->data, cookie, 8); aimbs_put16(&fr->data, 0x0002); /* channel */ aimbs_put8(&fr->data, strlen(sender)); aimbs_putraw(&fr->data, (guint8 *)sender, strlen(sender)); aimbs_put16(&fr->data, 0x0003); /* reason: channel specific */ aimbs_putle16(&fr->data, 0x001b); /* length of data SEQ1 */ aimbs_putle16(&fr->data, 0x0008); /* protocol version */ aimbs_putle32(&fr->data, 0x0000); /* no plugin -> 16 times 0x00 */ aimbs_putle32(&fr->data, 0x0000); aimbs_putle32(&fr->data, 0x0000); aimbs_putle32(&fr->data, 0x0000); aimbs_putle16(&fr->data, 0x0000); /* unknown */ aimbs_putle32(&fr->data, 0x0003); /* client features */ aimbs_putle8(&fr->data, 0x00); /* unknown */ aimbs_putle16(&fr->data, dc); /* Sequence number? XXX - This should decrement by 1 with each request */ /* end of SEQ1 */ aimbs_putle16(&fr->data, 0x000e); /* Length of SEQ2 */ aimbs_putle16(&fr->data, dc); /* Sequence number? same as above * XXX - This should decrement by 1 with each request */ aimbs_putle32(&fr->data, 0x00000000); /* Unknown */ aimbs_putle32(&fr->data, 0x00000000); /* Unknown */ aimbs_putle32(&fr->data, 0x00000000); /* Unknown */ /* end of SEQ2 */ /* now for the real fun */ aimbs_putle8(&fr->data, state); /* away state */ aimbs_putle8(&fr->data, 0x03); /* msg-flag: 03 for states */ aimbs_putle16(&fr->data, 0x0000); /* status code ? */ aimbs_putle16(&fr->data, 0x0000); /* priority code */ aimbs_putle16(&fr->data, strlen(message) + 1); /* message length + termination */ aimbs_putraw(&fr->data, (guint8 *) message, strlen(message) + 1); /* null terminated string */ aim_tx_enqueue(sess, fr); return 0; }
/** * Subtype 0x0002 - Upload your icon. * * @param sess The oscar session. * @param conn The icon connection for this session. * @param icon The raw data of the icon image file. * @param iconlen Length of the raw data of the icon image file. * @return Return 0 if no errors, otherwise return the error number. */ faim_export int aim_bart_upload(aim_session_t *sess, const fu8_t *icon, fu16_t iconlen) { aim_conn_t *conn; aim_frame_t *fr; aim_snacid_t snacid; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0010)) || !icon || !iconlen) return -EINVAL; if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 2 + 2+iconlen))) return -ENOMEM; snacid = aim_cachesnac(sess, 0x0010, 0x0002, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0010, 0x0002, 0x0000, snacid); /* The reference number for the icon */ aimbs_put16(&fr->data, 1); /* The icon */ aimbs_put16(&fr->data, iconlen); aimbs_putraw(&fr->data, icon, iconlen); aim_tx_enqueue(sess, fr); return 0; }
/* * * I definitly recommend sending this. If you don't, you'll be stuck * with the rather unreasonable defaults. You don't want those. Send this. * */ int aim_seticbmparam(aim_session_t *sess, struct aim_icbmparameters *params) { aim_conn_t *conn; aim_frame_t *fr; aim_snacid_t snacid; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) return -EINVAL; if (!params) return -EINVAL; if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+16))) return -ENOMEM; snacid = aim_cachesnac(sess, 0x0004, 0x0002, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0004, 0x0002, 0x0000, snacid); /* This is read-only (see Parameter Reply). Must be set to zero here. */ aimbs_put16(&fr->data, 0x0000); /* These are all read-write */ aimbs_put32(&fr->data, params->flags); aimbs_put16(&fr->data, params->maxmsglen); aimbs_put16(&fr->data, params->maxsenderwarn); aimbs_put16(&fr->data, params->maxrecverwarn); aimbs_put32(&fr->data, params->minmsginterval); aim_tx_enqueue(sess, fr); return 0; }
/* * aim_reqicbmparaminfo() * * Request ICBM parameter information. * */ int aim_reqicbmparams(aim_session_t *sess) { aim_conn_t *conn; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) return -EINVAL; return aim_genericreq_n(sess, conn, 0x0004, 0x0004); }
/* * Subtype 0x0014 - Send a mini typing notification (mtn) packet. * * This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer, * and Gaim 0.60 and newer. * */ int aim_im_sendmtn(aim_session_t *sess, guint16 type1, const char *sn, guint16 type2) { aim_conn_t *conn; aim_frame_t *fr; aim_snacid_t snacid; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0002))) return -EINVAL; if (!sn) return -EINVAL; if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+11+strlen(sn)+2))) return -ENOMEM; snacid = aim_cachesnac(sess, 0x0004, 0x0014, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0004, 0x0014, 0x0000, snacid); /* * 8 days of light * Er, that is to say, 8 bytes of 0's */ aimbs_put16(&fr->data, 0x0000); aimbs_put16(&fr->data, 0x0000); aimbs_put16(&fr->data, 0x0000); aimbs_put16(&fr->data, 0x0000); /* * Type 1 (should be 0x0001 for mtn) */ aimbs_put16(&fr->data, type1); /* * Dest sn */ aimbs_put8(&fr->data, strlen(sn)); aimbs_putraw(&fr->data, (const guint8*)sn, strlen(sn)); /* * Type 2 (should be 0x0000, 0x0001, or 0x0002 for mtn) */ aimbs_put16(&fr->data, type2); aim_tx_enqueue(sess, fr); return 0; }
faim_export int aim_icq_getalias(aim_session_t *sess, const char *uin) { aim_conn_t *conn; aim_frame_t *fr; aim_snacid_t snacid; int bslen; struct aim_icq_info *info; if (!uin || uin[0] < '0' || uin[0] > '9') return -EINVAL; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) return -EINVAL; bslen = 2 + 4 + 2 + 2 + 2 + 4; if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) return -ENOMEM; snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid); /* For simplicity, don't bother using a tlvlist */ aimbs_put16(&fr->data, 0x0001); aimbs_put16(&fr->data, bslen); aimbs_putle16(&fr->data, bslen - 2); aimbs_putle32(&fr->data, atoi(sess->sn)); aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */ aimbs_putle16(&fr->data, snacid); /* eh. */ aimbs_putle16(&fr->data, 0x04ba); /* shrug. */ aimbs_putle32(&fr->data, atoi(uin)); aim_tx_enqueue(sess, fr); /* Keep track of this request and the ICQ number and request ID */ info = (struct aim_icq_info *)calloc(1, sizeof(struct aim_icq_info)); info->reqid = snacid; info->uin = atoi(uin); info->next = sess->icq_info; sess->icq_info = info; return 0; }
/** * Change your ICQ password. * * @param sess The oscar session * @param passwd The new password. If this is longer than 8 characters it * will be truncated. * @return Return 0 if no errors, otherwise return the error number. */ faim_export int aim_icq_changepasswd(aim_session_t *sess, const char *passwd) { aim_conn_t *conn; aim_frame_t *fr; aim_snacid_t snacid; int bslen, passwdlen; if (!passwd) return -EINVAL; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) return -EINVAL; passwdlen = strlen(passwd); if (passwdlen > MAXICQPASSLEN) passwdlen = MAXICQPASSLEN; bslen = 2+4+2+2+2+2+passwdlen+1; if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) return -ENOMEM; snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid); /* For simplicity, don't bother using a tlvlist */ aimbs_put16(&fr->data, 0x0001); aimbs_put16(&fr->data, bslen); aimbs_putle16(&fr->data, bslen - 2); aimbs_putle32(&fr->data, atoi(sess->sn)); aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */ aimbs_putle16(&fr->data, snacid); /* eh. */ aimbs_putle16(&fr->data, 0x042e); /* shrug. */ aimbs_putle16(&fr->data, passwdlen+1); aimbs_putraw(&fr->data, passwd, passwdlen); aimbs_putle8(&fr->data, '\0'); aim_tx_enqueue(sess, fr); return 0; }
faim_export int aim_icq_sendxmlreq(aim_session_t *sess, const char *xml) { aim_conn_t *conn; aim_frame_t *fr; aim_snacid_t snacid; int bslen; if (!xml || !strlen(xml)) return -EINVAL; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) return -EINVAL; bslen = 2 + 10 + 2 + strlen(xml) + 1; if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) return -ENOMEM; snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid); /* For simplicity, don't bother using a tlvlist */ aimbs_put16(&fr->data, 0x0001); aimbs_put16(&fr->data, bslen); aimbs_putle16(&fr->data, bslen - 2); aimbs_putle32(&fr->data, atoi(sess->sn)); aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */ aimbs_putle16(&fr->data, snacid); /* eh. */ aimbs_putle16(&fr->data, 0x0998); /* shrug. */ aimbs_putle16(&fr->data, strlen(xml) + 1); aimbs_putraw(&fr->data, xml, strlen(xml) + 1); aim_tx_enqueue(sess, fr); return 0; }
faim_export int aim_icq_getsimpleinfo(aim_session_t *sess, const char *uin) { aim_conn_t *conn; aim_frame_t *fr; aim_snacid_t snacid; int bslen; if (!uin || uin[0] < '0' || uin[0] > '9') return -EINVAL; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) return -EINVAL; bslen = 2 + 4 + 2 + 2 + 2 + 4; if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) return -ENOMEM; snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid); /* For simplicity, don't bother using a tlvlist */ aimbs_put16(&fr->data, 0x0001); aimbs_put16(&fr->data, bslen); aimbs_putle16(&fr->data, bslen - 2); aimbs_putle32(&fr->data, atoi(sess->sn)); aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */ aimbs_putle16(&fr->data, snacid); /* eh. */ aimbs_putle16(&fr->data, 0x051f); /* shrug. */ aimbs_putle32(&fr->data, atoi(uin)); aim_tx_enqueue(sess, fr); return 0; }
/* * Send an SMS message. This is the non-US way. The US-way is to IM * their cell phone number (+19195551234). * * We basically construct and send an XML message. The format is: * <icq_sms_message> * <destination>full_phone_without_leading_+</destination> * <text>message</text> * <codepage>1252</codepage> * <senders_UIN>self_uin</senders_UIN> * <senders_name>self_name</senders_name> * <delivery_receipt>Yes|No</delivery_receipt> * <time>Wkd, DD Mmm YYYY HH:MM:SS TMZ</time> * </icq_sms_message> * * Yeah hi Peter, whaaaat's happening. If there's any way to use * a codepage other than 1252 that would be great. Thaaaanks. */ faim_export int aim_icq_sendsms(aim_session_t *sess, const char *name, const char *msg, const char *alias) { aim_conn_t *conn; aim_frame_t *fr; aim_snacid_t snacid; int bslen, xmllen; char *xml, timestr[30]; time_t t; struct tm *tm; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) return -EINVAL; if (!name || !msg || !alias) return -EINVAL; time(&t); tm = gmtime(&t); strftime(timestr, 30, "%a, %d %b %Y %T %Z", tm); /* The length of xml included the null terminating character */ xmllen = 225 + strlen(name) + strlen(msg) + strlen(sess->sn) + strlen(alias) + strlen(timestr) + 1; if (!(xml = (char *)malloc(xmllen*sizeof(char)))) return -ENOMEM; snprintf(xml, xmllen, "<icq_sms_message>\n" "\t<destination>%s</destination>\n" "\t<text>%s</text>\n" "\t<codepage>1252</codepage>\n" "\t<senders_UIN>%s</senders_UIN>\n" "\t<senders_name>%s</senders_name>\n" "\t<delivery_receipt>Yes</delivery_receipt>\n" "\t<time>%s</time>\n" "</icq_sms_message>\n", name, msg, sess->sn, alias, timestr); bslen = 37 + xmllen; if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) { free(xml); return -ENOMEM; } snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid); /* For simplicity, don't bother using a tlvlist */ aimbs_put16(&fr->data, 0x0001); aimbs_put16(&fr->data, bslen); aimbs_putle16(&fr->data, bslen - 2); aimbs_putle32(&fr->data, atoi(sess->sn)); aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */ aimbs_putle16(&fr->data, snacid); /* eh. */ /* From libicq200-0.3.2/src/SNAC-SRV.cpp */ aimbs_putle16(&fr->data, 0x8214); aimbs_put16(&fr->data, 0x0001); aimbs_put16(&fr->data, 0x0016); aimbs_put32(&fr->data, 0x00000000); aimbs_put32(&fr->data, 0x00000000); aimbs_put32(&fr->data, 0x00000000); aimbs_put32(&fr->data, 0x00000000); aimbs_put16(&fr->data, 0x0000); aimbs_put16(&fr->data, xmllen); aimbs_putraw(&fr->data, xml, xmllen); aim_tx_enqueue(sess, fr); free(xml); return 0; }
/* * Send an ICBM (instant message). * * * Possible flags: * AIM_IMFLAGS_AWAY -- Marks the message as an autoresponse * AIM_IMFLAGS_ACK -- Requests that the server send an ack * when the message is received (of type 0x0004/0x000c) * AIM_IMFLAGS_OFFLINE--If destination is offline, store it until they are * online (probably ICQ only). * AIM_IMFLAGS_UNICODE--Instead of ASCII7, the passed message is * made up of UNICODE duples. If you set * this, you'd better be damn sure you know * what you're doing. * AIM_IMFLAGS_ISO_8859_1 -- The message contains the ASCII8 subset * known as ISO-8859-1. * * Generally, you should use the lowest encoding possible to send * your message. If you only use basic punctuation and the generic * Latin alphabet, use ASCII7 (no flags). If you happen to use non-ASCII7 * characters, but they are all clearly defined in ISO-8859-1, then * use that. Keep in mind that not all characters in the PC ASCII8 * character set are defined in the ISO standard. For those cases (most * notably when the (r) symbol is used), you must use the full UNICODE * encoding for your message. In UNICODE mode, _all_ characters must * occupy 16bits, including ones that are not special. (Remember that * the first 128 UNICODE symbols are equivelent to ASCII7, however they * must be prefixed with a zero high order byte.) * * I strongly discourage the use of UNICODE mode, mainly because none * of the clients I use can parse those messages (and besides that, * wchars are difficult and non-portable to handle in most UNIX environments). * If you really need to include special characters, use the HTML UNICODE * entities. These are of the form ߪ where 2026 is the hex * representation of the UNICODE index (in this case, UNICODE * "Horizontal Ellipsis", or 133 in in ASCII8). * * Implementation note: Since this is one of the most-used functions * in all of libfaim, it is written with performance in mind. As such, * it is not as clear as it could be in respect to how this message is * supposed to be layed out. Most obviously, tlvlists should be used * instead of writing out the bytes manually. * * XXX more precise verification that we never send SNACs larger than 8192 * XXX check SNAC size for multipart * */ int aim_send_im_ext(aim_session_t *sess, struct aim_sendimext_args *args) { static const guint8 deffeatures[] = { 0x01, 0x01, 0x01, 0x02 }; aim_conn_t *conn; int i, msgtlvlen; aim_frame_t *fr; aim_snacid_t snacid; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004))) return -EINVAL; if (!args) return -EINVAL; if (args->flags & AIM_IMFLAGS_MULTIPART) { if (args->mpmsg->numparts <= 0) return -EINVAL; } else { if (!args->msg || (args->msglen <= 0)) return -EINVAL; if (args->msglen >= MAXMSGLEN) return -E2BIG; } /* Painfully calculate the size of the message TLV */ msgtlvlen = 1 + 1; /* 0501 */ if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) msgtlvlen += 2 + args->featureslen; else msgtlvlen += 2 + sizeof(deffeatures); if (args->flags & AIM_IMFLAGS_MULTIPART) { aim_mpmsg_section_t *sec; for (sec = args->mpmsg->parts; sec; sec = sec->next) { msgtlvlen += 2 /* 0101 */ + 2 /* block len */; msgtlvlen += 4 /* charset */ + sec->datalen; } } else { msgtlvlen += 2 /* 0101 */ + 2 /* block len */; msgtlvlen += 4 /* charset */ + args->msglen; } if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, msgtlvlen+128))) return -ENOMEM; /* XXX should be optional */ snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1); aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid); /* * Generate a random message cookie * * We could cache these like we do SNAC IDs. (In fact, it * might be a good idea.) In the message error functions, * the 8byte message cookie is returned as well as the * SNAC ID. * */ for (i = 0; i < 8; i++) aimbs_put8(&fr->data, (guint8) rand()); /* * Channel ID */ aimbs_put16(&fr->data, 0x0001); /* * Destination SN (prepended with byte length) */ aimbs_put8(&fr->data, strlen(args->destsn)); aimbs_putraw(&fr->data, (guint8 *)args->destsn, strlen(args->destsn)); /* * Message TLV (type 2). */ aimbs_put16(&fr->data, 0x0002); aimbs_put16(&fr->data, msgtlvlen); /* * Features * */ aimbs_put8(&fr->data, 0x05); aimbs_put8(&fr->data, 0x01); if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) { aimbs_put16(&fr->data, args->featureslen); aimbs_putraw(&fr->data, args->features, args->featureslen); } else { aimbs_put16(&fr->data, sizeof(deffeatures)); aimbs_putraw(&fr->data, deffeatures, sizeof(deffeatures)); } if (args->flags & AIM_IMFLAGS_MULTIPART) { aim_mpmsg_section_t *sec; for (sec = args->mpmsg->parts; sec; sec = sec->next) { aimbs_put16(&fr->data, 0x0101); aimbs_put16(&fr->data, sec->datalen + 4); aimbs_put16(&fr->data, sec->charset); aimbs_put16(&fr->data, sec->charsubset); aimbs_putraw(&fr->data, sec->data, sec->datalen); } } else { aimbs_put16(&fr->data, 0x0101); /* * Message block length. */ aimbs_put16(&fr->data, args->msglen + 0x04); /* * Character set. */ if (args->flags & AIM_IMFLAGS_CUSTOMCHARSET) { aimbs_put16(&fr->data, args->charset); aimbs_put16(&fr->data, args->charsubset); } else { if (args->flags & AIM_IMFLAGS_UNICODE) aimbs_put16(&fr->data, 0x0002); else if (args->flags & AIM_IMFLAGS_ISO_8859_1) aimbs_put16(&fr->data, 0x0003); else aimbs_put16(&fr->data, 0x0000); aimbs_put16(&fr->data, 0x0000); } /* * Message. Not terminated. */ aimbs_putraw(&fr->data, (guint8 *)args->msg, args->msglen); } /* * Set the Request Acknowledge flag. */ if (args->flags & AIM_IMFLAGS_ACK) { aimbs_put16(&fr->data, 0x0003); aimbs_put16(&fr->data, 0x0000); } /* * Set the Autoresponse flag. */ if (args->flags & AIM_IMFLAGS_AWAY) { aimbs_put16(&fr->data, 0x0004); aimbs_put16(&fr->data, 0x0000); } if (args->flags & AIM_IMFLAGS_OFFLINE) { aimbs_put16(&fr->data, 0x0006); aimbs_put16(&fr->data, 0x0000); } /* * Set the I HAVE A REALLY PURTY ICON flag. */ if (args->flags & AIM_IMFLAGS_HASICON) { aimbs_put16(&fr->data, 0x0008); aimbs_put16(&fr->data, 0x000c); aimbs_put32(&fr->data, args->iconlen); aimbs_put16(&fr->data, 0x0001); aimbs_put16(&fr->data, args->iconsum); aimbs_put32(&fr->data, args->iconstamp); } /* * Set the Buddy Icon Requested flag. */ if (args->flags & AIM_IMFLAGS_BUDDYREQ) { aimbs_put16(&fr->data, 0x0009); aimbs_put16(&fr->data, 0x0000); } aim_tx_enqueue(sess, fr); if (!(sess->flags & AIM_SESS_FLAGS_DONTTIMEOUTONICBM)) aim_cleansnacs(sess, 60); /* clean out SNACs over 60sec old */ return 0; }
faim_export int aim_icq_sendsms(aim_session_t *sess, const char *dest, const char *body) { aim_conn_t *conn; aim_frame_t *fr; aim_snacid_t snacid; int bslen; int a; char *xml; int xmllen; char timestr[30]; time_t t; struct tm *tm; if (!body || !strlen(body)) return -EINVAL; if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) return -EINVAL; time(&t); tm = gmtime(&t); strftime(timestr, 30, "%a, %d %b %Y %T %Z", tm); xmllen = 17 + 13 + strlen(dest) + 14 + 6 + strlen(body) + 7 + 25 + 13 + strlen(sess->sn) + 14 + 14 + strlen(sess->sn /* should be nick */) + 15 + 18 + 2 + 19 + 6 + strlen(timestr) + 7 + 18 + 1; bslen = 2 + 4 + 2 + 2 + 2 + 2 + 2 + 16 + 4 + xmllen; if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) return -ENOMEM; xml = (char *) malloc(xmllen); snprintf(xml, xmllen, "<icq_sms_message><destination>%s</destination>"\ "<text>%s</text><codepage>1252</codepage>"\ "<senders_UIN>%s</senders_UIN>"\ "<senders_name>%s</senders_name>"\ "<delivery_receipt>No</delivery_receipt>"\ "<time>%s</time></icq_sms_message>", dest, body, sess->sn, sess->sn /* should be nick */, timestr); snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid); /* For simplicity, don't bother using a tlvlist */ aimbs_put16(&fr->data, 0x0001); aimbs_put16(&fr->data, bslen); aimbs_putle16(&fr->data, bslen - 2); aimbs_putle32(&fr->data, atoi(sess->sn)); aimbs_putle16(&fr->data, 2000); /* I command thee. */ aimbs_putle16(&fr->data, snacid); /* eh. */ aimbs_put16(&fr->data, 0x8214); /* SMS send subtype */ aimbs_put16(&fr->data, 0x0001); aimbs_put16(&fr->data, 0x0016); for(a = 0; a < 16; a++) aimbs_put8(&fr->data, 0x00); aimbs_put32(&fr->data, xmllen); /* yes, this has to be 32 bits */ aimbs_putraw(&fr->data, xml, xmllen); aim_tx_enqueue(sess, fr); free(xml); return 0; }