diff -Bur bitlbee-0.92/protocols/nogaim.c bitlbee-info/protocols/nogaim.c --- bitlbee-0.92/protocols/nogaim.c 2005-02-23 10:47:58.000000000 -0500 +++ bitlbee-info/protocols/nogaim.c 2005-05-15 23:07:02.000000000 -0400 @@ -283,6 +283,9 @@ msg = buf; else msg = text; + + if( g_strcasecmp( set_getstr(gc->irc, "html" ), "strip" ) == 0 ) + strip_html( msg ); irc_usermsg( gc->irc, "%s - %s", proto_name[gc->protocol], msg ); } @@ -628,6 +631,20 @@ } } +void serv_got_away( struct gaim_connection *gc, char *handle, char *away) +{ + user_t *u; + + u = user_findhandle( gc, handle ); + if(!u || !away) return; + if(u->away) + g_free(u->away); + + u->away = g_strdup(away); + if( g_strcasecmp( set_getstr( gc->irc, "html" ), "strip" ) == 0 ) + strip_html(u->away); +} + void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 flags, time_t mtime, gint len ) { irc_t *irc = gc->irc; diff -Bur bitlbee-0.92/protocols/nogaim.h bitlbee-info/protocols/nogaim.h --- bitlbee-0.92/protocols/nogaim.h 2004-10-29 19:42:07.000000000 -0400 +++ bitlbee-info/protocols/nogaim.h 2005-05-15 23:05:54.000000000 -0400 @@ -297,6 +297,7 @@ /* server.c */ G_MODULE_EXPORT void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, int evil, time_t signon, time_t idle, int type, guint caps ); +G_MODULE_EXPORT void serv_got_away( struct gaim_connection *gc, char *handle, char *away); G_MODULE_EXPORT void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 flags, time_t mtime, gint len ); G_MODULE_EXPORT void serv_got_typing( struct gaim_connection *gc, char *handle, int timeout ); G_MODULE_EXPORT void serv_got_chat_invite( struct gaim_connection *gc, char *handle, char *who, char *msg, GList *data ); diff -Bur bitlbee-0.92/protocols/oscar/info.c bitlbee-info/protocols/oscar/info.c --- bitlbee-0.92/protocols/oscar/info.c 2004-10-10 07:24:06.000000000 -0400 +++ bitlbee-info/protocols/oscar/info.c 2005-05-15 23:05:54.000000000 -0400 @@ -614,8 +614,10 @@ { aim_userinfo_t userinfo; char *text_encoding = NULL, *text = NULL; + guint16 text_length = 0; aim_rxcallback_t userfunc; aim_tlvlist_t *tlvlist; + aim_tlv_t *tlv; aim_snac_t *origsnac = NULL; struct aim_priv_inforeq *inforeq; int ret = 0; @@ -649,10 +651,18 @@ */ if (inforeq->infotype == AIM_GETINFO_GENERALINFO) { text_encoding = aim_gettlv_str(tlvlist, 0x0001, 1); - text = aim_gettlv_str(tlvlist, 0x0002, 1); + if((tlv = aim_gettlv(tlvlist, 0x0002, 1))) { + text = g_new0(char, tlv->length); + memcpy(text, tlv->value, tlv->length); + text_length = tlv->length; + } } else if (inforeq->infotype == AIM_GETINFO_AWAYMESSAGE) { text_encoding = aim_gettlv_str(tlvlist, 0x0003, 1); - text = aim_gettlv_str(tlvlist, 0x0004, 1); + if((tlv = aim_gettlv(tlvlist, 0x0004, 1))) { + text = g_new0(char, tlv->length); + memcpy(text, tlv->value, tlv->length); + text_length = tlv->length; + } } else if (inforeq->infotype == AIM_GETINFO_CAPABILITIES) { aim_tlv_t *ct; @@ -667,7 +677,7 @@ } 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, text_length); g_free(text_encoding); g_free(text); diff -Bur bitlbee-0.92/protocols/oscar/oscar.c bitlbee-info/protocols/oscar/oscar.c --- bitlbee-0.92/protocols/oscar/oscar.c 2005-02-23 17:26:59.000000000 -0500 +++ bitlbee-info/protocols/oscar/oscar.c 2005-05-24 22:33:28.000000000 -0400 @@ -82,6 +82,8 @@ gboolean icq; GSList *evilhack; + GSList *info_requests; /*Used to separate away message requests the user made from automatic ones*/ + struct { guint maxbuddies; /* max users you can watch */ guint maxwatchers; /* max users who can watch you */ @@ -215,6 +217,7 @@ static int gaim_ssi_parseack (aim_session_t *, aim_frame_t *, ...); static int gaim_icqinfo (aim_session_t *, aim_frame_t *, ...); +static int gaim_parseaiminfo (aim_session_t *, aim_frame_t *, ...); static char *msgerrreason[] = { "Invalid error", @@ -422,6 +425,11 @@ odata->create_rooms = g_slist_remove(odata->create_rooms, cr); g_free(cr); } + while(odata->info_requests) { + char * data = odata->info_requests->data; + odata->info_requests = g_slist_remove(odata->info_requests, data); + g_free(data); + } if (odata->email) g_free(odata->email); if (odata->newp) @@ -548,6 +556,7 @@ 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_SRVACK, gaim_ssi_parseack, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, gaim_parseaiminfo, 0); ((struct oscar_data *)gc->proto_data)->conn = bosconn; for (i = 0; i < (int)strlen(info->bosip); i++) { @@ -1201,6 +1210,10 @@ return 1; } +int handle_cmp_aim(const char * a, const char * b) { + return handle_cmp(a, b, PROTO_TOC); +} + static int gaim_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...) { int channel, ret = 0; aim_userinfo_t *userinfo; @@ -1357,6 +1370,10 @@ char *destn; guint16 reason; char buf[1024]; + GSList *l; + struct oscar_data *od; + + od = ((struct gaim_connection*)sess->aux_data)->proto_data; va_start(ap, fr); reason = (guint16)va_arg(ap, unsigned int); @@ -1367,6 +1384,11 @@ (reason < msgerrreasonlen) ? msgerrreason[reason] : _("Reason unknown")); do_error_dialog(sess->aux_data, buf, _("Gaim - Error")); + if((l = g_slist_find_custom(od->info_requests, destn, (GCompareFunc)handle_cmp_aim))) { + g_free(l->data); + od->info_requests = g_slist_remove(od->info_requests, l); + } + return 1; } @@ -1869,11 +1891,12 @@ struct oscar_data *odata = (struct oscar_data *)g->proto_data; if (odata->icq) aim_icq_getallinfo(odata->sess, name); - else - /* people want the away message on the top, so we get the away message - * first and then get the regular info, since it's too difficult to - * insert in the middle. i hate people. */ + else { aim_getinfo(odata->sess, odata->conn, name, AIM_GETINFO_AWAYMESSAGE); + aim_getinfo(odata->sess, odata->conn, name, AIM_GETINFO_GENERALINFO); + if(!g_slist_find_custom(odata->info_requests, name, (GCompareFunc)handle_cmp_aim)) + odata->info_requests = g_slist_append(odata->info_requests, g_strdup(name)); + } } static void oscar_get_away(struct gaim_connection *g, char *who) { @@ -1885,7 +1908,7 @@ if (budlight->caps & AIM_CAPS_ICQSERVERRELAY) aim_send_im_ch2_geticqmessage(odata->sess, who, (budlight->uc & 0xff80) >> 7); } else - aim_getinfo(odata->sess, odata->conn, who, AIM_GETINFO_GENERALINFO); + aim_getinfo(odata->sess, odata->conn, who, AIM_GETINFO_AWAYMESSAGE); } static void oscar_set_away_aim(struct gaim_connection *gc, struct oscar_data *od, const char *message) @@ -2286,6 +2309,125 @@ } +static char *oscar_encoding_extract(const char *encoding) +{ + char *ret = NULL; + char *begin, *end; + + g_return_val_if_fail(encoding != NULL, NULL); + + /* Make sure encoding begins with charset= */ + if (strncmp(encoding, "text/plain; charset=", 20) && + strncmp(encoding, "text/aolrtf; charset=", 21) && + strncmp(encoding, "text/x-aolrtf; charset=", 23)) + { + return NULL; + } + + begin = strchr(encoding, '"'); + end = strrchr(encoding, '"'); + + if ((begin == NULL) || (end == NULL) || (begin >= end)) + return NULL; + + ret = g_strndup(begin+1, (end-1) - begin); + + return ret; +} + +static char *oscar_encoding_to_utf8(char *encoding, char *text, int textlen) +{ + char *utf8 = g_new0(char, 8192); + + if ((encoding == NULL) || encoding[0] == '\0') { + /* gaim_debug_info("oscar", "Empty encoding, assuming UTF-8\n");*/ + } else if (!g_strcasecmp(encoding, "iso-8859-1")) { + do_iconv("iso-8859-1", "UTF-8", text, utf8, textlen, 8192); + } else if (!g_strcasecmp(encoding, "ISO-8859-1-Windows-3.1-Latin-1")) { + do_iconv("Windows-1252", "UTF-8", text, utf8, textlen, 8192); + } else if (!g_strcasecmp(encoding, "unicode-2-0")) { + do_iconv("UCS-2BE", "UTF-8", text, utf8, textlen, 8192); + } else if (g_strcasecmp(encoding, "us-ascii") && strcmp(encoding, "utf-8")) { + /* gaim_debug_warning("oscar", "Unrecognized character encoding \"%s\", " + "attempting to convert to UTF-8 anyway\n", encoding);*/ + do_iconv(encoding, "UTF-8", text, utf8, textlen, 8192); + } + + /* + * If utf8 is still NULL then either the encoding is us-ascii/utf-8 or + * we have been unable to convert the text to utf-8 from the encoding + * that was specified. So we check if the text is valid utf-8 then + * just copy it. + */ + if (*utf8 == 0) { + if (textlen != 0 && *text != '\0' + && !g_utf8_validate(text, textlen, NULL)) + strcpy(utf8, _("(There was an error receiving this message. The buddy you are speaking to most likely has a buggy client.)")); + else + strncpy(utf8, text, textlen); + } + + return utf8; +} + +static int gaim_parseaiminfo(aim_session_t *sess, aim_frame_t *fr, ...) +{ + struct gaim_connection *gc = sess->aux_data; + struct oscar_data *od = gc->proto_data; + va_list ap; + aim_userinfo_t *userinfo; + guint16 infotype; + char *text_encoding = NULL, *text = NULL, *extracted_encoding = NULL; + guint16 text_length; + char *utf8 = NULL; + GSList *l; + + va_start(ap, fr); + userinfo = va_arg(ap, aim_userinfo_t *); + infotype = va_arg(ap, int); + text_encoding = va_arg(ap, char*); + text = va_arg(ap, char*); + text_length = va_arg(ap, int); + va_end(ap); + + if(text_encoding) + extracted_encoding = oscar_encoding_extract(text_encoding); + if(infotype == AIM_GETINFO_GENERALINFO) { + /*Display idle time*/ + char buff[256]; + struct tm idletime; + if(userinfo->idletime) { + memset(&idletime, 0, sizeof(struct tm)); + idletime.tm_mday = (userinfo->idletime / 60) / 24; + idletime.tm_hour = (userinfo->idletime / 60) % 24; + idletime.tm_min = userinfo->idletime % 60; + idletime.tm_sec = 0; + strftime(buff, 256, _("%d days %H hours %M minutes"), &idletime); + serv_got_crap(gc, "%s: %s", _("Idle Time"), buff); + } + + if(text) { + utf8 = oscar_encoding_to_utf8(extracted_encoding, text, text_length); + serv_got_crap(gc, "%s\n%s", _("User Info"), utf8); + } else { + serv_got_crap(gc, _("No user info available.")); + } + } else if(infotype == AIM_GETINFO_AWAYMESSAGE && userinfo->flags & AIM_FLAG_AWAY) { + utf8 = oscar_encoding_to_utf8(extracted_encoding, text, text_length); + if((l = g_slist_find_custom(od->info_requests, userinfo->sn, (GCompareFunc)handle_cmp_aim))) { + /*If the user requested info, display it, otherwise just pass it on*/ + g_free(l->data); + od->info_requests = g_slist_remove(od->info_requests, l); + serv_got_crap(gc, "%s\n%s", _("Away Message"), utf8); + } + serv_got_away(gc, userinfo->sn, utf8); + } + + g_free(utf8); + + return 1; +} + static char *oscar_get_status_string( struct gaim_connection *gc, int number ) { struct oscar_data *od = gc->proto_data; diff -Bur bitlbee-0.92/protocols/util.c bitlbee-info/protocols/util.c --- bitlbee-0.92/protocols/util.c 2004-10-10 07:24:06.000000000 -0400 +++ bitlbee-info/protocols/util.c 2005-05-15 23:05:54.000000000 -0400 @@ -325,6 +325,8 @@ if( *in ) { + if( g_strncasecmp( cs+1, "br", 2) == 0 ) + *(s++) = '\n'; in ++; } else