# HG changeset patch # User Eric Warmenhoven # Date 988163636 0 # Node ID bacb77b0eb0618ba363c9b469cd3377103d37943 # Parent c39cc2b4422654504de98a629cb39da9ff54653d [gaim-migrate @ 1756] this won't help. committer: Tailor Script diff -r c39cc2b44226 -r bacb77b0eb06 libfaim/CHANGES --- a/libfaim/CHANGES Tue Apr 24 23:23:40 2001 +0000 +++ b/libfaim/CHANGES Wed Apr 25 01:53:56 2001 +0000 @@ -1,6 +1,33 @@ No release numbers ------------------ + - Tue Apr 24 17:36:03 PDT 2001 + - Let Eric generate the hash if he wants. + + - Mon Apr 23 15:58:11 PDT 2001 + - On a clear day, you can see forever. + + - Thu Mar 29 13:05:50 PST 2001 + - Less leaks. + + - Thu Mar 29 14:45:22 CST 2001 (jbm) + - Add module capability to the 0001/001f stuff (jbm) + + - Wed Mar 28 21:20:08 PST 2001 + - Add flags arg to aim_chat_send_im() + - Add msglen arg to aim_send_im and aim_chat_send_im + - This will make more sense when I make the UNICODE commit (tomorrow?) + + - Wed Mar 28 16:51:25 PST 2001 + - I decided it was a good day while I was figuring out that it was a bad day. + - See faimtest and login.c::memrequest(). + - Hopefully I'm done for a while. + + - Tue Mar 27 19:15:10 PST 2001 + - I haven't decided yet whether today is a good day or a bad day. + - Probably both. + - More later. + - Mon Mar 26 16:08:45 PST 2001 - Why didn't anyone tell me buddy-offgoing wasn't working? - *** REQUIRES CLIENT CHANGES... buddy-offgoing now passes a userinfo diff -r c39cc2b44226 -r bacb77b0eb06 libfaim/aim.h --- a/libfaim/aim.h Tue Apr 24 23:23:40 2001 +0000 +++ b/libfaim/aim.h Wed Apr 25 01:53:56 2001 +0000 @@ -169,7 +169,7 @@ long unknown; }; -#define AIM_CLIENTINFO_KNOWNGOOD { \ +#define AIM_CLIENTINFO_KNOWNGOOD_3_5_1670 { \ "AOL Instant Messenger (SM), version 3.5.1670/WIN32", \ 0x0003, \ 0x0005, \ @@ -181,6 +181,28 @@ 0x0000002a, \ } +#define AIM_CLIENTINFO_KNOWNGOOD_4_1_2010 { \ + "AOL Instant Messenger (SM), version 4.1.2010/WIN32", \ + 0x0004, \ + 0x0001, \ + 0x07da, \ + "us", \ + "en", \ + 0x0004, \ + 0x0000, \ + 0x0000004b, \ +} + +/* + * I would make 4.1.2010 the default, but they seem to have found + * an alternate way of breaking that one. + * + * 3.5.1670 should work fine, however, you will be subjected to the + * memory test, which may require you to have a WinAIM binary laying + * around. (see login.c::memrequest()) + */ +#define AIM_CLIENTINFO_KNOWNGOOD AIM_CLIENTINFO_KNOWNGOOD_3_5_1670 + #ifndef TRUE #define TRUE 1 #define FALSE 0 @@ -615,7 +637,7 @@ #define AIM_IMFLAGS_AWAY 0x01 /* mark as an autoreply */ #define AIM_IMFLAGS_ACK 0x02 /* request a receipt notice */ -faim_export unsigned long aim_send_im(struct aim_session_t *, struct aim_conn_t *, char *, u_int, char *); +faim_export unsigned long aim_send_im(struct aim_session_t *, struct aim_conn_t *, const char *destsn, unsigned short flags, const char *msg, int msglen); faim_export int aim_send_im_direct(struct aim_session_t *, struct aim_conn_t *, char *); faim_export struct aim_conn_t * aim_directim_initiate(struct aim_session_t *, struct aim_conn_t *, struct aim_directim_priv *, char *destsn); faim_export struct aim_conn_t *aim_directim_connect(struct aim_session_t *, struct aim_conn_t *, struct aim_directim_priv *); @@ -637,7 +659,11 @@ #define AIM_CAPS_SAVESTOCKS 0x80 faim_export int aim_0002_000b(struct aim_session_t *sess, struct aim_conn_t *conn, const char *sn); -faim_export int aim_0001_0020(struct aim_session_t *sess, struct aim_conn_t *conn); + +#define AIM_SENDMEMBLOCK_FLAG_ISREQUEST 0 +#define AIM_SENDMEMBLOCK_FLAG_ISHASH 1 + +faim_export int aim_sendmemblock(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned long offset, unsigned long len, const unsigned char *buf, unsigned char flag); #define AIM_GETINFO_GENERALINFO 0x00001 #define AIM_GETINFO_AWAYMESSAGE 0x00003 @@ -714,7 +740,9 @@ char *lang2; }; -faim_export unsigned long aim_chat_send_im(struct aim_session_t *sess, struct aim_conn_t *conn, char *msg); +#define AIM_CHATFLAGS_NOREFLECT 0x0001 +#define AIM_CHATFLAGS_AWAY 0x0002 +faim_export unsigned long aim_chat_send_im(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned short flags, const char *msg, int msglen); faim_export unsigned long aim_chat_join(struct aim_session_t *sess, struct aim_conn_t *conn, u_short exchange, const char *roomname); faim_export unsigned long aim_chat_clientready(struct aim_session_t *sess, struct aim_conn_t *conn); faim_export int aim_chat_attachname(struct aim_conn_t *conn, char *roomname); diff -r c39cc2b44226 -r bacb77b0eb06 libfaim/bos.c --- a/libfaim/bos.c Tue Apr 24 23:23:40 2001 +0000 +++ b/libfaim/bos.c Wed Apr 25 01:53:56 2001 +0000 @@ -19,34 +19,6 @@ return aim_genericreq_l(sess, conn, 0x0009, 0x0004, &mask); } -faim_export int aim_0001_0020(struct aim_session_t *sess, struct aim_conn_t *conn) -{ - struct command_tx_struct *tx; - int i = 0; - - if (!sess || !conn) - return 0; - - if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+16))) - return -1; - - tx->lock = 1; - - /* Hummm.... */ - i = aim_putsnac(tx->data, 0x0001, 0x0020, 0x0000, sess->snac_nextid++); - i += aimutil_put16(tx->data+i, 0x0010); - i += aimutil_put32(tx->data+i, 0xd41d8cd9); - i += aimutil_put32(tx->data+i, 0x8f00b204); - i += aimutil_put32(tx->data+i, 0xe9800998); - i += aimutil_put32(tx->data+i, 0xecf8427e); - - tx->commandlen = i; - tx->lock = 0; - aim_tx_enqueue(sess, tx); - - return 0; -} - static int rights(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { rxcallback_t userfunc; diff -r c39cc2b44226 -r bacb77b0eb06 libfaim/chat.c --- a/libfaim/chat.c Tue Apr 24 23:23:40 2001 +0000 +++ b/libfaim/chat.c Wed Apr 25 01:53:56 2001 +0000 @@ -51,17 +51,30 @@ return 0; } -/* XXX convert this to use tlvchains */ +/* + * 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 unsigned long aim_chat_send_im(struct aim_session_t *sess, struct aim_conn_t *conn, - char *msg) + unsigned short flags, + const char *msg, + int msglen) { int curbyte,i; struct command_tx_struct *newpacket; struct aim_msgcookie_t *cookie; - if (!sess || !conn || !msg) + if (!sess || !conn || !msg || (msglen <= 0)) return 0; if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 1152))) @@ -90,16 +103,26 @@ curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003); /* - * Type 1: Unknown. Blank. + * Type 1: Flag meaning this message is destined to the room. */ curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); /* - * Type 6: Unknown. Blank. + * Type 6: Reflect */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0006); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + if (!(flags & AIM_CHATFLAGS_NOREFLECT)) { + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0006); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + } + + /* + * Type 7: Autoresponse + */ + if (flags & AIM_CHATFLAGS_AWAY) { + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0007); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000); + } /* * Type 5: Message block. Contains more TLVs. diff -r c39cc2b44226 -r bacb77b0eb06 libfaim/im.c --- a/libfaim/im.c Tue Apr 24 23:23:40 2001 +0000 +++ b/libfaim/im.c Wed Apr 25 01:53:56 2001 +0000 @@ -75,18 +75,18 @@ * when the message is received (of type 0x0004/0x000c) * */ -faim_export unsigned long aim_send_im(struct aim_session_t *sess, - struct aim_conn_t *conn, - char *destsn, u_int flags, char *msg) -{ - +faim_export unsigned long aim_send_im(struct aim_session_t *sess, struct aim_conn_t *conn, const char *destsn, unsigned short flags, const char *msg, int msglen) +{ int curbyte,i; struct command_tx_struct *newpacket; - - if (strlen(msg) >= MAXMSGLEN) + + if (!msg || (msglen <= 0)) return -1; - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, strlen(msg)+256))) + if (msglen >= MAXMSGLEN) + return -1; + + if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, msglen+256))) return -1; newpacket->lock = 1; /* lock struct */ @@ -122,7 +122,7 @@ * metaTLV start. */ curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); - curbyte += aimutil_put16(newpacket->data+curbyte, strlen(msg) + 0x10); + curbyte += aimutil_put16(newpacket->data+curbyte, msglen + 0x10); /* * Flag data / ICBM Parameters? @@ -145,7 +145,7 @@ /* * Message block length. */ - curbyte += aimutil_put16(newpacket->data+curbyte, strlen(msg) + 0x04); + curbyte += aimutil_put16(newpacket->data+curbyte, msglen + 0x04); /* * Character set data? @@ -156,7 +156,7 @@ /* * Message. Not terminated. */ - curbyte += aimutil_putstr(newpacket->data+curbyte,msg, strlen(msg)); + curbyte += aimutil_putstr(newpacket->data+curbyte,msg, msglen); /* * Set the Request Acknowledge flag. diff -r c39cc2b44226 -r bacb77b0eb06 libfaim/login.c --- a/libfaim/login.c Tue Apr 24 23:23:40 2001 +0000 +++ b/libfaim/login.c Wed Apr 25 01:53:56 2001 +0000 @@ -121,9 +121,9 @@ * * This is the initial login request packet. * - * The password is encoded before transmition, as per - * encode_password(). See that function for their - * stupid method of doing it. + * NOTE!! If you want/need to make use of the aim_sendmemblock() function, + * then the client information you send here must exactly match the + * executable that you're pulling the data from. * * Latest WinAIM: * clientstring = "AOL Instant Messenger (SM), version 4.3.2188/WIN32" @@ -138,6 +138,15 @@ * unknown4a = 0x01 * * Latest WinAIM that libfaim can emulate without server-side buddylists: + * clientstring = "AOL Instant Messenger (SM), version 4.1.2010/WIN32" + * major2 = 0x0004 + * major = 0x0004 + * minor = 0x0001 + * minor2 = 0x0000 + * build = 0x07da + * unknown= 0x0000004b + * + * WinAIM 3.5.1670: * clientstring = "AOL Instant Messenger (SM), version 3.5.1670/WIN32" * major2 = 0x0004 * major = 0x0003 @@ -146,6 +155,25 @@ * build = 0x0686 * unknown =0x0000002a * + * Java AIM 1.1.19: + * clientstring = "AOL Instant Messenger (TM) version 1.1.19 for Java built 03/24/98, freeMem 215871 totalMem 1048567, i686, Linus, #2 SMP Sun Feb 11 03:41:17 UTC 2001 2.4.1-ac9, IBM Corporation, 1.1.8, 45.3, Tue Mar 27 12:09:17 PST 2001" + * major2 = 0x0001 + * major = 0x0001 + * minor = 0x0001 + * minor2 = (not sent) + * build = 0x0013 + * unknown= (not sent) + * + * AIM for Linux 1.1.112: + * clientstring = "AOL Instant Messenger (SM)" + * major2 = 0x1d09 + * major = 0x0001 + * minor = 0x0001 + * minor2 = 0x0001 + * build = 0x0070 + * unknown= 0x0000008b + * serverstore = 0x01 + * */ faim_export int aim_send_login (struct aim_session_t *sess, struct aim_conn_t *conn, @@ -646,6 +674,164 @@ return 0; } +/* + * Starting this past week (26 Mar 2001, say), AOL has started sending + * this nice little extra SNAC. AFAIK, it has never been used until now. + * + * The request contains eight bytes. The first four are an offset, the + * second four are a length. + * + * The offset is an offset into aim.exe when it is mapped during execution + * on Win32. So far, AOL has only been requesting bytes in static regions + * of memory. (I won't put it past them to start requesting data in + * less static regions -- regions that are initialized at run time, but still + * before the client recieves this request.) + * + * When the client recieves the request, it adds it to the current ds + * (0x00400000) and dereferences it, copying the data into a buffer which + * it then runs directly through the MD5 hasher. The 16 byte output of + * the hash is then sent back to the server. + * + * If the client does not send any data back, or the data does not match + * the data that the specific client should have, the client will get the + * following message from "AOL Instant Messenger": + * "You have been disconnected from the AOL Instant Message Service (SM) + * for accessing the AOL network using unauthorized software. You can + * download a FREE, fully featured, and authorized client, here + * http://www.aol.com/aim/download2.html" + * The connection is then closed, recieving disconnect code 1, URL + * http://www.aim.aol.com/errors/USER_LOGGED_OFF_NEW_LOGIN.html. + * + * Note, however, that numerous inconsistencies can cause the above error, + * not just sending back a bad hash. Do not immediatly suspect this code + * if you get disconnected. AOL and the open/free software community have + * played this game for a couple years now, generating the above message + * on numerous ocassions. + * + * Anyway, neener. We win again. + * + */ +static int memrequest(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) +{ + rxcallback_t userfunc; + unsigned long offset, len; + int i = 0; + struct aim_tlvlist_t *list; + char *modname = NULL; + + offset = aimutil_get32(data); + i += 4; + + len = aimutil_get32(data+4); + i += 4; + + list = aim_readtlvchain(data+i, datalen-i); + + if (aim_gettlv(list, 0x0001, 1)) + modname = aim_gettlv_str(list, 0x0001, 1); + + faimdprintf(sess, 1, "data at 0x%08lx (%d bytes) of requested\n", offset, len, modname?modname:"aim.exe"); + + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) + return userfunc(sess, rx, offset, len, modname); + + free(modname); + aim_freetlvchain(&list); + + return 0; +} + +static void dumpbox(struct aim_session_t *sess, unsigned char *buf, int len) +{ + int i = 0; + + if (!sess || !buf || !len) + return; + + faimdprintf(sess, 1, "\nDump of %d bytes at %p:", len, buf); + + for (i = 0; i < len; i++) + { + if ((i % 8) == 0) + faimdprintf(sess, 1, "\n\t"); + + faimdprintf(sess, 1, "0x%2x ", buf[i]); + } + + faimdprintf(sess, 1, "\n\n"); + + return; +} + +faim_export int aim_sendmemblock(struct aim_session_t *sess, struct aim_conn_t *conn, unsigned long offset, unsigned long len, const unsigned char *buf, unsigned char flag) +{ + struct command_tx_struct *tx; + int i = 0; + + if (!sess || !conn || ((offset == 0) && !buf)) + return 0; + + if (!(tx = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+2+16))) + return -1; + + tx->lock = 1; + + i = aim_putsnac(tx->data, 0x0001, 0x0020, 0x0000, sess->snac_nextid++); + i += aimutil_put16(tx->data+i, 0x0010); /* md5 is always 16 bytes */ + + if ((flag == AIM_SENDMEMBLOCK_FLAG_ISHASH) && + buf && (len == 0x10)) { /* we're getting a hash */ + + memcpy(tx->data+i, buf, 0x10); + i += 0x10; + + } else if (buf && (len > 0)) { /* use input buffer */ + md5_state_t state; + + md5_init(&state); + md5_append(&state, (const md5_byte_t *)buf, len); + md5_finish(&state, (md5_byte_t *)(tx->data+i)); + i += 0x10; + + } else if (len == 0) { /* no length, just hash NULL (buf is optional) */ + md5_state_t state; + unsigned char nil = '\0'; + + /* + * These MD5 routines are stupid in that you have to have + * at least one append. So thats why this doesn't look + * real logical. + */ + md5_init(&state); + md5_append(&state, (const md5_byte_t *)&nil, 0); + md5_finish(&state, (md5_byte_t *)(tx->data+i)); + i += 0x10; + + } else { + + if ((offset != 0x00001004) || (len != 0x00000004)) + faimdprintf(sess, 0, "sendmemblock: WARNING: sending bad hash... you will be disconnected soon...\n"); + + /* + * This data is correct for AIM 3.5.1670, offset 0x1004, length 4 + * + * Using this block is as close to "legal" as you can get without + * using an AIM binary. + */ + i += aimutil_put32(tx->data+i, 0x92bd6757); + i += aimutil_put32(tx->data+i, 0x3722cbd3); + i += aimutil_put32(tx->data+i, 0x2b048ab9); + i += aimutil_put32(tx->data+i, 0xd0b1e4ab); + + } + + tx->commandlen = i; + tx->lock = 0; + aim_tx_enqueue(sess, tx); + + return 0; +} + static int snachandler(struct aim_session_t *sess, aim_module_t *mod, struct command_rx_struct *rx, aim_modsnac_t *snac, unsigned char *data, int datalen) { @@ -665,6 +851,8 @@ return motd(sess, mod, rx, snac, data, datalen); else if (snac->subtype == 0x0018) return hostversions(sess, mod, rx, snac, data, datalen); + else if (snac->subtype == 0x001f) + return memrequest(sess, mod, rx, snac, data, datalen); return 0; } diff -r c39cc2b44226 -r bacb77b0eb06 src/oscar.c --- a/src/oscar.c Tue Apr 24 23:23:40 2001 +0000 +++ b/src/oscar.c Wed Apr 25 01:53:56 2001 +0000 @@ -243,6 +243,7 @@ static int gaim_parse_buddyrights(struct aim_session_t *, struct command_rx_struct *, ...); static int gaim_parse_locerr (struct aim_session_t *, struct command_rx_struct *, ...); static int gaim_parse_genericerr (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_memrequest (struct aim_session_t *, struct command_rx_struct *, ...); static int gaim_directim_initiate (struct aim_session_t *, struct command_rx_struct *, ...); static int gaim_directim_incoming (struct aim_session_t *, struct command_rx_struct *, ...); @@ -593,6 +594,7 @@ aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, gaim_parse_genericerr, 0); aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, gaim_parse_genericerr, 0); aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, gaim_parse_genericerr, 0); + aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, gaim_memrequest, 0); aim_auth_sendcookie(sess, bosconn, cookie); ((struct oscar_data *)gc->proto_data)->conn = bosconn; @@ -602,6 +604,87 @@ return 1; } +struct pieceofcrap { + struct gaim_connection *gc; + unsigned long offset; + unsigned long len; + char *modname; + struct aim_conn_t *conn; + struct aim_conn_t *mainconn; + unsigned int inpa; +}; + +void damn_you(gpointer data, gint source, GdkInputCondition c) +{ + struct pieceofcrap *pos = data; + struct oscar_data *od = pos->gc->proto_data; + char in; + int x = 0; + char m[17]; + if (c == GDK_INPUT_WRITE) { + char buf[BUF_LONG]; + aim_conn_completeconnect(od->sess, pos->conn); + g_snprintf(buf, sizeof(buf), "GET http://gaim.sourceforge.net/aim_data.php3?" + "offset=%d&len=%d&modname=%s HTTP/1.0\n\n", + pos->offset, pos->len, pos->modname ? pos->modname : ""); + write(pos->conn->fd, buf, strlen(buf)); + if (pos->modname) + g_free(pos->modname); + gdk_input_remove(pos->inpa); + pos->inpa = gdk_input_add(pos->conn->fd, GDK_INPUT_READ, damn_you, pos); + return; + } + + while (read(pos->conn->fd, &in, 1) == 1) { + if (in == '\n') + x++; + else if (in != '\r') + x = 0; + if (x == 2) + break; + } + read(pos->conn->fd, m, 16); + m[16] = '\0'; + gdk_input_remove(pos->inpa); + close(pos->conn->fd); + aim_conn_kill(od->sess, &pos->conn); + aim_sendmemblock(od->sess, pos->mainconn, 0, 16, m, AIM_SENDMEMBLOCK_FLAG_ISHASH); + g_free(pos); +} + +int gaim_memrequest(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + va_list ap; + struct pieceofcrap *pos; + unsigned long offset, len; + char *modname; + + va_start(ap, command); + offset = va_arg(ap, unsigned long); + len = va_arg(ap, unsigned long); + modname = va_arg(ap, char *); + va_end(ap); + + if (len == 0) { + aim_sendmemblock(sess, command->conn, offset, len, NULL, + AIM_SENDMEMBLOCK_FLAG_ISREQUEST); + return; + } + + pos = g_new0(struct pieceofcrap, 1); + pos->gc = sess->aux_data; + pos->mainconn = command->conn; + + pos->offset = offset; + pos->len = len; + pos->modname = modname ? g_strdup(modname) : NULL; + + pos->conn = aim_newconn(sess, 0, "gaim.sourceforge.net:80"); + pos->inpa = gdk_input_add(pos->conn->fd, GDK_INPUT_WRITE, damn_you, pos); + + return 1; +} + void some_name(char *buf) { int x[4]; @@ -1448,8 +1531,6 @@ do_error_dialog(_("Your connection may be lost."), _("AOL error")); - aim_0001_0020(sess, command->conn); - return 1; } @@ -1893,9 +1974,11 @@ aim_send_im_direct(odata->sess, dim->conn, message); } else { if (away) - aim_send_im(odata->sess, odata->conn, name, AIM_IMFLAGS_AWAY, message); + aim_send_im(odata->sess, odata->conn, name, AIM_IMFLAGS_AWAY, message, + strlen(message)); else - aim_send_im(odata->sess, odata->conn, name, AIM_IMFLAGS_ACK, message); + aim_send_im(odata->sess, odata->conn, name, AIM_IMFLAGS_ACK, message, + strlen(message)); } } @@ -2069,7 +2152,7 @@ return; cn = aim_chat_getconn(odata->sess, b->name); - aim_chat_send_im(odata->sess, cn, message); + aim_chat_send_im(odata->sess, cn, 0, message, strlen(message)); } static char **oscar_list_icon(int uc) {