# HG changeset patch # User Mark Doliner # Date 1041181925 0 # Node ID 1a5dcfa1823e7a7ac22cc3441edf97eea0ec5654 # Parent 1bd663beada50f771a9ff1c7a99b3c1732ceba53 [gaim-migrate @ 4377] Why do I make these things so long? I'm defective, that's why. Mr. Walp pointed out a problem with "allow only peeps in my buddy list" for ICQ, so I fixed that. One important problem: If you set your permdeny to "allow only peeps in my buddy list," and then add or remove someone from your buddy list, it will not update the allow/deny list on the server. And that's a bad thing. I changed an error message string or 4 in oscar.c for various reasons. 1) I feel that "he/she" is much better than "it." If you disagree, please let me know, because I'm not sure of the correct phrasing. 2) There is only 1 unknown reason, it just applies to multiple messages. I shuffled some of the clientauto functions around in oscar.c to make it more uniform. I intend to look into why status messages aren't working well soon. I added some semblance of more advanced ICQ info support to libfaim. There's also a bit of support in oscar.c for it, but making it display itself nicely will take a little work, so I'll do it later. A patch from the good Mr. Blanton taking out a non-ascii character from oscar.c (my bad). A patch from the good Mr. Blanton adding support for i18n to away messages and aim profile info. Questions for the good Mr. Blanton: 1) Line 59 of info.c, in the first half of that if statement, should profile_len also be &&'ed in with the other 2? 2) I changed a gaim_parse_user_info so that it works for non-unicode away messages and profiles. Or so I think. 3) I changed little bits of your patch to appease my annoyingness, so it might not cvs update cleanly for you. Sorry. I organized the ChangeLog entries for 0.60. I tried to put stuff that I thought was more important near the top of each category. Please change stuff around, because I'm pretty sure it could be better. Breathe in, breathe out, breathe in, breathe out... Tied to a wheel... committer: Tailor Script diff -r 1bd663beada5 -r 1a5dcfa1823e ChangeLog --- a/ChangeLog Sat Dec 28 05:15:43 2002 +0000 +++ b/ChangeLog Sun Dec 29 17:12:05 2002 +0000 @@ -1,33 +1,115 @@ -Gaim: The Pimpin' Penguin IM Clone that's good for the soul! +Gaim: The Pimpin' Penguin IM Clone that's good for the soul! version 0.60: - * French translation updated (thanks, Stephane Wirtel, - Sebastian Carpe, and David Odin) - * Polish translation updated (Thanks, Przemyslaw Sulek) - * Finnish translation updated (Thanks, Tero Kuusela) - * Spanish translation updated (Thanks, Lars Goldschlager) - * Traditional Chinese translation updated (Thanks, Paladin Liu) - * Japanese translation updated (Thanks, Junichi Uekawa) - * Korean translation updated (Thanks, A Lee) - * Romanian translation added (Thanks, Misu Moldovan) - * Jabber invisibility and permanently cancel sending on- - line status to Jabber buddies. + Core: + * Auto-loading protocol plugins. + * Plugins dialog and perl script menu merged into preferences. + * Login all auto-login accounts from login window. (Thanks, + Etan Reisner) + * Don't auto-login if an existing Gaim session is already + running. + * Moved "privacy preferences" to Tools menu. + * -n, --loginwin option to disable autologins. + * Added support for gettext 0.11.x. + * Added support for automake 1.6. + * aim:// URI's supported with gaim-remote command. + * Quit Gaim remotely with gaim-remote. (Thanks, John Silvestri) + + Plugins: + * Docklet plugin--replaces the old GNOME applet. You'll need the + Panel Notification Area applet for GNOME 2, or the kicker for + KDE 3.1. (Thanks, Robert McQueen, Ari Pollak, Patrick Aussems) + * Added GAIM::remove_event_handler and made set_info short + circuitable in perl. (Thanks, Ryan McCabe) + * event_del_conversation for plugins. (Thanks, Bill Tompkins) + * Notify.c plugin rewritten; check its configure dialog. (Thanks, + Etan Reisner) + * Buddy Ticker made a plugin. + * I'dle Mak'er added to source. + * Fortune profile added to source. + + AIM/ICQ: + * TOC no longer compiles statically by default--use OSCAR. + * ICQ plugin no longer gets built--use OSCAR. + * File send/receive support for Oscar (Thanks, William T. Mahan) + * Non-direct connect typing notification for AIM over oscar. + (Thanks, Mark Doliner) + * Allow only people in buddy list privacy option added for AIM. * Support for synchronizing group renames on server. Group rename server synchronization for AIM. Server-side synchronization for moving individual AIM buddy to new - group improved. (Thanks, Mark Doliner) + group improved. (Thanks, Mark Doliner) + * Ability to add screenname@mac.com people to AIM buddy lists. + (Thanks, Graham Booker) + * Option to have AIM notify you if you have + unread mail. (Thanks, Mark Doliner) + * Parse URL messages, Contact Sending and Pager Messages + in ICQ. (Thanks, Mark Doliner) + * use snprintf instead of sprintf. (Thanks, William T. Mahan) + * Fixed crashbug on empty rvous requests. (Thanks Brandon Scott + (Xeon) for pointing this out, and Matt Pandina for the patch) + * Nice Oscar changes--mostly internal. (Thanks, Mark Doliner) + + IRC: + * Added more IRC slash commands -- /W, /VERSION, /MODE, /CTCP stuff, + -- and other cool IRC enhancments. (Thanks, Jonas Birmé) + * IRC's /topic with no argument displays the current topic (Thanks, + Mark Doliner) + * DCC File Receive support for IRC. + * Optional password on IRC accounts. (Thanks, Christian Hammond) + + Jabber: + * Jabber invisibility and permanently cancel sending on- + line status to Jabber buddies. * Jabber roster updated on group renames. - * -n, --loginwin option to disable autologins. - * All new preferences dialog (best used in gtk2) - * Moved "privacy preferences" to Tools menu - * Now using libiconv for better i18n support (Thanks Junichi + * Fixed a possible segfault when signing off Jabber. (Thanks, + Craig Boston) + * Improved typing notification support for Jabber and + Yahoo! (Thanks, Nathan Walp) + * File receive support for Jabber. (Thanks, Nathan Walp) + + MSN: + * MSN users are notified when the other party closes the conversation + window. (Thanks, Christian Hammond) + * File receive support for MSN. (Thanks, Christian Hammond) + + Translations: + * French translation updated. (Thanks, Stephane Wirtel, + Sebastian Carpe, and David Odin) + * Polish translation updated. (Thanks, Przemyslaw Sulek) + * Finnish translation updated. (Thanks, Tero Kuusela) + * Spanish translation updated. (Thanks, Lars Goldschlager) + * Traditional Chinese translation updated. (Thanks, Paladin Liu) + * Japanese translation updated. (Thanks, Junichi Uekawa) + * Korean translation updated. (Thanks, A Lee) + * Romanian translation added. (Thanks, Misu Moldovan) + + Internationalization: + * Now using libiconv for better i18n support (Thanks, Junichi Uekawa) + * Lots of i18n fixes (Thanks Matt Wilson, Ethan Blanton, A Lee) + * Correct i18n handling for many parts of AIM/ICQ, including + instant messages, away messages, and profiles (Thanks, + Ethan Blanton) + * Improved MSN internationalization (Thanks, A Lee) + + Other: * Optionally uniquely colorize nicks in chats + * Add / Remove buddy menu item added to the chat users list + (Thanks, Jonas Birmé) + * View log button in conversation toolbar (Thanks, Etan Reisner) + * Option to log IMs and Chats seperately. (Thanks, Etan + Reisner) + * Removed Ctrl-C binding for color + * Fix first message in tab not displaying bug (Thanks, Etan Reisner) * Changed some default options - * Updated desktop and window icons (Thanks Robert McQueen) + * Updated desktop and window icons (Thanks, Robert McQueen) + * Switch the .desktop file to the new KDE/GNOME common vfolder + format (Thanks, Robert McQueen) * GTK2 Goodness: - - Preferences dialog - - SignOn Screen + - Account editor (rewritten by Christian Hammond) + - Preferences dialog (rewritten by Sean Egan) + - SignOn Screen (rewritten by Rob Flynn) - Conversation Window (needs tooltips) - Chat Window (sort of: needs menu bar, tooltips) - GtkIMHtml (Ari Pollak, Christian Hammond) @@ -36,77 +118,18 @@ - Alert Dialogs - GtkIMHtml tooltips Pangonated - About Dialog (Nathan Walp) - - i18n capable text input widget (Thanks Ethan Blanton, David Odin, etc) - * Notify.c plugin rewritten; check its configure dialog (Thanks, - Etan Reisner) - * TOC no longer compiles statically by default--use OSCAR - * ICQ plugin no longer gets built--use OSCAR - * Added support for gettext 0.11.x. - * Added support for automake 1.6. - * Buddy Ticker made a plugin. - * Read proxy environment variables. (Thanks, Christian Hammond) + - i18n capable text input widget (Thanks Ethan Blanton, + David Odin, etc) + * Read proxy environment variables. (Thanks, Christian Hammond) * Fixed security vulnerability with manual browser option (Thanks, Robert McQueen) - * Added more IRC slash commands -- /W, /VERSION, /MODE, /CTCP stuff, - -- and other cool IRC enhancments (Thanks, Jonas Birmé) - * Add / Remove buddy menu item added to the chat users list - (Thanks Jonas Birmé) - * Parse URL messages, Contact Sending and Pager Messages - in ICQ (Thanks Mark Doliner) - * Added GAIM::remove_event_handler and made set_info short - circuitable in perl. (Thanks Ryan McCabe) - * Improved MSN internationalization (Thanks A Lee) * Can get info for ICQ and Jabber users from the "Edit - Buddies" tab (Thanks Brian Bernas) - * Option to log IMs and Chats seperately. (Thanks Etan - Reisner) - * Nice Oscar changes--mostly internal (Thanks Mark Doliner) - * event_del_conversation for plugins (Thanks Bill Tompkins) - * Code cleanups and fixes (Thanks: Federico Mena Quintero, + Buddies" tab (Thanks, Brian Bernas) + * Code cleanups and fixes (Thanks, Federico Mena Quintero and Ka-Hing Cheung) - * aim:// URI's supported with gaim-remote command - * Quit Gaim remotely with gaim-remote (Thanks John Silvestri) - * Don't auto-login if an existing Gaim session is already - running. - * Login all auto-login accounts from login window (Thanks - Etan Reisner) - * View log button in conversation toolbar (Thanks Etan Reisner) - * Fixed a possible segfault when signing off Jabber (Thanks - Craig Boston) * Word-wrapping on mail notification text (Thanks, Andrew Molloy) - * /topic with no argument displays the current topic (Thanks Mark - Doliner) - * Lots of i18n fixes (Thanks Matt Wilson, Ethan Blanton, A Lee) - * Removed Ctrl-C binding for color - * Docklet plugin--replaces the old GNOME applet. You'll need the - Panel Notification Area applet for GNOME 2, or the kicker for - KDE 3.1. (Thanks Robert McQueen, Ari Pollak, Patrick Aussems) - * Plugins dialog and perl script menu merged into preferences. - * Auto-loading protocol plugins. - * use snprintf instead of sprintf (Thanks William T. Mahan). - * Non-direct connect typing notification for AIM over oscar - (Thanks Mark Doliner) - * Improved typing notification support for Jabber and - Yahoo! (Thanks Nathan Walp) - * Generic File Transfer PRPL interface (Thanks William T. Mahan) - * DCC File Receive support for IRC - * File receive support for Jabber (Thanks, Nathan Walp) - * File send/receive support for Oscar (Thanks, William T. Mahan) - * Option to have AIM over oscar notify you if you have - unread mail (Thanks, Mark Doliner) - * Fix first message in tab not displaying bug (Thanks Etan Reisner) - * Switch the .desktop file to the new KDE/GNOME common vfolder - format (Thanks Robert McQueen). - * Allow only people in buddy list privacy option added for AIM - * Optional password on IRC accounts (Thanks, Christian Hammond) - * Better supression of auto-responses (Thanks Joshua Blanton) - * MSN users are notified when the other party closes the conversation - window (Thanks, Christian Hammond) - * Ability to add screenname@mac.com people to AIM buddy lists - (Thanks, Graham Booker) - * Fixed crashbug on empty rvous requests, thanks Brandon Scott (Xeon) and - Matt Pandina for pointing this out (Brandon) and for the patch (Matt) - * File receive support for MSN (Thanks, Christian Hammond) + * Generic File Transfer PRPL interface (Thanks, William T. Mahan) + * Better supression of auto-responses (Thanks, Joshua Blanton) version 0.59 (06/24/2002): * Hungarian translation added (Thanks, Sutto Zoltan) diff -r 1bd663beada5 -r 1a5dcfa1823e src/protocols/oscar/aim.h --- a/src/protocols/oscar/aim.h Sat Dec 28 05:15:43 2002 +0000 +++ b/src/protocols/oscar/aim.h Sun Dec 29 17:12:05 2002 +0000 @@ -669,7 +669,7 @@ faim_export int aim_bos_setidle(aim_session_t *, aim_conn_t *, fu32_t); faim_export int aim_bos_changevisibility(aim_session_t *, aim_conn_t *, int, const char *); faim_export int aim_bos_setbuddylist(aim_session_t *, aim_conn_t *, const char *); -faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile, const char *awaymsg, fu32_t caps); +faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile_encoding, const char *profile, const int profile_len, const char *awaymsg_encoding, const char *awaymsg, const int awaymsg_len, fu32_t caps); faim_export int aim_bos_setgroupperm(aim_session_t *, aim_conn_t *, fu32_t mask); faim_export int aim_bos_setprivacyflags(aim_session_t *, aim_conn_t *, fu32_t); faim_export int aim_reqpersonalinfo(aim_session_t *, aim_conn_t *); @@ -1175,17 +1175,34 @@ int msglen; }; -struct aim_icq_simpleinfo { +struct aim_icq_info { fu32_t uin; char *nick; char *first; char *last; char *email; + char *personalwebpage; + char *info; + char *homecity; + char *homestate; + char *homeaddr; + char *homezip; + fu16_t homecountry; + char *workcity; + char *workstate; + char *workaddr; + char *workzip; + fu16_t workcountry; + char *workcompany; + char *workdivision; + char *workposition; + char *workwebpage; }; faim_export int aim_icq_reqofflinemsgs(aim_session_t *sess); faim_export int aim_icq_ackofflinemsgs(aim_session_t *sess); faim_export int aim_icq_getsimpleinfo(aim_session_t *sess, const char *uin); +faim_export int aim_icq_getallinfo(aim_session_t *sess, const char *uin); /* email.c */ struct aim_emailinfo { diff -r 1bd663beada5 -r 1a5dcfa1823e src/protocols/oscar/aim_cbtypes.h --- a/src/protocols/oscar/aim_cbtypes.h Sat Dec 28 05:15:43 2002 +0000 +++ b/src/protocols/oscar/aim_cbtypes.h Sun Dec 29 17:12:05 2002 +0000 @@ -194,6 +194,7 @@ #define AIM_CB_ICQ_OFFLINEMSG 0x00f0 #define AIM_CB_ICQ_OFFLINEMSGCOMPLETE 0x00f1 #define AIM_CB_ICQ_SIMPLEINFO 0x00f2 +#define AIM_CB_ICQ_ALLINFO 0x00f3 #define AIM_CB_ICQ_DEFAULT 0xffff /* diff -r 1bd663beada5 -r 1a5dcfa1823e src/protocols/oscar/icq.c --- a/src/protocols/oscar/icq.c Sat Dec 28 05:15:43 2002 +0000 +++ b/src/protocols/oscar/icq.c Sun Dec 29 17:12:05 2002 +0000 @@ -145,6 +145,43 @@ return 0; } +faim_export int aim_icq_getallinfo(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, 0x04b2); /* shrug. */ + aimbs_putle32(&fr->data, atoi(uin)); + + aim_tx_enqueue(sess, fr); + + return 0; +} + /* * Response to 15/2, contains an ICQ packet. */ @@ -198,40 +235,108 @@ if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE))) ret = userfunc(sess, rx); - } else if (cmd == 0x07da) { + + } else if (cmd == 0x07da) { /* information */ fu16_t subtype; + struct aim_icq_info *info; + aim_rxcallback_t userfunc; subtype = aimbs_getle16(&qbs); + info = (struct aim_icq_info *)malloc(sizeof(struct aim_icq_info)); + memset(info, 0, sizeof(struct aim_icq_info)); + aim_bstream_advance(&qbs, 1); /* 0x0a */ + + switch (subtype) { + case 0x00c8: { /* info summary (useful stuff) */ + info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + aim_bstream_advance(&qbs, aimbs_getle16(&qbs)); + info->homecity = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + info->homestate = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + aim_bstream_advance(&qbs, aimbs_getle16(&qbs)); + aim_bstream_advance(&qbs, aimbs_getle16(&qbs)); + info->homeaddr = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + aim_bstream_advance(&qbs, aimbs_getle16(&qbs)); + info->homezip = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + info->homecountry = aimbs_getle16(&qbs); + } break; + + case 0x00dc: { /* personal web page */ + aim_bstream_advance(&qbs, 3); + info->personalwebpage = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + } break; + + case 0x00eb: { /* email address(es) */ + aim_bstream_advance(&qbs, 2); /* Number of email addresses? */ + info->email = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + } break; + + case 0x00d2: { /* work information */ + info->workcity = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + info->workstate = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + aim_bstream_advance(&qbs, aimbs_getle16(&qbs)); + aim_bstream_advance(&qbs, aimbs_getle16(&qbs)); + info->workaddr = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + info->workzip = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + info->workcountry = aimbs_getle16(&qbs); + info->workcompany = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + info->workdivision = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + info->workposition = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + aim_bstream_advance(&qbs, 2); /* Number of webpage addresses? */ + info->workwebpage = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + } break; + + case 0x00e6: { /* additional personal information */ + info->info = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + } break; + + case 0x00f0: { /* personal interests */ + } break; + + case 0x00fa: { /* past background and current organizations */ + } break; + + case 0x010e: { /* unknown */ + } break; + + case 0x019a: { /* simple info */ + aim_bstream_advance(&qbs, 2); + info->uin = aimbs_getle32(&qbs); + info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + info->email = aimbs_getstr(&qbs, aimbs_getle16(&qbs)); + } break; + } /* End switch statement */ if (subtype == 0x019a) { - fu16_t tlen; - struct aim_icq_simpleinfo info; - aim_rxcallback_t userfunc; - - memset(&info, 0, sizeof(info)); - - aimbs_getle8(&qbs); /* no clue */ - aimbs_getle16(&qbs); /* no clue */ - info.uin = aimbs_getle32(&qbs); - tlen = aimbs_getle16(&qbs); - info.nick = aimbs_getstr(&qbs, tlen); - tlen = aimbs_getle16(&qbs); - info.first = aimbs_getstr(&qbs, tlen); - tlen = aimbs_getle16(&qbs); - info.last = aimbs_getstr(&qbs, tlen); - tlen = aimbs_getle16(&qbs); - info.email = aimbs_getstr(&qbs, tlen); - /* no clue what the rest of it is */ - if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_SIMPLEINFO))) - ret = userfunc(sess, rx, &info); - - free(info.nick); - free(info.first); - free(info.last); - free(info.email); + ret = userfunc(sess, rx, info); + } else { + if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_ALLINFO))) + ret = userfunc(sess, rx, info); } + free(info->nick); + free(info->first); + free(info->last); + free(info->email); + free(info->personalwebpage); + free(info->info); + free(info->homecity); + free(info->homestate); + free(info->homeaddr); + free(info->homezip); + free(info->workcity); + free(info->workstate); + free(info->workaddr); + free(info->workzip); + free(info->workcompany); + free(info->workdivision); + free(info->workposition); + free(info->workwebpage); + free(info); } aim_freetlvchain(&tl); diff -r 1bd663beada5 -r 1a5dcfa1823e src/protocols/oscar/info.c --- a/src/protocols/oscar/info.c Sat Dec 28 05:15:43 2002 +0000 +++ b/src/protocols/oscar/info.c Sun Dec 29 17:12:05 2002 +0000 @@ -29,19 +29,48 @@ * Subtype 0x0004 * * Gives BOS your profile. + * + * profile_encoding and awaymsg_encoding MUST be set if profile or + * away are set, respectively, and their value may or may not be + * restricted to a few choices. I am currently aware of: + * + * us-ascii Just that + * unicode-2-0 UCS2-BE + * + * profile_len and awaymsg_len MUST be set similarly, and they MUST + * be the length of their respective strings in bytes. + * + * To get the previous behavior of awaymsg == "" un-setting the away + * message, set awaymsg non-NULL and awaymsg_len to 0 (this is the + * obvious equivalent). * */ -faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile, const char *awaymsg, fu32_t caps) +faim_export int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, + const char *profile_encoding, const char *profile, const int profile_len, + const char *awaymsg_encoding, const char *awaymsg, const int awaymsg_len, + fu32_t caps) { - static const char defencoding[] = {"text/aolrtf; charset=\"us-ascii\""}; + static const char defencoding[] = {"text/aolrtf; charset=\"%s\""}; aim_frame_t *fr; aim_tlvlist_t *tl = NULL; aim_snacid_t snacid; + char *encoding; + + if ((profile && profile_encoding == NULL) || (awaymsg && awaymsg_len && awaymsg_encoding == NULL)) { + return -EINVAL; + } /* Build to packet first to get real length */ if (profile) { - aim_addtlvtochain_raw(&tl, 0x0001, strlen(defencoding), defencoding); - aim_addtlvtochain_raw(&tl, 0x0002, strlen(profile), profile); + /* no + 1 here because of %s */ + encoding = malloc(strlen(defencoding) + strlen(profile_encoding)); + if (encoding == NULL) { + return -ENOMEM; + } + snprintf(encoding, strlen(defencoding) + strlen(profile_encoding), defencoding, profile_encoding); + aim_addtlvtochain_raw(&tl, 0x0001, strlen(encoding), encoding); + aim_addtlvtochain_raw(&tl, 0x0002, profile_len, profile); + free(encoding); } /* @@ -53,9 +82,15 @@ * (that is, if you were away, you'll remain away). */ if (awaymsg) { - if (strlen(awaymsg)) { - aim_addtlvtochain_raw(&tl, 0x0003, strlen(defencoding), defencoding); - aim_addtlvtochain_raw(&tl, 0x0004, strlen(awaymsg), awaymsg); + if (awaymsg_len) { + encoding = malloc(strlen(defencoding) + strlen(awaymsg_encoding)); + if (encoding == NULL) { + return -ENOMEM; + } + snprintf(encoding, strlen(defencoding) + strlen(awaymsg_encoding), defencoding, awaymsg_encoding); + aim_addtlvtochain_raw(&tl, 0x0003, strlen(encoding), encoding); + aim_addtlvtochain_raw(&tl, 0x0004, awaymsg_len, awaymsg); + free(encoding); } else aim_addtlvtochain_noval(&tl, 0x0004); } @@ -712,8 +747,10 @@ { aim_userinfo_t userinfo; char *text_encoding = NULL, *text = NULL; + int textlen = 0; aim_rxcallback_t userfunc; aim_tlvlist_t *tlvlist; + aim_tlv_t *text_tlv = NULL; aim_snac_t *origsnac = NULL; struct aim_priv_inforeq *inforeq; int ret = 0; @@ -747,10 +784,10 @@ */ if (inforeq->infotype == AIM_GETINFO_GENERALINFO) { text_encoding = aim_gettlv_str(tlvlist, 0x0001, 1); - text = aim_gettlv_str(tlvlist, 0x0002, 1); + text_tlv = aim_gettlv(tlvlist, 0x0002, 1); } else if (inforeq->infotype == AIM_GETINFO_AWAYMESSAGE) { text_encoding = aim_gettlv_str(tlvlist, 0x0003, 1); - text = aim_gettlv_str(tlvlist, 0x0004, 1); + text_tlv = aim_gettlv(tlvlist, 0x0004, 1); } else if (inforeq->infotype == AIM_GETINFO_CAPABILITIES) { aim_tlv_t *ct; @@ -764,11 +801,15 @@ } } + if (text_tlv) { + text = text_tlv->value; + textlen = text_tlv->length; + } + if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx, &userinfo, inforeq->infotype, text_encoding, text); + ret = userfunc(sess, rx, &userinfo, inforeq->infotype, text_encoding, text, textlen); free(text_encoding); - free(text); aim_freetlvchain(&tlvlist); diff -r 1bd663beada5 -r 1a5dcfa1823e src/protocols/oscar/oscar.c --- a/src/protocols/oscar/oscar.c Sat Dec 28 05:15:43 2002 +0000 +++ b/src/protocols/oscar/oscar.c Sun Dec 29 17:12:05 2002 +0000 @@ -368,7 +368,8 @@ static int gaim_selfinfo (aim_session_t *, aim_frame_t *, ...); static int gaim_offlinemsg (aim_session_t *, aim_frame_t *, ...); static int gaim_offlinemsgdone (aim_session_t *, aim_frame_t *, ...); -static int gaim_simpleinfo (aim_session_t *, aim_frame_t *, ...); +static int gaim_icqsimpleinfo (aim_session_t *, aim_frame_t *, ...); +static int gaim_icqallinfo (aim_session_t *, aim_frame_t *, ...); static int gaim_popup (aim_session_t *, aim_frame_t *, ...); static int gaim_ssi_parserights (aim_session_t *, aim_frame_t *, ...); static int gaim_ssi_parselist (aim_session_t *, aim_frame_t *, ...); @@ -387,6 +388,9 @@ struct oscar_file_transfer *oft); static int oscar_sendfile_timeout(aim_session_t *sess, aim_frame_t *fr, ...); +static fu32_t check_encoding(const char *utf8); +static fu32_t parse_encoding(const char *enc); + static char *msgerrreason[] = { N_("Invalid error"), N_("Invalid SNAC"), @@ -884,7 +888,8 @@ aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG, gaim_offlinemsg, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE, gaim_offlinemsgdone, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_POP, 0x0002, gaim_popup, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_SIMPLEINFO, gaim_simpleinfo, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_SIMPLEINFO, gaim_icqsimpleinfo, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_ALLINFO, gaim_icqallinfo, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_RIGHTSINFO, gaim_ssi_parserights, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_LIST, gaim_ssi_parselist, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_NOLIST, gaim_ssi_parselist, 0); @@ -2073,7 +2078,7 @@ debug_printf("Received a channel 4 message of type %d.\n", args->type); /* Split up the message at the delimeter character, then convert each string to UTF-8 */ - msg1 = g_strsplit(args->msg, "ţ", 0); + msg1 = g_strsplit(args->msg, "\177", 0); msg2 = (gchar **)g_malloc(10*sizeof(gchar *)); /* AAA */ for (i=0; msg1[i]; i++) { strip_linefeed(msg1[i]); @@ -2156,7 +2161,7 @@ case 0x0013: { /* Someone has sent you some ICQ contacts */ int i, num; gchar **text; - text = g_strsplit(args->msg, "ţ", 0); + text = g_strsplit(args->msg, "\177", 0); if (text) { num = 0; for (i=0; isn); break; @@ -2295,8 +2300,8 @@ g_snprintf(buf, sizeof(buf), nummissed == 1 ? - _("You missed %d message from %s for unknown reasons.") : - _("You missed %d messages from %s for unknown reasons."), + _("You missed %d message from %s for an unknown reason.") : + _("You missed %d messages from %s for an unknown reason."), nummissed, userinfo->sn); break; @@ -2326,34 +2331,78 @@ return g_strdup_printf("Online"); } -static int gaim_parse_clientauto_rend(aim_session_t *sess, - const char *who, int reason, const char *cookie) { +static int gaim_parse_clientauto_ch2(aim_session_t *sess, const char *who, int reason, const char *cookie) { struct gaim_connection *gc = sess->aux_data; - struct oscar_file_transfer *oft; - char *buf; switch (reason) { - case 3: /* Decline sendfile. */ - oft = find_oft_by_cookie(gc, cookie); + case 3: { /* Decline sendfile. */ + struct oscar_file_transfer *oft = find_oft_by_cookie(gc, cookie); if (oft) { - buf = g_strdup_printf(_("%s has declined to receive a file from %s.\n"), + char *buf = g_strdup_printf(_("%s has declined to receive a file from %s.\n"), who, gc->username); transfer_abort(oft->xfer, buf); g_free(buf); oscar_file_transfer_disconnect(sess, oft->conn); } - break; - default: + } break; + + default: { debug_printf("Received an unknown rendezvous client auto-response from %s. Type 0x%04x\n", who, reason); + } } return 0; } +static int gaim_parse_clientauto_ch4(aim_session_t *sess, char *who, int reason, int state, char *msg) { + struct gaim_connection *gc = sess->aux_data; + + switch(reason) { + case 0x0003: { /* Reply from an ICQ status message request */ + char *status_msg = gaim_icq_status(state); + char *dialog_msg, **splitmsg; + struct oscar_data *od = gc->proto_data; + GSList *l = od->evilhack; + gboolean evilhack = FALSE; + + /* Split at (carriage return/newline)'s, then rejoin later with BRs between. */ + splitmsg = g_strsplit(msg, "\r\n", 0); + + /* If who is in od->evilhack, then we're just getting the away message, otherwise this + * will just get appended to the info box (which is already showing). */ + while (l) { + char *x = l->data; + if (!strcmp(x, normalize(who))) { + evilhack = TRUE; + g_free(x); + od->evilhack = g_slist_remove(od->evilhack, x); + break; + } + l = l->next; + } + + if (evilhack) + dialog_msg = g_strdup_printf(_("UIN: %s
Status: %s

%s
"), who, status_msg, g_strjoinv("
", splitmsg)); + else + dialog_msg = g_strdup_printf(_("Status: %s

%s
"), status_msg, g_strjoinv("
", splitmsg)); + g_show_info_text(gc, who, 2, dialog_msg, NULL); + + g_free(status_msg); + g_free(dialog_msg); + g_strfreev(splitmsg); + } break; + + default: { + debug_printf("Received an unknown client auto-response from %s. Type 0x%04x\n", who, reason); + } break; + } /* end of switch */ + + return 0; +} + static int gaim_parse_clientauto(aim_session_t *sess, aim_frame_t *fr, ...) { - struct gaim_connection *gc = sess->aux_data; va_list ap; fu16_t chan, reason; char *who; @@ -2365,51 +2414,16 @@ if (chan == 0x0002) { /* File transfer declined */ char *cookie = va_arg(ap, char *); - return gaim_parse_clientauto_rend(sess, who, reason, cookie); + return gaim_parse_clientauto_ch2(sess, who, reason, cookie); } else if (chan == 0x0004) { /* ICQ message */ - switch(reason) { - case 0x0003: { /* Reply from an ICQ status message request */ - int state = (int)va_arg(ap, fu32_t); - char *msg = va_arg(ap, char *); - char *status_msg = gaim_icq_status(state); - char *dialog_msg, **splitmsg; - struct oscar_data *od = gc->proto_data; - GSList *l = od->evilhack; - gboolean evilhack = FALSE; - - /* Split at (carriage return/newline)'s, then rejoin later with BRs between. */ - splitmsg = g_strsplit(msg, "\r\n", 0); - - /* If who is in od->evilhack, then we're just getting the away message, otherwise this - * will just get appended to the info box (which is already showing). */ - while (l) { - char *x = l->data; - if (!strcmp(x, normalize(who))) { - evilhack = TRUE; - g_free(x); - od->evilhack = g_slist_remove(od->evilhack, x); - break; - } - l = l->next; - } - - if (evilhack) - dialog_msg = g_strdup_printf(_("UIN: %s
Status: %s

%s
"), who, status_msg, g_strjoinv("
", splitmsg)); - else - dialog_msg = g_strdup_printf(_("Status: %s

%s
"), status_msg, g_strjoinv("
", splitmsg)); - g_show_info_text(gc, who, 2, dialog_msg, NULL); - - g_free(status_msg); - g_free(dialog_msg); - g_strfreev(splitmsg); - } break; - - default: { - debug_printf("Received an unknown client auto-response from %s. Type 0x%04x\n", who, reason); - } break; - } /* end of switch */ - - } /* end of if */ + int state = 0; + char *msg = NULL; + if (reason == 0x0003) { + state = (int)va_arg(ap, fu32_t); + msg = va_arg(ap, char *); + } + return gaim_parse_clientauto_ch4(sess, who, reason, state, msg); + } va_end(ap); @@ -2605,8 +2619,10 @@ static int gaim_parse_user_info(aim_session_t *sess, aim_frame_t *fr, ...) { aim_userinfo_t *info; - char *prof_enc = NULL, *prof = NULL; + char *text_enc = NULL, *text = NULL, *utf8 = NULL; + int text_len; fu16_t infotype; + fu32_t flags; char header[BUF_LONG]; char legend[BUF_LONG]; struct gaim_connection *gc = sess->aux_data; @@ -2619,10 +2635,25 @@ va_start(ap, fr); info = va_arg(ap, aim_userinfo_t *); infotype = (fu16_t)va_arg(ap, unsigned int); - prof_enc = va_arg(ap, char *); - prof = va_arg(ap, char *); + text_enc = va_arg(ap, char *); + text = va_arg(ap, char *); + text_len = va_arg(ap, int); va_end(ap); + if (text_len > 0) { + flags = parse_encoding (text_enc); + switch (flags) { + case 0: + utf8 = g_strdup(text); + break; + case AIM_IMFLAGS_UNICODE: + utf8 = g_convert(text, text_len, "UTF-8", "UCS-2BE", NULL, NULL, NULL); + break; + default: + debug_printf("Encountered an unknown encoding parsing userinfo\n"); + } + } + if (!od->icq) { g_snprintf(legend, sizeof legend, _("
Legend:

" @@ -2684,14 +2715,14 @@ if (evilhack) { g_show_info_text(gc, info->sn, 2, header, - (prof && *prof) ? away_subs(prof, gc->username) : - _("User has no away message"), + (utf8 && *utf8) ? away_subs(utf8, gc->username) : + _("User has no away message"), legend, NULL); } else { g_show_info_text(gc, info->sn, 0, header, - (prof && *prof) ? away_subs(prof, gc->username) : NULL, - (prof && *prof) ? "

" : NULL, + (utf8 && *utf8) ? away_subs(utf8, gc->username) : NULL, + (utf8 && *utf8) ? "

" : NULL, NULL); } } else if (infotype == AIM_GETINFO_CAPABILITIES) { @@ -2704,12 +2735,14 @@ NULL); } else { g_show_info_text(gc, info->sn, 1, - (prof && *prof) ? away_subs(prof, gc->username) : - _("No Information Provided"), + (utf8 && *utf8) ? away_subs(utf8, gc->username) : + _("No Information Provided"), legend, NULL); } + g_free(utf8); + return 1; } @@ -3123,6 +3156,9 @@ fu16_t maxsiglen; struct gaim_connection *gc = sess->aux_data; struct oscar_data *odata = (struct oscar_data *)gc->proto_data; + char *unicode; + int unicode_len; + fu32_t flags; va_start(ap, fr); maxsiglen = va_arg(ap, int); @@ -3133,9 +3169,21 @@ odata->rights.maxsiglen = odata->rights.maxawaymsglen = (guint)maxsiglen; if (odata->icq) - aim_bos_setprofile(sess, fr->conn, NULL, NULL, caps_icq); - else - aim_bos_setprofile(sess, fr->conn, gc->user->user_info, NULL, caps_aim); + aim_bos_setprofile(sess, fr->conn, NULL, NULL, 0, NULL, NULL, 0, caps_icq); + else { + flags = check_encoding (gc->user->user_info); + + if (flags == 0) { + aim_bos_setprofile(sess, fr->conn, "us-ascii", gc->user->user_info, + strlen(gc->user->user_info), NULL, NULL, 0, caps_aim); + } else { + unicode = g_convert (gc->user->user_info, strlen(gc->user->user_info), + "UCS-2BE", "UTF-8", NULL, &unicode_len, NULL); + aim_bos_setprofile(sess, fr->conn, "unicode-2-0", unicode, unicode_len, + NULL, NULL, 0, caps_aim); + g_free(unicode); + } + } return 1; } @@ -3230,29 +3278,41 @@ return 1; } -static int gaim_simpleinfo(aim_session_t *sess, aim_frame_t *fr, ...) +static int gaim_icqsimpleinfo(aim_session_t *sess, aim_frame_t *fr, ...) { struct gaim_connection *gc = sess->aux_data; struct buddy *budlight; va_list ap; - struct aim_icq_simpleinfo *info; - char buf[16 * 1024]; - char who[16]; + struct aim_icq_info *info; + gchar *buf, *tmp; + gchar who[16]; va_start(ap, fr); - info = va_arg(ap, struct aim_icq_simpleinfo *); + info = va_arg(ap, struct aim_icq_info *); va_end(ap); - g_snprintf(who, sizeof who, "%lu", info->uin); - g_snprintf(buf, sizeof buf, - "UIN: %lu
" - "Nick: %s
" - "Name: %s %s
" - "Email: %s
\n", - info->uin, - info->nick, - info->first, info->last, - info->email); + g_snprintf(who, sizeof(who), "%lu", info->uin); + buf = g_strdup_printf("UIN: %s
", who); + if (info->nick) { + tmp = buf; + buf = g_strconcat(tmp, "Nick: ", info->nick, "
\n", NULL); + g_free(tmp); + } + if (info->first) { + tmp = buf; + buf = g_strconcat(tmp, "First Name: ", info->first, "
\n", NULL); + g_free(tmp); + } + if (info->last) { + tmp = buf; + buf = g_strconcat(tmp, "Last Name: ", info->last, "
\n", NULL); + g_free(tmp); + } + if (info->email) { + tmp = buf; + buf = g_strconcat(tmp, "Email Address: ", info->email, "
\n", NULL); + g_free(tmp); + } /* If the contact is away, then we also want to get their status message * and show it in the same window as info. g_show_info_text gets the status @@ -3277,6 +3337,64 @@ } else g_show_info_text(gc, who, 2, buf, NULL); + g_free(buf); + + return 1; +} + +static int gaim_icqallinfo(aim_session_t *sess, aim_frame_t *fr, ...) +{ + struct gaim_connection *gc = sess->aux_data; + va_list ap; + struct aim_icq_info *info; + gchar *buf, *tmp; + gchar who[16]; + + va_start(ap, fr); + info = va_arg(ap, struct aim_icq_info *); + va_end(ap); + + g_snprintf(who, sizeof(who), "%lu", info->uin); + buf = g_strdup_printf("UIN: %s
", who); + if (info->nick) { + tmp = buf; + buf = g_strconcat(tmp, "Nick: ", info->nick, "
\n", NULL); + g_free(tmp); + } + if (info->first) { + tmp = buf; + buf = g_strconcat(tmp, "First Name: ", info->first, "
\n", NULL); + g_free(tmp); + } + if (info->last) { + tmp = buf; + buf = g_strconcat(tmp, "Last Name: ", info->last, "
\n", NULL); + g_free(tmp); + } + if (info->email) { + tmp = buf; + buf = g_strconcat(tmp, "Email Address: ", info->email, "
\n", NULL); + g_free(tmp); + } + if (info->personalwebpage) { + tmp = buf; + buf = g_strconcat(tmp, "Personal Webpage: ", info->personalwebpage, "
\n", NULL); + g_free(tmp); + } + if (info->info) { + tmp = buf; + buf = g_strconcat(tmp, "
Additional Information:
", info->info, "

\n", NULL); + g_free(tmp); + } + if (info->homecity && info->homestate && info->homeaddr && info->homezip) { + tmp = buf; + buf = g_strconcat(tmp, "
Home Address:
\n", info->homeaddr, "
\n", info->homecity, ", ", info->homestate, " ", info->homezip, "
\n", NULL); + g_free(tmp); + } + + g_show_info_text(gc, who, 2, buf, NULL); + g_free(buf); + return 1; } @@ -3478,7 +3596,7 @@ struct icon_req *ir = NULL; char *who = normalize(name); struct stat st; - int i, len; + int len; args.flags = AIM_IMFLAGS_ACK | AIM_IMFLAGS_CUSTOMFEATURES; if (odata->icq) @@ -3519,35 +3637,8 @@ args.destsn = name; - /* Determine how we can send this message. Per the - * warnings elsewhere in this file, these little - * checks determine the simplest encoding we can use - * for a given message send using it. */ len = strlen(message); - i = 0; - while (message[i]) { - if ((unsigned char)message[i] > 0x7f) { - /* not ASCII! */ - args.flags |= AIM_IMFLAGS_ISO_8859_1; - break; - } - i++; - } - while (message[i]) { - /* ISO-8859-1 is 0x00-0xbf in the first byte - * followed by 0xc0-0xc3 in the second */ - if ((unsigned char)message[i] < 0x80) { - i++; - continue; - } else if (((unsigned char)message[i] & 0xfc) == 0xc0 && - ((unsigned char)message[i + 1] & 0xc0) == 0x80) { - i += 2; - continue; - } - args.flags ^= AIM_IMFLAGS_ISO_8859_1; - args.flags |= AIM_IMFLAGS_UNICODE; - break; - } + args.flags |= check_encoding(message); if (args.flags & AIM_IMFLAGS_UNICODE) { debug_printf ("Sending Unicode IM\n"); args.msg = g_convert(message, len, "UCS-2BE", "UTF-8", NULL, &len, &err); @@ -3632,7 +3723,9 @@ static void oscar_set_info(struct gaim_connection *g, char *info) { struct oscar_data *odata = (struct oscar_data *)g->proto_data; - gchar *inforeal; + gchar *inforeal, *unicode; + fu32_t flags; + int unicode_len; if (odata->rights.maxsiglen == 0) do_error_dialog(_("Unable to set AIM profile."), @@ -3652,10 +3745,21 @@ inforeal = g_strndup(info, odata->rights.maxsiglen); if (odata->icq) - aim_bos_setprofile(odata->sess, odata->conn, NULL, NULL, caps_icq); - else - aim_bos_setprofile(odata->sess, odata->conn, inforeal, NULL, caps_aim); - + aim_bos_setprofile(odata->sess, odata->conn, NULL, NULL, 0, NULL, NULL, 0, caps_icq); + else { + flags = check_encoding(inforeal); + + if (flags == 0) { + aim_bos_setprofile(odata->sess, odata->conn, "us-ascii", inforeal, strlen (inforeal), + NULL, NULL, 0, caps_aim); + } else { + unicode = g_convert (inforeal, strlen(inforeal), "UCS-2BE", "UTF-8", NULL, + &unicode_len, NULL); + aim_bos_setprofile(odata->sess, odata->conn, "unicode-2-0", unicode, unicode_len, + NULL, NULL, 0, caps_aim); + g_free(unicode); + } + } g_free(inforeal); return; @@ -3663,6 +3767,9 @@ static void oscar_set_away_aim(struct gaim_connection *gc, struct oscar_data *od, const char *message) { + fu32_t flags; + char *unicode; + int unicode_len; if (od->rights.maxawaymsglen == 0) do_error_dialog(_("Unable to set AIM away message."), @@ -3675,7 +3782,7 @@ } if (!message) { - aim_bos_setprofile(od->sess, od->conn, NULL, "", caps_aim); + aim_bos_setprofile(od->sess, od->conn, NULL, NULL, 0, NULL, "", 0, caps_aim); return; } @@ -3689,7 +3796,17 @@ } gc->away = g_strndup(message, od->rights.maxawaymsglen); - aim_bos_setprofile(od->sess, od->conn, NULL, gc->away, caps_aim); + flags = check_encoding(message); + + if (flags == 0) { + aim_bos_setprofile(od->sess, od->conn, NULL, NULL, 0, "us-ascii", gc->away, strlen(gc->away), + caps_aim); + } else { + unicode = g_convert(message, strlen(message), "UCS-2BE", "UTF-8", NULL, &unicode_len, NULL); + aim_bos_setprofile(od->sess, od->conn, NULL, NULL, 0, "unicode-2-0", unicode, unicode_len, + caps_aim); + g_free(unicode); + } return; } @@ -4646,11 +4763,11 @@ break; case 5: g = gc->groups; - at = 0; + at = 0; while (g) { list = ((struct group *)g->data)->members; while (list) { - at += g_snprintf(buf + at, sizeof(buf) - at, "%s&", (char *)list->data); + at += g_snprintf(buf + at, sizeof(buf) - at, "%s&", ((struct buddy *)list->data)->name); list = list->next; } g = g->next; @@ -4840,7 +4957,61 @@ g_free(dim); } - +static fu32_t check_encoding(const char *utf8) +{ + int i = 0; + fu32_t encodingflag = 0; + + /* Determine how we can send this message. Per the + * warnings elsewhere in this file, these little + * checks determine the simplest encoding we can use + * for a given message send using it. */ + while (utf8[i]) { + if ((unsigned char)utf8[i] > 0x7f) { + /* not ASCII! */ + encodingflag = AIM_IMFLAGS_ISO_8859_1; + break; + } + i++; + } + while (utf8[i]) { + /* ISO-8859-1 is 0x00-0xbf in the first byte + * followed by 0xc0-0xc3 in the second */ + if ((unsigned char)utf8[i] < 0x80) { + i++; + continue; + } else if (((unsigned char)utf8[i] & 0xfc) == 0xc0 && + ((unsigned char)utf8[i + 1] & 0xc0) == 0x80) { + i += 2; + continue; + } + encodingflag = AIM_IMFLAGS_UNICODE; + break; + } + + return encodingflag; +} + +static fu32_t parse_encoding(const char *enc) +{ + char *charset; + + /* If anything goes wrong, fall back on ASCII and print a message */ + charset = strstr(enc, "charset="); + if (charset == NULL) { + debug_printf("No charset specified for info, assuming ASCII\n"); + return 0; + } + charset += 8; + if (!strcmp(charset, "\"us-ascii\"")) { + return 0; + } else if (!strcmp(charset, "\"unicode-2-0\"")) { + return AIM_IMFLAGS_UNICODE; + } else { + debug_printf("Unrecognized character set '%s', using ASCII\n", charset); + return 0; + } +} static struct prpl *my_protocol = NULL;