# HG changeset patch # User andrew.victor@mxit.com # Date 1282293327 0 # Node ID 581a070c37371d2dde5b080c91275de1ded9066b # Parent 69760676c50cf2c97f5284fc3962dd00cc3b831f# Parent 9789e8e7d83411b3051400eec415452d73444db7 propagate from branch 'im.pidgin.pidgin' (head 47179f04bde4a1cd3857fd05eb4e40f25ee9e26f) to branch 'im.pidgin.pidgin.mxit' (head 2b62fc7e560dfcd0decc64eff067becbb581c423) diff -r 69760676c50c -r 581a070c3737 finch/libgnt/gntentry.c --- a/finch/libgnt/gntentry.c Fri Aug 20 08:34:12 2010 +0000 +++ b/finch/libgnt/gntentry.c Fri Aug 20 08:35:27 2010 +0000 @@ -480,7 +480,7 @@ { GntEntry *entry = GNT_ENTRY(bind); GList *iter; - const char *current , *pos; + const char *current; int len; if (entry->history->prev && entry->search->needle) @@ -497,7 +497,7 @@ const char *str = iter->data; /* A more utf8-friendly version of strstr would have been better, but * for now, this will have to do. */ - if ((pos = strstr(str, current))) + if (strstr(str, current) != NULL) break; } diff -r 69760676c50c -r 581a070c3737 finch/libgnt/gnttextview.c --- a/finch/libgnt/gnttextview.c Fri Aug 20 08:34:12 2010 +0000 +++ b/finch/libgnt/gnttextview.c Fri Aug 20 08:35:27 2010 +0000 @@ -711,7 +711,7 @@ int gnt_text_view_get_lines_above(GntTextView *view) { int above = 0; - GList *list = view->list; + GList *list; list = g_list_nth(view->list, GNT_WIDGET(view)->priv.height); if (!list) return 0; diff -r 69760676c50c -r 581a070c3737 libpurple/log.c --- a/libpurple/log.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/log.c Fri Aug 20 08:35:27 2010 +0000 @@ -1681,7 +1681,6 @@ struct tm tm; char month[4]; struct old_logger_data *data = NULL; - char *newlog; int logfound = 0; int lastoff = 0; int newlen; @@ -1783,7 +1782,7 @@ } while (fgets(buf, BUF_LONG, file)) { - if ((newlog = strstr(buf, "---- New C"))) { + if (strstr(buf, "---- New C") != NULL) { int length; int offset; char convostart[32]; diff -r 69760676c50c -r 581a070c3737 libpurple/media/backend-fs2.c --- a/libpurple/media/backend-fs2.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/media/backend-fs2.c Fri Aug 20 08:35:27 2010 +0000 @@ -1791,7 +1791,7 @@ const gchar *sess_id) { PurpleMediaBackendFs2Private *priv; - gboolean ret; + gboolean ret = FALSE; g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), FALSE); diff -r 69760676c50c -r 581a070c3737 libpurple/plugins/tcl/tcl_cmd.c --- a/libpurple/plugins/tcl/tcl_cmd.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/plugins/tcl/tcl_cmd.c Fri Aug 20 08:35:27 2010 +0000 @@ -125,7 +125,7 @@ gchar **args, gchar **errors, struct tcl_cmd_handler *handler) { - int retval, error, i; + int retval, i; Tcl_Obj *command, *arg, *tclargs, *result; command = Tcl_NewListObj(0, NULL); @@ -153,8 +153,7 @@ } Tcl_ListObjAppendElement(handler->interp, command, tclargs); - if ((error = Tcl_EvalObjEx(handler->interp, command, - TCL_EVAL_GLOBAL)) != TCL_OK) { + if (Tcl_EvalObjEx(handler->interp, command, TCL_EVAL_GLOBAL) != TCL_OK) { gchar *errorstr; errorstr = g_strdup_printf("error evaluating callback: %s\n", @@ -164,8 +163,8 @@ retval = PURPLE_CMD_RET_FAILED; } else { result = Tcl_GetObjResult(handler->interp); - if ((error = Tcl_GetIntFromObj(handler->interp, result, - &retval)) != TCL_OK) { + if (Tcl_GetIntFromObj(handler->interp, result, + &retval) != TCL_OK) { gchar *errorstr; errorstr = g_strdup_printf("Error retreiving procedure result: %s\n", diff -r 69760676c50c -r 581a070c3737 libpurple/plugins/tcl/tcl_signals.c --- a/libpurple/plugins/tcl/tcl_signals.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/plugins/tcl/tcl_signals.c Fri Aug 20 08:35:27 2010 +0000 @@ -160,7 +160,7 @@ { GString *name, *val; PurpleBlistNode *node; - int error, i; + int i; void *retval = NULL; Tcl_Obj *cmd, *arg, *result; void **vals; /* Used for inout parameters */ @@ -335,7 +335,7 @@ } /* Call the friggin' procedure already */ - if ((error = Tcl_EvalObjEx(handler->interp, cmd, TCL_EVAL_GLOBAL)) != TCL_OK) { + if (Tcl_EvalObjEx(handler->interp, cmd, TCL_EVAL_GLOBAL) != TCL_OK) { purple_debug(PURPLE_DEBUG_ERROR, "tcl", "error evaluating callback: %s\n", Tcl_GetString(Tcl_GetObjResult(handler->interp))); } else { @@ -345,7 +345,7 @@ if (purple_value_get_type(handler->returntype) == PURPLE_TYPE_STRING) { retval = (void *)g_strdup(Tcl_GetString(result)); } else { - if ((error = Tcl_GetIntFromObj(handler->interp, result, (int *)&retval)) != TCL_OK) { + if (Tcl_GetIntFromObj(handler->interp, result, (int *)&retval) != TCL_OK) { purple_debug(PURPLE_DEBUG_ERROR, "tcl", "Error retrieving procedure result: %s\n", Tcl_GetString(Tcl_GetObjResult(handler->interp))); retval = NULL; diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/bonjour/jabber.c --- a/libpurple/protocols/bonjour/jabber.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/bonjour/jabber.c Fri Aug 20 08:35:27 2010 +0000 @@ -1273,7 +1273,6 @@ static void xep_iq_parse(xmlnode *packet, PurpleBuddy *pb) { - xmlnode *child; PurpleAccount *account; PurpleConnection *gc; @@ -1283,7 +1282,7 @@ account = purple_buddy_get_account(pb); gc = purple_account_get_connection(account); - if ((child = xmlnode_get_child(packet, "si")) || (child = xmlnode_get_child(packet, "error"))) + if (xmlnode_get_child(packet, "si") != NULL || xmlnode_get_child(packet, "error") != NULL) xep_si_parse(gc, packet, pb); else xep_bytestreams_parse(gc, packet, pb); diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/bonjour/mdns_avahi.c --- a/libpurple/protocols/bonjour/mdns_avahi.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/bonjour/mdns_avahi.c Fri Aug 20 08:35:27 2010 +0000 @@ -115,7 +115,6 @@ AvahiStringList *l; size_t size; char *key, *value; - int ret; char ip[AVAHI_ADDRESS_STR_MAX]; AvahiBuddyImplData *b_impl; AvahiSvcResolverData *rd; @@ -202,7 +201,7 @@ /* Obtain the parameters from the text_record */ clear_bonjour_buddy_values(bb); for(l = txt; l != NULL; l = l->next) { - if ((ret = avahi_string_list_get_pair(l, &key, &value, &size)) < 0) + if (avahi_string_list_get_pair(l, &key, &value, &size) < 0) continue; set_bonjour_buddy_value(bb, key, value, size); /* TODO: Since we're using the glib allocator, I think we diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/jabber/auth_cyrus.c --- a/libpurple/protocols/jabber/auth_cyrus.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/jabber/auth_cyrus.c Fri Aug 20 08:35:27 2010 +0000 @@ -103,6 +103,7 @@ return SASL_BADPARAM; len = strlen(pw); + /* Not an off-by-one because sasl_secret_t defines char data[1] */ x = (sasl_secret_t *) realloc(x, sizeof(sasl_secret_t) + len); if (!x) diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/jabber/bosh.c --- a/libpurple/protocols/jabber/bosh.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/jabber/bosh.c Fri Aug 20 08:35:27 2010 +0000 @@ -711,11 +711,10 @@ /* Make sure Content-Length is in headers, not body */ if (content_length && (!end_of_headers || content_length < end_of_headers)) { const char *sep; - const char *eol; int len; if ((sep = strstr(content_length, ": ")) == NULL || - (eol = strstr(sep, "\r\n")) == NULL) + strstr(sep, "\r\n") == NULL) /* * The packet ends in the middle of the Content-Length line. * We'll try again later when we have more. diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/jabber/disco.c --- a/libpurple/protocols/jabber/disco.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/jabber/disco.c Fri Aug 20 08:35:27 2010 +0000 @@ -604,7 +604,7 @@ /* we don't actually care about the specific nodes, * so we won't query them */ - if((node = xmlnode_get_attrib(child, "node"))) + if(xmlnode_get_attrib(child, "node") != NULL) continue; iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_DISCO_INFO); diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/jabber/jabber.c --- a/libpurple/protocols/jabber/jabber.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/jabber/jabber.c Fri Aug 20 08:35:27 2010 +0000 @@ -205,7 +205,7 @@ * resource string from being unreasonably long on systems which stuff the * whole FQDN in the hostname */ if((dot = strchr(hostname, '.'))) - dot = '\0'; + *dot = '\0'; return purple_strreplace(input, "__HOSTNAME__", hostname); } @@ -3493,7 +3493,7 @@ if (js->pep) { /* if no argument was given, unset mood */ - if (!args | !args[0]) { + if (!args || !args[0]) { jabber_mood_set(js, NULL, NULL); } else if (!args[1]) { jabber_mood_set(js, args[0], NULL); diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/jabber/message.c --- a/libpurple/protocols/jabber/message.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/jabber/message.c Fri Aug 20 08:35:27 2010 +0000 @@ -296,7 +296,6 @@ } static void handle_buzz(JabberMessage *jm) { - PurpleBuddy *buddy; PurpleAccount *account; /* Delayed buzz MUST NOT be accepted */ @@ -309,7 +308,7 @@ account = purple_connection_get_account(jm->js->gc); - if ((buddy = purple_find_buddy(account, jm->from)) == NULL) + if (purple_find_buddy(account, jm->from) == NULL) return; /* Do not accept buzzes from unknown people */ /* xmpp only has 1 attention type, so index is 0 */ diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/jabber/si.c --- a/libpurple/protocols/jabber/si.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/jabber/si.c Fri Aug 20 08:35:27 2010 +0000 @@ -1734,7 +1734,7 @@ /* if they've already sent us this file transfer with the same damn id * then we're gonna ignore it, until I think of something better to do * with it */ - if((xfer = jabber_si_xfer_find(js, stream_id, from))) + if(jabber_si_xfer_find(js, stream_id, from) != NULL) return; jsx = g_new0(JabberSIXfer, 1); diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/msn/contact.c --- a/libpurple/protocols/msn/contact.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/msn/contact.c Fri Aug 20 08:35:27 2010 +0000 @@ -536,7 +536,7 @@ abLastChange = purple_account_get_string(session->account, "ablastChange", NULL); dynamicItemLastChange = purple_account_get_string(session->account, - "dynamicItemLastChange", NULL); + "DynamicItemLastChanged", NULL); if (state->partner_scenario == MSN_PS_INITIAL) { #ifdef MSN_PARTIAL_LISTS @@ -684,20 +684,20 @@ xmlnode *annotation; MsnUser *user; + g_free(passport); + g_free(Name); + g_free(uid); + g_free(type); + g_free(mobile_number); + g_free(alias); + passport = Name = uid = type = mobile_number = alias = NULL; + mobile = FALSE; + if (!(contactId = xmlnode_get_child(contactNode,"contactId")) || !(contactInfo = xmlnode_get_child(contactNode, "contactInfo")) || !(contactType = xmlnode_get_child(contactInfo, "contactType"))) continue; - g_free(passport); - g_free(Name); - g_free(alias); - g_free(uid); - g_free(type); - g_free(mobile_number); - passport = Name = uid = type = mobile_number = alias = NULL; - mobile = FALSE; - uid = xmlnode_get_data(contactId); type = xmlnode_get_data(contactType); @@ -836,6 +836,7 @@ g_free(uid); g_free(type); g_free(mobile_number); + g_free(alias); } static gboolean @@ -885,7 +886,7 @@ msn_parse_addressbook_groups(session, groups); } - /*add a default No group to set up the no group Membership*/ + /* Add an "Other Contacts" group for buddies who aren't in a group */ msn_group_new(session->userlist, MSN_INDIVIDUALS_GROUP_ID, MSN_INDIVIDUALS_GROUP_NAME); purple_debug_misc("msn", "AB group_id:%s name:%s\n", @@ -895,7 +896,7 @@ purple_blist_add_group(g, NULL); } - /*add a default No group to set up the no group Membership*/ + /* Add a "Non-IM Contacts" group */ msn_group_new(session->userlist, MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME); purple_debug_misc("msn", "AB group_id:%s name:%s\n", MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME); if ((purple_find_group(MSN_NON_IM_GROUP_NAME)) == NULL) { diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/Makefile.am --- a/libpurple/protocols/oscar/Makefile.am Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/Makefile.am Fri Aug 20 08:35:27 2010 +0000 @@ -6,10 +6,11 @@ pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION) OSCARSOURCES = \ + authorization.c \ bstream.c \ clientlogin.c \ + encoding.c \ family_admin.c \ - family_advert.c \ family_alert.c \ family_auth.c \ family_bart.c \ @@ -19,14 +20,11 @@ family_chatnav.c \ family_icq.c \ family_icbm.c \ - family_invite.c \ family_locate.c \ - family_odir.c \ family_oservice.c \ family_popup.c \ family_feedbag.c \ family_stats.c \ - family_translate.c \ family_userlookup.c \ flap_connection.c \ misc.c \ @@ -44,7 +42,9 @@ snac.c \ snactypes.h \ tlv.c \ - util.c + userinfo.c \ + util.c \ + visibility.c AM_CFLAGS = $(st) diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/Makefile.mingw --- a/libpurple/protocols/oscar/Makefile.mingw Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/Makefile.mingw Fri Aug 20 08:35:27 2010 +0000 @@ -41,10 +41,11 @@ ## SOURCES, OBJECTS ## C_SRC = \ + authorization.c \ bstream.c \ clientlogin.c \ + encoding.c \ family_admin.c \ - family_advert.c \ family_alert.c \ family_auth.c \ family_bart.c \ @@ -52,16 +53,13 @@ family_buddy.c \ family_chat.c \ family_chatnav.c \ - family_icq.c \ + family_feedbag.c \ family_icbm.c \ - family_invite.c \ + family_icq.c \ family_locate.c \ - family_odir.c \ + family_oservice.c \ family_popup.c \ - family_oservice.c \ - family_feedbag.c \ family_stats.c \ - family_translate.c \ family_userlookup.c \ flap_connection.c \ misc.c \ @@ -75,7 +73,9 @@ rxhandlers.c \ snac.c \ tlv.c \ - util.c + userinfo.c \ + util.c \ + visibility.c OBJECTS = $(C_SRC:%.c=%.o) diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/authorization.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/oscar/authorization.c Fri Aug 20 08:35:27 2010 +0000 @@ -0,0 +1,153 @@ +/* + * Purple's oscar protocol plugin + * This file is the legal property of its developers. + * Please see the AUTHORS file distributed alongside this file. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA +*/ + +/* + * Everything related to OSCAR authorization requests. + */ + +#include "oscar.h" +#include "request.h" + +static void +oscar_auth_request(struct name_data *data, char *msg) +{ + PurpleConnection *gc; + OscarData *od; + PurpleAccount *account; + PurpleBuddy *buddy; + PurpleGroup *group; + const char *bname, *gname; + + gc = data->gc; + od = purple_connection_get_protocol_data(gc); + account = purple_connection_get_account(gc); + buddy = purple_find_buddy(account, data->name); + if (buddy != NULL) + group = purple_buddy_get_group(buddy); + else + group = NULL; + + if (group != NULL) + { + bname = purple_buddy_get_name(buddy); + gname = purple_group_get_name(group); + purple_debug_info("oscar", "ssi: adding buddy %s to group %s\n", + bname, gname); + aim_ssi_sendauthrequest(od, data->name, msg ? msg : _("Please authorize me so I can add you to my buddy list.")); + if (!aim_ssi_itemlist_finditem(od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY)) + { + aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, TRUE); + + /* Mobile users should always be online */ + if (bname[0] == '+') { + purple_prpl_got_user_status(account, + purple_buddy_get_name(buddy), + OSCAR_STATUS_ID_AVAILABLE, NULL); + purple_prpl_got_user_status(account, + purple_buddy_get_name(buddy), + OSCAR_STATUS_ID_MOBILE, NULL); + } + } + } + + oscar_free_name_data(data); +} + +static void +oscar_auth_grant(gpointer cbdata) +{ + struct name_data *data = cbdata; + PurpleConnection *gc = data->gc; + OscarData *od = purple_connection_get_protocol_data(gc); + + aim_ssi_sendauthreply(od, data->name, 0x01, NULL); + + oscar_free_name_data(data); +} + +static void +oscar_auth_dontgrant(struct name_data *data, char *msg) +{ + PurpleConnection *gc = data->gc; + OscarData *od = purple_connection_get_protocol_data(gc); + + aim_ssi_sendauthreply(od, data->name, 0x00, msg ? msg : _("No reason given.")); + + oscar_free_name_data(data); +} + +static void +oscar_auth_dontgrant_msgprompt(gpointer cbdata) +{ + struct name_data *data = cbdata; + purple_request_input(data->gc, NULL, _("Authorization Denied Message:"), + NULL, _("No reason given."), TRUE, FALSE, NULL, + _("_OK"), G_CALLBACK(oscar_auth_dontgrant), + _("_Cancel"), G_CALLBACK(oscar_free_name_data), + purple_connection_get_account(data->gc), data->name, NULL, + data); +} + +/* When you ask other people for authorization */ +void +oscar_auth_sendrequest(PurpleConnection *gc, const char *name) +{ + struct name_data *data; + + data = g_new0(struct name_data, 1); + data->gc = gc; + data->name = g_strdup(name); + + purple_request_input(data->gc, NULL, _("Authorization Request Message:"), + NULL, _("Please authorize me!"), TRUE, FALSE, NULL, + _("_OK"), G_CALLBACK(oscar_auth_request), + _("_Cancel"), G_CALLBACK(oscar_free_name_data), + purple_connection_get_account(gc), name, NULL, + data); +} + +void +oscar_auth_sendrequest_menu(PurpleBlistNode *node, gpointer ignored) +{ + PurpleBuddy *buddy; + PurpleConnection *gc; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); + + buddy = (PurpleBuddy *) node; + gc = purple_account_get_connection(purple_buddy_get_account(buddy)); + oscar_auth_sendrequest(gc, purple_buddy_get_name(buddy)); +} + +/* When other people ask you for authorization */ +void +oscar_auth_recvrequest(PurpleConnection *gc, gchar *name, gchar *nick, gchar *reason) +{ + PurpleAccount* account = purple_connection_get_account(gc); + struct name_data *data = g_new(struct name_data, 1); + + data->gc = gc; + data->name = name; + data->nick = nick; + + purple_account_request_authorization(account, data->name, NULL, data->nick, + reason, purple_find_buddy(account, data->name) != NULL, + oscar_auth_grant, oscar_auth_dontgrant_msgprompt, data); +} \ No newline at end of file diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/bstream.c --- a/libpurple/protocols/oscar/bstream.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/bstream.c Fri Aug 20 08:35:27 2010 +0000 @@ -24,7 +24,7 @@ #include "oscar.h" -int byte_stream_new(ByteStream *bs, guint32 len) +int byte_stream_new(ByteStream *bs, size_t len) { if (bs == NULL) return -1; @@ -32,9 +32,8 @@ return byte_stream_init(bs, g_malloc(len), len); } -int byte_stream_init(ByteStream *bs, guint8 *data, int len) +int byte_stream_init(ByteStream *bs, guint8 *data, size_t len) { - if (bs == NULL) return -1; @@ -50,7 +49,7 @@ g_free(bs->data); } -int byte_stream_empty(ByteStream *bs) +int byte_stream_bytes_left(ByteStream *bs) { return bs->len - bs->offset; } @@ -60,229 +59,172 @@ return bs->offset; } -int byte_stream_setpos(ByteStream *bs, unsigned int off) +int byte_stream_setpos(ByteStream *bs, size_t off) { - - if (off > bs->len) - return -1; + g_return_val_if_fail(off <= bs->len, -1); bs->offset = off; - return off; } void byte_stream_rewind(ByteStream *bs) { - byte_stream_setpos(bs, 0); - - return; } /* * N can be negative, which can be used for going backwards - * in a bstream. I'm not sure if libfaim actually does - * this anywhere... + * in a bstream. */ int byte_stream_advance(ByteStream *bs, int n) { - - if ((byte_stream_curpos(bs) + n < 0) || (byte_stream_empty(bs) < n)) - return 0; /* XXX throw an exception */ + g_return_val_if_fail(byte_stream_curpos(bs) + n >= 0, 0); + g_return_val_if_fail(n <= byte_stream_bytes_left(bs), 0); bs->offset += n; - return n; } guint8 byte_stream_get8(ByteStream *bs) { - - if (byte_stream_empty(bs) < 1) - return 0; /* XXX throw an exception */ + g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0); bs->offset++; - return aimutil_get8(bs->data + bs->offset - 1); } guint16 byte_stream_get16(ByteStream *bs) { - - if (byte_stream_empty(bs) < 2) - return 0; /* XXX throw an exception */ + g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0); bs->offset += 2; - return aimutil_get16(bs->data + bs->offset - 2); } guint32 byte_stream_get32(ByteStream *bs) { - - if (byte_stream_empty(bs) < 4) - return 0; /* XXX throw an exception */ + g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0); bs->offset += 4; - return aimutil_get32(bs->data + bs->offset - 4); } guint8 byte_stream_getle8(ByteStream *bs) { - - if (byte_stream_empty(bs) < 1) - return 0; /* XXX throw an exception */ + g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0); bs->offset++; - return aimutil_getle8(bs->data + bs->offset - 1); } guint16 byte_stream_getle16(ByteStream *bs) { - - if (byte_stream_empty(bs) < 2) - return 0; /* XXX throw an exception */ + g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0); bs->offset += 2; - return aimutil_getle16(bs->data + bs->offset - 2); } guint32 byte_stream_getle32(ByteStream *bs) { - - if (byte_stream_empty(bs) < 4) - return 0; /* XXX throw an exception */ + g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0); bs->offset += 4; - return aimutil_getle32(bs->data + bs->offset - 4); } -static void byte_stream_getrawbuf_nocheck(ByteStream *bs, guint8 *buf, int len) +static void byte_stream_getrawbuf_nocheck(ByteStream *bs, guint8 *buf, size_t len) { memcpy(buf, bs->data + bs->offset, len); bs->offset += len; } -int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, int len) +int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, size_t len) { - - if (byte_stream_empty(bs) < len) - return 0; + g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, 0); byte_stream_getrawbuf_nocheck(bs, buf, len); return len; } -guint8 *byte_stream_getraw(ByteStream *bs, int len) +guint8 *byte_stream_getraw(ByteStream *bs, size_t len) { guint8 *ob; - if (byte_stream_empty(bs) < len) - return NULL; + g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, NULL); ob = g_malloc(len); - byte_stream_getrawbuf_nocheck(bs, ob, len); - return ob; } -char *byte_stream_getstr(ByteStream *bs, int len) +char *byte_stream_getstr(ByteStream *bs, size_t len) { char *ob; - if (byte_stream_empty(bs) < len) - return NULL; + g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, NULL); ob = g_malloc(len + 1); - byte_stream_getrawbuf_nocheck(bs, (guint8 *)ob, len); - ob[len] = '\0'; - return ob; } int byte_stream_put8(ByteStream *bs, guint8 v) { - - if (byte_stream_empty(bs) < 1) - return 0; /* XXX throw an exception */ + g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0); bs->offset += aimutil_put8(bs->data + bs->offset, v); - return 1; } int byte_stream_put16(ByteStream *bs, guint16 v) { - - if (byte_stream_empty(bs) < 2) - return 0; /* XXX throw an exception */ + g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0); bs->offset += aimutil_put16(bs->data + bs->offset, v); - return 2; } int byte_stream_put32(ByteStream *bs, guint32 v) { - - if (byte_stream_empty(bs) < 4) - return 0; /* XXX throw an exception */ + g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0); bs->offset += aimutil_put32(bs->data + bs->offset, v); - return 1; } int byte_stream_putle8(ByteStream *bs, guint8 v) { - - if (byte_stream_empty(bs) < 1) - return 0; /* XXX throw an exception */ + g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0); bs->offset += aimutil_putle8(bs->data + bs->offset, v); - return 1; } int byte_stream_putle16(ByteStream *bs, guint16 v) { - - if (byte_stream_empty(bs) < 2) - return 0; /* XXX throw an exception */ + g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0); bs->offset += aimutil_putle16(bs->data + bs->offset, v); - return 2; } int byte_stream_putle32(ByteStream *bs, guint32 v) { - - if (byte_stream_empty(bs) < 4) - return 0; /* XXX throw an exception */ + g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0); bs->offset += aimutil_putle32(bs->data + bs->offset, v); - return 1; } -int byte_stream_putraw(ByteStream *bs, const guint8 *v, int len) +int byte_stream_putraw(ByteStream *bs, const guint8 *v, size_t len) { - - if (byte_stream_empty(bs) < len) - return 0; /* XXX throw an exception */ + g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, 0); memcpy(bs->data + bs->offset, v, len); bs->offset += len; - return len; } @@ -291,19 +233,14 @@ return byte_stream_putraw(bs, (guint8 *)str, strlen(str)); } -int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, int len) +int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, size_t len) { - - if (byte_stream_empty(srcbs) < len) - return 0; /* XXX throw exception (underrun) */ - - if (byte_stream_empty(bs) < len) - return 0; /* XXX throw exception (overflow) */ + g_return_val_if_fail(byte_stream_bytes_left(srcbs) >= len, 0); + g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, 0); memcpy(bs->data + bs->offset, srcbs->data + srcbs->offset, len); bs->offset += len; srcbs->offset += len; - return len; } diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/encoding.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/oscar/encoding.c Fri Aug 20 08:35:27 2010 +0000 @@ -0,0 +1,235 @@ +/* + * Purple's oscar protocol plugin + * This file is the legal property of its developers. + * Please see the AUTHORS file distributed alongside this file. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA +*/ + +#include "encoding.h" + +static gchar * +encoding_extract(const char *encoding) +{ + char *begin, *end; + + if (encoding == NULL) { + return NULL; + } + + if (!g_str_has_prefix(encoding, "text/aolrtf; charset=") && + !g_str_has_prefix(encoding, "text/x-aolrtf; charset=") && + !g_str_has_prefix(encoding, "text/plain; charset=")) { + return g_strdup(encoding); + } + + begin = strchr(encoding, '"'); + end = strrchr(encoding, '"'); + + if ((begin == NULL) || (end == NULL) || (begin >= end)) { + return g_strdup(encoding); + } + + return g_strndup(begin+1, (end-1) - begin); +} + +gchar * +oscar_encoding_to_utf8(const char *encoding, const char *text, int textlen) +{ + gchar *utf8 = NULL; + const gchar *glib_encoding = NULL; + gchar *extracted_encoding = encoding_extract(encoding); + + if (extracted_encoding == NULL || *extracted_encoding == '\0') { + purple_debug_info("oscar", "Empty encoding, assuming UTF-8\n"); + } else if (!g_ascii_strcasecmp(extracted_encoding, "iso-8859-1")) { + glib_encoding = "iso-8859-1"; + } else if (!g_ascii_strcasecmp(extracted_encoding, "ISO-8859-1-Windows-3.1-Latin-1") || !g_ascii_strcasecmp(extracted_encoding, "us-ascii")) { + glib_encoding = "Windows-1252"; + } else if (!g_ascii_strcasecmp(extracted_encoding, "unicode-2-0")) { + glib_encoding = "UTF-16BE"; + } else if (g_ascii_strcasecmp(extracted_encoding, "utf-8")) { + purple_debug_warning("oscar", "Unrecognized character encoding \"%s\", attempting to convert to UTF-8 anyway\n", extracted_encoding); + glib_encoding = extracted_encoding; + } + + if (glib_encoding != NULL) { + utf8 = g_convert(text, textlen, "UTF-8", glib_encoding, NULL, NULL, NULL); + } + + /* + * If utf8 is still NULL then either the encoding is 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 == NULL) { + if (textlen != 0 && *text != '\0' && !g_utf8_validate(text, textlen, NULL)) + utf8 = g_strdup(_("(There was an error receiving this message. The buddy you are speaking with is probably using a different encoding than expected. If you know what encoding he is using, you can specify it in the advanced account options for your AIM/ICQ account.)")); + else + utf8 = g_strndup(text, textlen); + } + + g_free(extracted_encoding); + return utf8; +} + +gchar * +oscar_utf8_try_convert(PurpleAccount *account, OscarData *od, const gchar *msg) +{ + const char *charset = NULL; + char *ret = NULL; + + if (msg == NULL) + return NULL; + + if (g_utf8_validate(msg, -1, NULL)) + return g_strdup(msg); + + if (od->icq) + charset = purple_account_get_string(account, "encoding", NULL); + + if(charset && *charset) + ret = g_convert(msg, -1, "UTF-8", charset, NULL, NULL, NULL); + + if(!ret) + ret = purple_utf8_try_convert(msg); + + return ret; +} + +static gchar * +oscar_convert_to_utf8(const gchar *data, gsize datalen, const char *charsetstr, gboolean fallback) +{ + gchar *ret = NULL; + GError *err = NULL; + + if ((charsetstr == NULL) || (*charsetstr == '\0')) + return NULL; + + if (g_ascii_strcasecmp("UTF-8", charsetstr)) { + if (fallback) + ret = g_convert_with_fallback(data, datalen, "UTF-8", charsetstr, "?", NULL, NULL, &err); + else + ret = g_convert(data, datalen, "UTF-8", charsetstr, NULL, NULL, &err); + if (err != NULL) { + purple_debug_warning("oscar", "Conversion from %s failed: %s.\n", + charsetstr, err->message); + g_error_free(err); + } + } else { + if (g_utf8_validate(data, datalen, NULL)) + ret = g_strndup(data, datalen); + else + purple_debug_warning("oscar", "String is not valid UTF-8.\n"); + } + + return ret; +} + +gchar * +oscar_decode_im(PurpleAccount *account, const char *sourcebn, guint16 charset, const gchar *data, gsize datalen) +{ + gchar *ret = NULL; + /* charsetstr1 is always set to what the correct encoding should be. */ + const gchar *charsetstr1, *charsetstr2, *charsetstr3 = NULL; + + if ((datalen == 0) || (data == NULL)) + return NULL; + + if (charset == AIM_CHARSET_UNICODE) { + charsetstr1 = "UTF-16BE"; + charsetstr2 = "UTF-8"; + } else if (charset == AIM_CHARSET_LATIN_1) { + if ((sourcebn != NULL) && oscar_util_valid_name_icq(sourcebn)) + charsetstr1 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING); + else + charsetstr1 = "ISO-8859-1"; + charsetstr2 = "UTF-8"; + } else if (charset == AIM_CHARSET_ASCII) { + /* Should just be "ASCII" */ + charsetstr1 = "ASCII"; + charsetstr2 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING); + } else if (charset == 0x000d) { + /* iChat sending unicode over a Direct IM connection = UTF-8 */ + /* Mobile AIM client on multiple devices (including Blackberry Tour, Nokia 3100, and LG VX6000) = ISO-8859-1 */ + charsetstr1 = "UTF-8"; + charsetstr2 = "ISO-8859-1"; + charsetstr3 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING); + } else { + /* Unknown, hope for valid UTF-8... */ + charsetstr1 = "UTF-8"; + charsetstr2 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING); + } + + purple_debug_info("oscar", "Parsing IM, charset=0x%04hx, datalen=%" G_GSIZE_FORMAT ", choice1=%s, choice2=%s, choice3=%s\n", + charset, datalen, charsetstr1, charsetstr2, (charsetstr3 ? charsetstr3 : "")); + + ret = oscar_convert_to_utf8(data, datalen, charsetstr1, FALSE); + if (ret == NULL) { + if (charsetstr3 != NULL) { + /* Try charsetstr2 without allowing substitutions, then fall through to charsetstr3 if needed */ + ret = oscar_convert_to_utf8(data, datalen, charsetstr2, FALSE); + if (ret == NULL) + ret = oscar_convert_to_utf8(data, datalen, charsetstr3, TRUE); + } else { + /* Try charsetstr2, allowing substitutions */ + ret = oscar_convert_to_utf8(data, datalen, charsetstr2, TRUE); + } + } + if (ret == NULL) { + char *str, *salvage, *tmp; + + str = g_malloc(datalen + 1); + strncpy(str, data, datalen); + str[datalen] = '\0'; + salvage = purple_utf8_salvage(str); + tmp = g_strdup_printf(_("(There was an error receiving this message. Either you and %s have different encodings selected, or %s has a buggy client.)"), + sourcebn, sourcebn); + ret = g_strdup_printf("%s %s", salvage, tmp); + g_free(tmp); + g_free(str); + g_free(salvage); + } + + return ret; +} + +static guint16 +get_simplest_charset(const char *utf8) +{ + while (*utf8) + { + if ((unsigned char)(*utf8) > 0x7f) { + /* not ASCII! */ + return AIM_CHARSET_UNICODE; + } + utf8++; + } + return AIM_CHARSET_ASCII; +} + +gchar * +oscar_encode_im(const gchar *msg, gsize *result_len, guint16 *charset, gchar **charsetstr) +{ + guint16 msg_charset = get_simplest_charset(msg); + if (charset != NULL) { + *charset = msg_charset; + } + if (charsetstr != NULL) { + *charsetstr = msg_charset == AIM_CHARSET_ASCII ? "us-ascii" : "unicode-2-0"; + } + return g_convert(msg, -1, msg_charset == AIM_CHARSET_ASCII ? "ASCII" : "UTF-16BE", "UTF-8", NULL, result_len, NULL); +} diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/encoding.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/oscar/encoding.h Fri Aug 20 08:35:27 2010 +0000 @@ -0,0 +1,46 @@ +/* + * Purple's oscar protocol plugin + * This file is the legal property of its developers. + * Please see the AUTHORS file distributed alongside this file. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA +*/ + +#ifndef _ENCODING_H_ +#define _ENCODING_H_ + +#include "oscar.h" +#include "oscarcommon.h" + +gchar * oscar_encoding_to_utf8(const char *encoding, const char *text, int textlen); +gchar * oscar_utf8_try_convert(PurpleAccount *account, OscarData *od, const gchar *msg); + +/** + * This attemps to decode an incoming IM into a UTF8 string. + * + * We try decoding using two different character sets. The charset + * specified in the IM determines the order in which we attempt to + * decode. We do this because there are lots of broken ICQ clients + * that don't correctly send non-ASCII messages. And if Purple isn't + * able to deal with that crap, then people complain like banshees. + */ +gchar * oscar_decode_im(PurpleAccount *account, const char *sourcebn, guint16 charset, const gchar *data, gsize datalen); + +/** + * Figure out what encoding to use when sending a given outgoing message. + */ +gchar * oscar_encode_im(const gchar *msg, gsize *result_len, guint16 *charset, gchar **charsetstr); + +#endif \ No newline at end of file diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_admin.c --- a/libpurple/protocols/oscar/family_admin.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/family_admin.c Fri Aug 20 08:35:27 2010 +0000 @@ -47,7 +47,7 @@ byte_stream_put16(&bs, 0x0000); snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0002, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0002, snacid, &bs); byte_stream_destroy(&bs); } @@ -68,7 +68,7 @@ perms = byte_stream_get16(bs); tlvcount = byte_stream_get16(bs); - while (tlvcount && byte_stream_empty(bs)) { + while (tlvcount && byte_stream_bytes_left(bs)) { guint16 type, length; type = byte_stream_get16(bs); @@ -127,7 +127,7 @@ aim_tlvlist_free(tlvlist); snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, snacid, &bs); byte_stream_destroy(&bs); } @@ -154,7 +154,7 @@ aim_tlvlist_free(tlvlist); snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, snacid, &bs); byte_stream_destroy(&bs); } @@ -177,7 +177,7 @@ aim_tlvlist_free(tlvlist); snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, snacid, &bs); byte_stream_destroy(&bs); } diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_advert.c --- a/libpurple/protocols/oscar/family_advert.c Fri Aug 20 08:34:12 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Purple's oscar protocol plugin - * This file is the legal property of its developers. - * Please see the AUTHORS file distributed alongside this file. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA -*/ - -/* - * Family 0x0005 - Advertisements. - * - */ - -#include "oscar.h" - -void -aim_ads_requestads(OscarData *od, FlapConnection *conn) -{ - aim_genericreq_n(od, conn, SNAC_FAMILY_ADVERT, 0x0002); -} - -static int snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs) -{ - return 0; -} - -int adverts_modfirst(OscarData *od, aim_module_t *mod) -{ - - mod->family = SNAC_FAMILY_ADVERT; - mod->version = 0x0001; - mod->toolid = 0x0001; - mod->toolversion = 0x0001; - mod->flags = 0; - strncpy(mod->name, "advert", sizeof(mod->name)); - mod->snachandler = snachandler; - - return 0; -} diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_alert.c --- a/libpurple/protocols/oscar/family_alert.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/family_alert.c Fri Aug 20 08:35:27 2010 +0000 @@ -73,7 +73,7 @@ byte_stream_put16(&bs, 0x0631); snacid = aim_cachesnac(od, SNAC_FAMILY_ALERT, 0x0006, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ALERT, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ALERT, 0x0006, snacid, &bs); byte_stream_destroy(&bs); @@ -189,7 +189,7 @@ byte_stream_put32(&bs, 0x00000000); snacid = aim_cachesnac(od, SNAC_FAMILY_ALERT, 0x0016, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ALERT, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ALERT, 0x0006, snacid, &bs); byte_stream_destroy(&bs); diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_auth.c --- a/libpurple/protocols/oscar/family_auth.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/family_auth.c Fri Aug 20 08:35:27 2010 +0000 @@ -56,17 +56,10 @@ aim_encode_password(const char *password, guint8 *encoded) { guint8 encoding_table[] = { -#if 0 /* old v1 table */ - 0xf3, 0xb3, 0x6c, 0x99, - 0x95, 0x3f, 0xac, 0xb6, - 0xc5, 0xfa, 0x6b, 0x63, - 0x69, 0x6c, 0xc3, 0x9f -#else /* v2.1 table, also works for ICQ */ 0xf3, 0x26, 0x81, 0xc4, 0x39, 0x86, 0xdb, 0x92, 0x71, 0xa3, 0xb9, 0xe6, 0x53, 0x7a, 0x95, 0x7c -#endif }; unsigned int i; @@ -234,7 +227,7 @@ frame = flap_frame_new(od, 0x02, 1152); snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, 0x0002, 0x0000, NULL, 0); - aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0002, 0x0000, snacid); + aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0002, snacid); aim_tlvlist_add_str(&tlvlist, 0x0001, sn); @@ -385,12 +378,6 @@ if (aim_tlv_gettlv(tlvlist, 0x0043, 1)) info->latestbeta.name = aim_tlv_getstr(tlvlist, 0x0043, 1); -#if 0 - if (aim_tlv_gettlv(tlvlist, 0x0048, 1)) { - /* beta serial */ - } -#endif - if (aim_tlv_gettlv(tlvlist, 0x0044, 1)) info->latestrelease.build = aim_tlv_get32(tlvlist, 0x0044, 1); if (aim_tlv_gettlv(tlvlist, 0x0045, 1)) @@ -400,27 +387,12 @@ if (aim_tlv_gettlv(tlvlist, 0x0047, 1)) info->latestrelease.name = aim_tlv_getstr(tlvlist, 0x0047, 1); -#if 0 - if (aim_tlv_gettlv(tlvlist, 0x0049, 1)) { - /* lastest release serial */ - } -#endif - /* * URL to change password. */ if (aim_tlv_gettlv(tlvlist, 0x0054, 1)) info->chpassurl = aim_tlv_getstr(tlvlist, 0x0054, 1); -#if 0 - /* - * Unknown. Seen on an @mac.com username with value of 0x003f - */ - if (aim_tlv_gettlv(tlvlist, 0x0055, 1)) { - /* Unhandled */ - } -#endif - od->authinfo = info; if ((userfunc = aim_callhandler(od, snac ? snac->family : SNAC_FAMILY_AUTH, snac ? snac->subtype : 0x0003))) @@ -504,7 +476,7 @@ frame = flap_frame_new(od, 0x02, 10+2+2+strlen(sn)+8); snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, 0x0006, 0x0000, NULL, 0); - aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0006, 0x0000, snacid); + aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0006, snacid); aim_tlvlist_add_str(&tlvlist, 0x0001, sn); @@ -602,7 +574,7 @@ frame = flap_frame_new(od, 0x02, 10+2+len); snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0x0000, NULL, 0); - aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0x0000, 0); + aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0); byte_stream_put16(&frame->data, len); byte_stream_putstr(&frame->data, securid); diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_bart.c --- a/libpurple/protocols/oscar/family_bart.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/family_bart.c Fri Aug 20 08:35:27 2010 +0000 @@ -56,7 +56,7 @@ byte_stream_putraw(&bs, icon, iconlen); snacid = aim_cachesnac(od, SNAC_FAMILY_BART, 0x0002, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_BART, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_BART, 0x0002, snacid, &bs); byte_stream_destroy(&bs); @@ -121,7 +121,7 @@ byte_stream_putraw(&bs, iconcsum, iconcsumlen); snacid = aim_cachesnac(od, SNAC_FAMILY_BART, 0x0004, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_BART, 0x0004, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_BART, 0x0004, snacid, &bs); byte_stream_destroy(&bs); diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_bos.c --- a/libpurple/protocols/oscar/family_bos.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/family_bos.c Fri Aug 20 08:35:27 2010 +0000 @@ -68,98 +68,6 @@ return ret; } -/* - * Subtype 0x0004 - Set group permission mask. - * - * Normally 0x1f (all classes). - * - * The group permission mask allows you to keep users of a certain - * class or classes from talking to you. The mask should be - * a bitwise OR of all the user classes you want to see you. - * - */ -void -aim_bos_setgroupperm(OscarData *od, FlapConnection *conn, guint32 mask) -{ - aim_genericreq_l(od, conn, SNAC_FAMILY_BOS, 0x0004, &mask); -} - -/* - * Stubtypes 0x0005, 0x0006, 0x0007, and 0x0008 - Modify permit/deny lists. - * - * Changes your visibility depending on changetype: - * - * AIM_VISIBILITYCHANGE_PERMITADD: Lets provided list of names see you - * AIM_VISIBILITYCHANGE_PERMIDREMOVE: Removes listed names from permit list - * AIM_VISIBILITYCHANGE_DENYADD: Hides you from provided list of names - * AIM_VISIBILITYCHANGE_DENYREMOVE: Lets list see you again - * - * list should be a list of "Buddy Name One&BuddyNameTwo&" etc. - * - * Equivelents to options in WinAIM: - * - Allow all users to contact me: Send an AIM_VISIBILITYCHANGE_DENYADD - * with only your name on it. - * - Allow only users on my Buddy List: Send an - * AIM_VISIBILITYCHANGE_PERMITADD with the list the same as your - * buddy list - * - Allow only the uesrs below: Send an AIM_VISIBILITYCHANGE_PERMITADD - * with everyone listed that you want to see you. - * - Block all users: Send an AIM_VISIBILITYCHANGE_PERMITADD with only - * yourself in the list - * - Block the users below: Send an AIM_VISIBILITYCHANGE_DENYADD with - * the list of users to be blocked - * - * XXX ye gods. - */ -int aim_bos_changevisibility(OscarData *od, FlapConnection *conn, int changetype, const char *denylist) -{ - ByteStream bs; - int packlen = 0; - guint16 subtype; - char *localcpy = NULL, *tmpptr = NULL; - int i; - int listcount; - aim_snacid_t snacid; - - if (!denylist) - return -EINVAL; - - if (changetype == AIM_VISIBILITYCHANGE_PERMITADD) - subtype = 0x05; - else if (changetype == AIM_VISIBILITYCHANGE_PERMITREMOVE) - subtype = 0x06; - else if (changetype == AIM_VISIBILITYCHANGE_DENYADD) - subtype = 0x07; - else if (changetype == AIM_VISIBILITYCHANGE_DENYREMOVE) - subtype = 0x08; - else - return -EINVAL; - - localcpy = g_strdup(denylist); - - listcount = aimutil_itemcnt(localcpy, '&'); - packlen = aimutil_tokslen(localcpy, 99, '&') + listcount-1; - - byte_stream_new(&bs, packlen); - - for (i = 0; (i < (listcount - 1)) && (i < 99); i++) { - tmpptr = aimutil_itemindex(localcpy, i, '&'); - - byte_stream_put8(&bs, strlen(tmpptr)); - byte_stream_putstr(&bs, tmpptr); - - g_free(tmpptr); - } - g_free(localcpy); - - snacid = aim_cachesnac(od, SNAC_FAMILY_BOS, subtype, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_BOS, subtype, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; -} - static int snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_buddy.c --- a/libpurple/protocols/oscar/family_buddy.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/family_buddy.c Fri Aug 20 08:35:27 2010 +0000 @@ -88,117 +88,6 @@ } /* - * Subtype 0x0004 (SNAC_SUBTYPE_BUDDY_ADDBUDDY) - Add buddy to list. - * - * Adds a single buddy to your buddy list after login. - * XXX This should just be an extension of setbuddylist() - * - */ -int -aim_buddylist_addbuddy(OscarData *od, FlapConnection *conn, const char *sn) -{ - ByteStream bs; - aim_snacid_t snacid; - - if (!sn || !strlen(sn)) - return -EINVAL; - - byte_stream_new(&bs, 1+strlen(sn)); - - byte_stream_put8(&bs, strlen(sn)); - byte_stream_putstr(&bs, sn); - - snacid = aim_cachesnac(od, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, sn, strlen(sn)+1); - flap_connection_send_snac(od, conn, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; -} - -/* - * Subtype 0x0004 (SNAC_SUBTYPE_BUDDY_ADDBUDDY) - Add multiple buddies to your buddy list. - * - * This just builds the "set buddy list" command then queues it. - * - * buddy_list = "Buddy Name One&BuddyNameTwo&"; - * - * XXX Clean this up. - * - */ -int -aim_buddylist_set(OscarData *od, FlapConnection *conn, const char *buddy_list) -{ - ByteStream bs; - aim_snacid_t snacid; - int len = 0; - char *localcpy = NULL; - char *tmpptr = NULL; - - if (!buddy_list || !(localcpy = g_strdup(buddy_list))) - return -EINVAL; - - for (tmpptr = strtok(localcpy, "&"); tmpptr; ) { - purple_debug_misc("oscar", "---adding: %s (%" G_GSIZE_FORMAT - ")\n", tmpptr, strlen(tmpptr)); - len += 1 + strlen(tmpptr); - tmpptr = strtok(NULL, "&"); - } - - byte_stream_new(&bs, len); - - strncpy(localcpy, buddy_list, strlen(buddy_list) + 1); - - for (tmpptr = strtok(localcpy, "&"); tmpptr; ) { - - purple_debug_misc("oscar", "---adding: %s (%" G_GSIZE_FORMAT - ")\n", tmpptr, strlen(tmpptr)); - - byte_stream_put8(&bs, strlen(tmpptr)); - byte_stream_putstr(&bs, tmpptr); - tmpptr = strtok(NULL, "&"); - } - - snacid = aim_cachesnac(od, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - g_free(localcpy); - - return 0; -} - -/* - * Subtype 0x0005 (SNAC_SUBTYPE_BUDDY_REMBUDDY) - Remove buddy from list. - * - * XXX generalise to support removing multiple buddies (basically, its - * the same as setbuddylist() but with a different snac subtype). - * - */ -int -aim_buddylist_removebuddy(OscarData *od, FlapConnection *conn, const char *sn) -{ - ByteStream bs; - aim_snacid_t snacid; - - if (!sn || !strlen(sn)) - return -EINVAL; - - byte_stream_new(&bs, 1 + strlen(sn)); - - byte_stream_put8(&bs, strlen(sn)); - byte_stream_putstr(&bs, sn); - - snacid = aim_cachesnac(od, SNAC_FAMILY_BUDDY, 0x0005, 0x0000, sn, strlen(sn)+1); - flap_connection_send_snac(od, conn, SNAC_FAMILY_BUDDY, 0x0005, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; -} - -/* * Subtypes 0x000b (SNAC_SUBTYPE_BUDDY_ONCOMING) and 0x000c (SNAC_SUBTYPE_BUDDY_OFFGOING) - Change in buddy status * * Oncoming Buddy notifications contain a subset of the diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_chat.c --- a/libpurple/protocols/oscar/family_chat.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/family_chat.c Fri Aug 20 08:35:27 2010 +0000 @@ -47,74 +47,6 @@ return; } -char * -aim_chat_getname(FlapConnection *conn) -{ - struct chatconnpriv *ccp; - - if (!conn) - return NULL; - - if (conn->type != SNAC_FAMILY_CHAT) - return NULL; - - ccp = (struct chatconnpriv *)conn->internal; - - return ccp->name; -} - -/* XXX get this into conn.c -- evil!! */ -FlapConnection * -aim_chat_getconn(OscarData *od, const char *name) -{ - GSList *cur; - - for (cur = od->oscar_connections; cur; cur = cur->next) - { - FlapConnection *conn; - struct chatconnpriv *ccp; - - conn = cur->data; - ccp = (struct chatconnpriv *)conn->internal; - - if (conn->type != SNAC_FAMILY_CHAT) - continue; - if (!conn->internal) - { - purple_debug_misc("oscar", "%sfaim: chat: chat connection with no name! (fd = %d)\n", - conn->gsc ? "(ssl) " : "", conn->gsc ? conn->gsc->fd : conn->fd); - continue; - } - - if (strcmp(ccp->name, name) == 0) - return conn; - } - - return NULL; -} - -int -aim_chat_attachname(FlapConnection *conn, guint16 exchange, const char *roomname, guint16 instance) -{ - struct chatconnpriv *ccp; - - if (!conn || !roomname) - return -EINVAL; - - if (conn->internal) - g_free(conn->internal); - - ccp = g_new(struct chatconnpriv, 1); - - ccp->exchange = exchange; - ccp->name = g_strdup(roomname); - ccp->instance = instance; - - conn->internal = (void *)ccp; - - return 0; -} - int aim_chat_readroominfo(ByteStream *bs, struct aim_chat_roominfo *outinfo) { @@ -129,19 +61,6 @@ return 0; } -int -aim_chat_leaveroom(OscarData *od, const char *name) -{ - FlapConnection *conn; - - if (!(conn = aim_chat_getconn(od, name))) - return -ENOENT; - - flap_connection_close(od, conn); - - return 0; -} - /* * Subtype 0x0002 - General room information. Lots of stuff. * @@ -153,21 +72,12 @@ static int infoupdate(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { - aim_userinfo_t *userinfo = NULL; aim_rxcallback_t userfunc; int ret = 0; - int usercount; guint8 detaillevel = 0; - char *roomname; struct aim_chat_roominfo roominfo; - guint16 tlvcount = 0; GSList *tlvlist; - aim_tlv_t *tlv; - char *roomdesc; - guint16 flags; - guint32 creationtime; guint16 maxmsglen, maxvisiblemsglen; - guint16 unknown_d2, unknown_d5; aim_chat_readroominfo(bs, &roominfo); @@ -178,139 +88,27 @@ return 1; } - tlvcount = byte_stream_get16(bs); - /* * Everything else are TLVs. */ tlvlist = aim_tlvlist_read(bs); /* - * TLV type 0x006a is the room name in Human Readable Form. - */ - roomname = aim_tlv_getstr(tlvlist, 0x006a, 1); - - /* - * Type 0x006f: Number of occupants. - */ - usercount = aim_tlv_get16(tlvlist, 0x006f, 1); - - /* - * Type 0x0073: Occupant list. - */ - tlv = aim_tlv_gettlv(tlvlist, 0x0073, 1); - if (tlv != NULL) - { - int curoccupant = 0; - ByteStream occbs; - - /* Allocate enough userinfo structs for all occupants */ - userinfo = g_new0(aim_userinfo_t, usercount); - - byte_stream_init(&occbs, tlv->value, tlv->length); - - while (curoccupant < usercount) - aim_info_extract(od, &occbs, &userinfo[curoccupant++]); - } - - /* - * Type 0x00c9: Flags. (AIM_CHATROOM_FLAG) - */ - flags = aim_tlv_get16(tlvlist, 0x00c9, 1); - - /* - * Type 0x00ca: Creation time (4 bytes) - */ - creationtime = aim_tlv_get32(tlvlist, 0x00ca, 1); - - /* * Type 0x00d1: Maximum Message Length */ maxmsglen = aim_tlv_get16(tlvlist, 0x00d1, 1); /* - * Type 0x00d2: Unknown. (2 bytes) - */ - unknown_d2 = aim_tlv_get16(tlvlist, 0x00d2, 1); - - /* - * Type 0x00d3: Room Description - */ - roomdesc = aim_tlv_getstr(tlvlist, 0x00d3, 1); - -#if 0 - /* - * Type 0x000d4: Unknown (flag only) - */ - if (aim_tlv_gettlv(tlvlist, 0x000d4, 1)) { - /* Unhandled */ - } -#endif - - /* - * Type 0x00d5: Unknown. (1 byte) - */ - unknown_d5 = aim_tlv_get8(tlvlist, 0x00d5, 1); - -#if 0 - /* - * Type 0x00d6: Encoding 1 ("us-ascii") - */ - if (aim_tlv_gettlv(tlvlist, 0x000d6, 1)) { - /* Unhandled */ - } - - /* - * Type 0x00d7: Language 1 ("en") - */ - if (aim_tlv_gettlv(tlvlist, 0x000d7, 1)) { - /* Unhandled */ - } - - /* - * Type 0x00d8: Encoding 2 ("us-ascii") - */ - if (aim_tlv_gettlv(tlvlist, 0x000d8, 1)) { - /* Unhandled */ - } - - /* - * Type 0x00d9: Language 2 ("en") - */ - if (aim_tlv_gettlv(tlvlist, 0x000d9, 1)) { - /* Unhandled */ - } -#endif - - /* * Type 0x00da: Maximum visible message length */ maxvisiblemsglen = aim_tlv_get16(tlvlist, 0x00da, 1); if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) { - ret = userfunc(od, conn, - frame, - &roominfo, - roomname, - usercount, - userinfo, - roomdesc, - flags, - creationtime, - maxmsglen, - unknown_d2, - unknown_d5, - maxvisiblemsglen); + ret = userfunc(od, conn, frame, maxmsglen, maxvisiblemsglen); } g_free(roominfo.name); - while (usercount > 0) - aim_info_free(&userinfo[--usercount]); - - g_free(userinfo); - g_free(roomname); - g_free(roomdesc); aim_tlvlist_free(tlvlist); return ret; @@ -324,7 +122,7 @@ aim_rxcallback_t userfunc; int curcount = 0, ret = 0; - while (byte_stream_empty(bs)) { + while (byte_stream_bytes_left(bs)) { curcount++; userinfo = g_realloc(userinfo, curcount * sizeof(aim_userinfo_t)); aim_info_extract(od, bs, &userinfo[curcount-1]); @@ -434,7 +232,7 @@ aim_tlvlist_free(inner_tlvlist); aim_tlvlist_free(tlvlist); - flap_connection_send_snac(od, conn, SNAC_FAMILY_CHAT, 0x0005, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_CHAT, 0x0005, snacid, &bs); byte_stream_destroy(&bs); @@ -523,16 +321,6 @@ aim_info_extract(od, &tbs, &userinfo); } -#if 0 - /* - * Type 0x0001: If present, it means it was a message to the - * room (as opposed to a whisper). - */ - if (aim_tlv_gettlv(tlvlist, 0x0001, 1)) { - /* Unhandled */ - } -#endif - /* * Type 0x0005: Message Block. Conains more TLVs. */ diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_chatnav.c --- a/libpurple/protocols/oscar/family_chatnav.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/family_chatnav.c Fri Aug 20 08:35:27 2010 +0000 @@ -139,7 +139,7 @@ aim_tlvlist_free(tlvlist); - flap_connection_send_snac(od, conn, SNAC_FAMILY_CHATNAV, 0x0008, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_CHATNAV, 0x0008, snacid, &bs); byte_stream_destroy(&bs); @@ -185,32 +185,6 @@ exchanges[curexchange-1].number = byte_stream_get16(&tbs); innerlist = aim_tlvlist_read(&tbs); -#if 0 - /* - * Type 0x000a: Unknown. - * - * Usually three bytes: 0x0114 (exchange 1) or 0x010f (others). - * - */ - if (aim_tlv_gettlv(innerlist, 0x000a, 1)) { - /* Unhandled */ - } - - /* - * Type 0x000d: Unknown. - */ - if (aim_tlv_gettlv(innerlist, 0x000d, 1)) { - /* Unhandled */ - } - - /* - * Type 0x0004: Unknown - */ - if (aim_tlv_gettlv(innerlist, 0x0004, 1)) { - /* Unhandled */ - } -#endif - /* * Type 0x0002: Unknown */ @@ -234,36 +208,6 @@ if (aim_tlv_gettlv(innerlist, 0x00c9, 1)) exchanges[curexchange-1].flags = aim_tlv_get16(innerlist, 0x00c9, 1); -#if 0 - /* - * Type 0x00ca: Creation Date - */ - if (aim_tlv_gettlv(innerlist, 0x00ca, 1)) { - /* Unhandled */ - } - - /* - * Type 0x00d0: Mandatory Channels? - */ - if (aim_tlv_gettlv(innerlist, 0x00d0, 1)) { - /* Unhandled */ - } - - /* - * Type 0x00d1: Maximum Message length - */ - if (aim_tlv_gettlv(innerlist, 0x00d1, 1)) { - /* Unhandled */ - } - - /* - * Type 0x00d2: Maximum Occupancy? - */ - if (aim_tlv_gettlv(innerlist, 0x00d2, 1)) { - /* Unhandled */ - } -#endif - /* * Type 0x00d3: Exchange Description */ @@ -272,15 +216,6 @@ else exchanges[curexchange-1].name = NULL; -#if 0 - /* - * Type 0x00d4: Exchange Description URL - */ - if (aim_tlv_gettlv(innerlist, 0x00d4, 1)) { - /* Unhandled */ - } -#endif - /* * Type 0x00d5: Creation Permissions * @@ -327,15 +262,6 @@ else exchanges[curexchange-1].lang2 = NULL; -#if 0 - /* - * Type 0x00da: Unknown - */ - if (aim_tlv_gettlv(innerlist, 0x00da, 1)) { - /* Unhandled */ - } -#endif - aim_tlvlist_free(innerlist); } diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_feedbag.c --- a/libpurple/protocols/oscar/family_feedbag.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/family_feedbag.c Fri Aug 20 08:35:27 2010 +0000 @@ -660,10 +660,8 @@ if (!cur->name) { if (cur->type == AIM_SSI_TYPE_BUDDY) aim_ssi_delbuddy(od, NULL, NULL); - else if (cur->type == AIM_SSI_TYPE_PERMIT) - aim_ssi_delpermit(od, NULL); - else if (cur->type == AIM_SSI_TYPE_DENY) - aim_ssi_deldeny(od, NULL); + else if (cur->type == AIM_SSI_TYPE_PERMIT || cur->type == AIM_SSI_TYPE_DENY || cur->type == AIM_SSI_TYPE_ICQDENY) + aim_ssi_del_from_private_list(od, NULL, cur->type); } else if ((cur->type == AIM_SSI_TYPE_BUDDY) && ((cur->gid == 0x0000) || (!aim_ssi_itemlist_find(od->ssi.local, cur->gid, 0x0000)))) { char *alias = aim_ssi_getalias(od->ssi.local, NULL, cur->name); aim_ssi_addbuddy(od, cur->name, "orphans", NULL, alias, NULL, NULL, FALSE); @@ -748,51 +746,31 @@ return aim_ssi_sync(od); } -/** - * Add a permit buddy to the list. - * - * @param od The oscar odion. - * @param name The name of the item.. - * @return Return 0 if no errors, otherwise return the error number. - */ -int aim_ssi_addpermit(OscarData *od, const char *name) +int +aim_ssi_add_to_private_list(OscarData *od, const char* name, guint16 list_type) { - if (!od || !name || !od->ssi.received_data) return -EINVAL; - /* Make sure the master group exists */ if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL) - aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL); + aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, list_type, NULL); - /* Add that bad boy */ - aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_PERMIT, NULL); - - /* Sync our local list with the server list */ + aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, list_type, NULL); return aim_ssi_sync(od); } -/** - * Add a deny buddy to the list. - * - * @param od The oscar odion. - * @param name The name of the item.. - * @return Return 0 if no errors, otherwise return the error number. - */ -int aim_ssi_adddeny(OscarData *od, const char *name) +int +aim_ssi_del_from_private_list(OscarData* od, const char* name, guint16 list_type) { + struct aim_ssi_item *del; - if (!od || !name || !od->ssi.received_data) + if (!od) return -EINVAL; - /* Make sure the master group exists */ - if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL) - aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL); + if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, NULL, name, list_type))) + return -EINVAL; - /* Add that bad boy */ - aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_DENY, NULL); - - /* Sync our local list with the server list */ + aim_ssi_itemlist_del(&od->ssi.local, del); return aim_ssi_sync(od); } @@ -860,56 +838,6 @@ } /** - * Deletes a permit buddy from the list. - * - * @param od The oscar odion. - * @param name The name of the item, or NULL. - * @return Return 0 if no errors, otherwise return the error number. - */ -int aim_ssi_delpermit(OscarData *od, const char *name) -{ - struct aim_ssi_item *del; - - if (!od) - return -EINVAL; - - /* Find the item */ - if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, NULL, name, AIM_SSI_TYPE_PERMIT))) - return -EINVAL; - - /* Remove the item from the list */ - aim_ssi_itemlist_del(&od->ssi.local, del); - - /* Sync our local list with the server list */ - return aim_ssi_sync(od); -} - -/** - * Deletes a deny buddy from the list. - * - * @param od The oscar odion. - * @param name The name of the item, or NULL. - * @return Return 0 if no errors, otherwise return the error number. - */ -int aim_ssi_deldeny(OscarData *od, const char *name) -{ - struct aim_ssi_item *del; - - if (!od) - return -EINVAL; - - /* Find the item */ - if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, NULL, name, AIM_SSI_TYPE_DENY))) - return -EINVAL; - - /* Remove the item from the list */ - aim_ssi_itemlist_del(&od->ssi.local, del); - - /* Sync our local list with the server list */ - return aim_ssi_sync(od); -} - -/** * Move a buddy from one group to another group. This basically just deletes the * buddy and re-adds it. * @@ -1030,17 +958,16 @@ * Stores your permit/deny setting on the server, and starts using it. * * @param od The oscar odion. - * @param permdeny Your permit/deny setting. Can be one of the following: + * @param permdeny Your permit/deny setting. For ICQ accounts, it actually affects your visibility + * and has nothing to do with blocking. Can be one of the following: * 1 - Allow all users * 2 - Block all users * 3 - Allow only the users below * 4 - Block only the users below * 5 - Allow only users on my buddy list - * @param vismask A bitmask of the class of users to whom you want to be - * visible. See the AIM_FLAG_BLEH #defines in oscar.h * @return Return 0 if no errors, otherwise return the error number. */ -int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny, guint32 vismask) +int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny) { struct aim_ssi_item *tmp; @@ -1059,9 +986,6 @@ /* Need to add the 0x00ca TLV to the TLV chain */ aim_tlvlist_replace_8(&tmp->data, 0x00ca, permdeny); - /* Need to add the 0x00cb TLV to the TLV chain */ - aim_tlvlist_replace_32(&tmp->data, 0x00cb, vismask); - /* Sync our local list with the server list */ return aim_ssi_sync(od); } @@ -1231,41 +1155,6 @@ } /* - * Subtype 0x0005 - Request SSI Data when you have a timestamp and revision - * number. - * - * The data will only be sent if it is newer than the posted local - * timestamp and revision. - * - * Note that the client should never increment the revision, only the server. - * - */ -int aim_ssi_reqifchanged(OscarData *od, time_t timestamp, guint16 numitems) -{ - FlapConnection *conn; - ByteStream bs; - aim_snacid_t snacid; - - if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG))) - return -EINVAL; - - byte_stream_new(&bs, 4+2); - - byte_stream_put32(&bs, timestamp); - byte_stream_put16(&bs, numitems); - - snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_REQIFCHANGED, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_REQIFCHANGED, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - /* Free any current data, just in case */ - aim_ssi_freelist(od); - - return 0; -} - -/* * Subtype 0x0006 - SSI Data. */ static int parsedata(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) @@ -1281,7 +1170,7 @@ od->ssi.numitems += byte_stream_get16(bs); /* # of items in this SSI SNAC */ /* Read in the list */ - while (byte_stream_empty(bs) > 4) { /* last four bytes are timestamp */ + while (byte_stream_bytes_left(bs) > 4) { /* last four bytes are timestamp */ if ((namelen = byte_stream_get16(bs))) name = byte_stream_getstr(bs, namelen); else @@ -1378,7 +1267,7 @@ } snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, od->ssi.pending->action, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, od->ssi.pending->action, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, od->ssi.pending->action, snacid, &bs); byte_stream_destroy(&bs); @@ -1399,7 +1288,7 @@ guint16 len, gid, bid, type; GSList *data; - while (byte_stream_empty(bs)) { + while (byte_stream_bytes_left(bs)) { if ((len = byte_stream_get16(bs))) name = byte_stream_getstr(bs, len); else @@ -1437,7 +1326,7 @@ GSList *data; struct aim_ssi_item *item; - while (byte_stream_empty(bs)) { + while (byte_stream_bytes_left(bs)) { if ((len = byte_stream_get16(bs))) name = byte_stream_getstr(bs, len); else @@ -1489,7 +1378,7 @@ guint16 gid, bid; struct aim_ssi_item *del; - while (byte_stream_empty(bs)) { + while (byte_stream_bytes_left(bs)) { byte_stream_advance(bs, byte_stream_get16(bs)); gid = byte_stream_get16(bs); bid = byte_stream_get16(bs); @@ -1522,7 +1411,7 @@ /* Read in the success/failure flags from the ack SNAC */ cur = od->ssi.pending; - while (cur && (byte_stream_empty(bs)>0)) { + while (cur && (byte_stream_bytes_left(bs)>0)) { cur->ack = byte_stream_get16(bs); cur = cur->next; } @@ -1678,45 +1567,6 @@ } /* - * Subtype 0x0014 - Grant authorization - * - * Authorizes a contact so they can add you to their contact list. - * - */ -int aim_ssi_sendauth(OscarData *od, char *bn, char *msg) -{ - FlapConnection *conn; - ByteStream bs; - aim_snacid_t snacid; - - if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !bn) - return -EINVAL; - - byte_stream_new(&bs, 1+strlen(bn) + 2+(msg ? strlen(msg)+1 : 0) + 2); - - /* Username */ - byte_stream_put8(&bs, strlen(bn)); - byte_stream_putstr(&bs, bn); - - /* Message (null terminated) */ - byte_stream_put16(&bs, msg ? strlen(msg) : 0); - if (msg) { - byte_stream_putstr(&bs, msg); - byte_stream_put8(&bs, 0x00); - } - - /* Unknown */ - byte_stream_put16(&bs, 0x0000); - - snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTH, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTH, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; -} - -/* * Subtype 0x0015 - Receive an authorization grant */ static int receiveauthgrant(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) @@ -1783,7 +1633,7 @@ byte_stream_put16(&bs, 0x0000); snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, snacid, &bs); byte_stream_destroy(&bs); @@ -1863,7 +1713,7 @@ byte_stream_put16(&bs, 0x0000); snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, snacid, &bs); byte_stream_destroy(&bs); @@ -1935,6 +1785,16 @@ return ret; } +/* + * If we're on ICQ, then AIM_SSI_TYPE_DENY is used for the "permanently invisible" list. + * AIM_SSI_TYPE_ICQDENY is used for blocking users instead. + */ +guint16 +aim_ssi_getdenyentrytype(OscarData* od) +{ + return od->icq ? AIM_SSI_TYPE_ICQDENY : AIM_SSI_TYPE_DENY; +} + static int snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_icbm.c --- a/libpurple/protocols/oscar/family_icbm.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/family_icbm.c Fri Aug 20 08:35:27 2010 +0000 @@ -44,6 +44,7 @@ * Make sure flap_connection_findbygroup is used by all functions. */ +#include "encoding.h" #include "oscar.h" #include "peer.h" @@ -108,69 +109,6 @@ } /* - * Takes a msghdr (and a length) and returns a client type - * code. Note that this is *only a guess* and has a low likelihood - * of actually being accurate. - * - * Its based on experimental data, with the help of Eric Warmenhoven - * who seems to have collected a wide variety of different AIM clients. - * - * - * Heres the current collection: - * 0501 0003 0101 0101 01 AOL Mobile Communicator, WinAIM 1.0.414 - * 0501 0003 0101 0201 01 WinAIM 2.0.847, 2.1.1187, 3.0.1464, - * 4.3.2229, 4.4.2286 - * 0501 0004 0101 0102 0101 WinAIM 4.1.2010, libfaim (right here) - * 0501 0003 0101 02 WinAIM 5 - * 0501 0001 01 iChat x.x, mobile buddies - * 0501 0001 0101 01 AOL v6.0, CompuServe 2000 v6.0, any TOC client - * 0501 0002 0106 WinICQ 5.45.1.3777.85 - * - * Note that in this function, only the feature bytes are tested, since - * the rest will always be the same. - * - */ -guint16 aim_im_fingerprint(const guint8 *msghdr, int len) -{ - static const struct { - guint16 clientid; - int len; - guint8 data[10]; - } fingerprints[] = { - /* AOL Mobile Communicator, WinAIM 1.0.414 */ - { AIM_CLIENTTYPE_MC, - 3, {0x01, 0x01, 0x01}}, - - /* WinAIM 2.0.847, 2.1.1187, 3.0.1464, 4.3.2229, 4.4.2286 */ - { AIM_CLIENTTYPE_WINAIM, - 3, {0x01, 0x01, 0x02}}, - - /* WinAIM 4.1.2010, libfaim */ - { AIM_CLIENTTYPE_WINAIM41, - 4, {0x01, 0x01, 0x01, 0x02}}, - - /* AOL v6.0, CompuServe 2000 v6.0, any TOC client */ - { AIM_CLIENTTYPE_AOL_TOC, - 1, {0x01}}, - - { 0, 0, {0x00}} - }; - int i; - - if (!msghdr || (len <= 0)) - return AIM_CLIENTTYPE_UNKNOWN; - - for (i = 0; fingerprints[i].len; i++) { - if (fingerprints[i].len != len) - continue; - if (memcmp(fingerprints[i].data, msghdr, fingerprints[i].len) == 0) - return fingerprints[i].clientid; - } - - return AIM_CLIENTTYPE_UNKNOWN; -} - -/* * Subtype 0x0001 - Error */ static int @@ -287,7 +225,7 @@ byte_stream_put32(&bs, params->minmsginterval); snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0002, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0002, snacid, &bs); byte_stream_destroy(&bs); @@ -345,40 +283,14 @@ * * 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 SNAC_FAMILY_ICBM/0x000c) * AIM_IMFLAGS_OFFLINE--If destination is offline, store it until they are * online (probably ICQ only). * - * 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 equivalent 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_im_sendch1_ext(OscarData *od, struct aim_sendimext_args *args) { @@ -387,7 +299,6 @@ ByteStream data; guchar cookie[8]; int msgtlvlen; - static const guint8 deffeatures[] = { 0x01, 0x01, 0x01, 0x02 }; if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM))) return -EINVAL; @@ -395,37 +306,17 @@ 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->msg || (args->msglen <= 0)) + return -EINVAL; - if (args->msglen > MAXMSGLEN) - return -E2BIG; - } + 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; - } + msgtlvlen += 2 + args->featureslen; + msgtlvlen += 2 /* 0101 */ + 2 /* block len */; + msgtlvlen += 4 /* charset */ + args->msglen; byte_stream_new(&data, msgtlvlen + 128); @@ -441,52 +332,31 @@ /* Features TLV (type 0x0501) */ byte_stream_put16(&data, 0x0501); - if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) { - byte_stream_put16(&data, args->featureslen); - byte_stream_putraw(&data, args->features, args->featureslen); - } else { - byte_stream_put16(&data, sizeof(deffeatures)); - byte_stream_putraw(&data, deffeatures, sizeof(deffeatures)); - } + byte_stream_put16(&data, args->featureslen); + byte_stream_putraw(&data, args->features, args->featureslen); - if (args->flags & AIM_IMFLAGS_MULTIPART) { - aim_mpmsg_section_t *sec; + /* Insert message text in a TLV (type 0x0101) */ + byte_stream_put16(&data, 0x0101); - /* Insert each message part in a TLV (type 0x0101) */ - for (sec = args->mpmsg->parts; sec; sec = sec->next) { - byte_stream_put16(&data, 0x0101); - byte_stream_put16(&data, sec->datalen + 4); - byte_stream_put16(&data, sec->charset); - byte_stream_put16(&data, sec->charsubset); - byte_stream_putraw(&data, (guchar *)sec->data, sec->datalen); - } - - } else { + /* Message block length */ + byte_stream_put16(&data, args->msglen + 0x04); - /* Insert message text in a TLV (type 0x0101) */ - byte_stream_put16(&data, 0x0101); - - /* Message block length */ - byte_stream_put16(&data, args->msglen + 0x04); + /* Character set */ + byte_stream_put16(&data, args->charset); + /* Character subset -- we always use 0 here */ + byte_stream_put16(&data, 0x0); - /* Character set */ - byte_stream_put16(&data, args->charset); - byte_stream_put16(&data, args->charsubset); - - /* Message. Not terminated */ - byte_stream_putraw(&data, (guchar *)args->msg, args->msglen); - } + /* Message. Not terminated */ + byte_stream_putraw(&data, (guchar *)args->msg, args->msglen); /* Set the Autoresponse flag */ if (args->flags & AIM_IMFLAGS_AWAY) { byte_stream_put16(&data, 0x0004); byte_stream_put16(&data, 0x0000); } else { - if (args->flags & AIM_IMFLAGS_ACK) { - /* Set the Request Acknowledge flag */ - byte_stream_put16(&data, 0x0003); - byte_stream_put16(&data, 0x0000); - } + /* Set the Request Acknowledge flag */ + byte_stream_put16(&data, 0x0003); + byte_stream_put16(&data, 0x0000); if (args->flags & AIM_IMFLAGS_OFFLINE) { /* Allow this message to be queued as an offline message */ @@ -521,7 +391,7 @@ /* XXX - should be optional */ snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, args->destbn, strlen(args->destbn)+1); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &data); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &data); byte_stream_destroy(&data); /* clean out SNACs over 60sec old */ @@ -531,33 +401,6 @@ } /* - * Simple wrapper for aim_im_sendch1_ext() - * - * You cannot use aim_send_im if you need the HASICON flag. You must - * use aim_im_sendch1_ext directly for that. - * - * aim_send_im also cannot be used if you require UNICODE messages, because - * that requires an explicit message length. Use aim_im_sendch1_ext(). - * - */ -int aim_im_sendch1(OscarData *od, const char *bn, guint16 flags, const char *msg) -{ - struct aim_sendimext_args args; - - args.destbn = bn; - args.flags = flags; - args.msg = msg; - args.msglen = strlen(msg); - args.charset = 0x0000; - args.charsubset = 0x0000; - - /* Make these don't get set by accident -- they need aim_im_sendch1_ext */ - args.flags &= ~(AIM_IMFLAGS_CUSTOMFEATURES | AIM_IMFLAGS_HASICON | AIM_IMFLAGS_MULTIPART); - - return aim_im_sendch1_ext(od, &args); -} - -/* * Subtype 0x0006 - Send a chat invitation. */ int aim_im_sendch2_chatinvite(OscarData *od, const char *bn, const char *msg, guint16 exchange, const char *roomname, guint16 instance) @@ -628,7 +471,7 @@ aim_tlvlist_free(inner_tlvlist); aim_tlvlist_free(outer_tlvlist); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs); byte_stream_destroy(&bs); @@ -698,100 +541,7 @@ byte_stream_put16(&bs, 0x0003); byte_stream_put16(&bs, 0x0000); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; -} - -/* - * Subtype 0x0006 - Send a rich text message. - * - * This only works for ICQ 2001b (thats 2001 not 2000). Better, only - * send it to clients advertising the RTF capability. In fact, if you send - * it to a client that doesn't support that capability, the server will gladly - * bounce it back to you. - * - * You'd think this would be in icq.c, but, well, I'm trying to stick with - * the one-group-per-file scheme as much as possible. This could easily - * be an exception, since Rendezvous IMs are external of the Oscar core, - * and therefore are undefined. Really I just need to think of a good way to - * make an interface similar to what AOL actually uses. But I'm not using COM. - * - */ -int aim_im_sendch2_rtfmsg(OscarData *od, struct aim_sendrtfmsg_args *args) -{ - FlapConnection *conn; - ByteStream bs; - aim_snacid_t snacid; - guchar cookie[8]; - const char rtfcap[] = {"{97B12751-243C-4334-AD22-D6ABF73F1492}"}; /* OSCAR_CAPABILITY_ICQRTF capability in string form */ - int servdatalen; - - if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM))) - return -EINVAL; - - if (!args || !args->destbn || !args->rtfmsg) - return -EINVAL; - - servdatalen = 2+2+16+2+4+1+2 + 2+2+4+4+4 + 2+4+2+strlen(args->rtfmsg)+1 + 4+4+4+strlen(rtfcap)+1; - - aim_icbm_makecookie(cookie); - - byte_stream_new(&bs, 128+servdatalen); - - snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0); - - /* ICBM header */ - aim_im_puticbm(&bs, cookie, 0x0002, args->destbn); - - /* TLV t(0005) - Encompasses everything below. */ - byte_stream_put16(&bs, 0x0005); - byte_stream_put16(&bs, 2+8+16 + 2+2+2 + 2+2 + 2+2+servdatalen); - - byte_stream_put16(&bs, 0x0000); - byte_stream_putraw(&bs, cookie, 8); - byte_stream_putcaps(&bs, OSCAR_CAPABILITY_ICQSERVERRELAY); - - /* t(000a) l(0002) v(0001) */ - byte_stream_put16(&bs, 0x000a); - byte_stream_put16(&bs, 0x0002); - byte_stream_put16(&bs, 0x0001); - - /* t(000f) l(0000) v() */ - byte_stream_put16(&bs, 0x000f); - byte_stream_put16(&bs, 0x0000); - - /* Service Data TLV */ - byte_stream_put16(&bs, 0x2711); - byte_stream_put16(&bs, servdatalen); - - byte_stream_putle16(&bs, 11 + 16 /* 11 + (sizeof CLSID) */); - byte_stream_putle16(&bs, 9); - byte_stream_putcaps(&bs, OSCAR_CAPABILITY_EMPTY); - byte_stream_putle16(&bs, 0); - byte_stream_putle32(&bs, 0); - byte_stream_putle8(&bs, 0); - byte_stream_putle16(&bs, 0x03ea); /* trid1 */ - - byte_stream_putle16(&bs, 14); - byte_stream_putle16(&bs, 0x03eb); /* trid2 */ - byte_stream_putle32(&bs, 0); - byte_stream_putle32(&bs, 0); - byte_stream_putle32(&bs, 0); - - byte_stream_putle16(&bs, 0x0001); - byte_stream_putle32(&bs, 0); - byte_stream_putle16(&bs, strlen(args->rtfmsg)+1); - byte_stream_putraw(&bs, (const guint8 *)args->rtfmsg, strlen(args->rtfmsg)+1); - - byte_stream_putle32(&bs, args->fgcolor); - byte_stream_putle32(&bs, args->bgcolor); - byte_stream_putle32(&bs, strlen(rtfcap)+1); - byte_stream_putraw(&bs, (const guint8 *)rtfcap, strlen(rtfcap)+1); - - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs); byte_stream_destroy(&bs); @@ -844,7 +594,7 @@ aim_tlvlist_free(inner_tlvlist); aim_tlvlist_free(outer_tlvlist); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs); byte_stream_destroy(&bs); } @@ -879,7 +629,7 @@ byte_stream_putraw(&bs, peer_conn->cookie, 8); byte_stream_putcaps(&bs, peer_conn->type); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs); byte_stream_destroy(&bs); } @@ -934,7 +684,7 @@ aim_tlvlist_free(inner_tlvlist); aim_tlvlist_free(outer_tlvlist); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs); byte_stream_destroy(&bs); } @@ -997,7 +747,7 @@ aim_tlvlist_free(inner_tlvlist); aim_tlvlist_free(outer_tlvlist); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs); byte_stream_destroy(&bs); } @@ -1044,17 +794,6 @@ aim_tlvlist_add_noval(&inner_tlvlist, 0x000f); /* TODO: Send 0x0016 and 0x0017 */ -#if 0 - /* TODO: If the following is ever enabled, ensure that it is - * not sent with a receive redirect or stage 3 proxy - * redirect for a file receive (same conditions for - * sending 0x000f above) - */ - aim_tlvlist_add_raw(&inner_tlvlist, 0x000e, 2, "en"); - aim_tlvlist_add_raw(&inner_tlvlist, 0x000d, 8, "us-ascii"); - aim_tlvlist_add_raw(&inner_tlvlist, 0x000c, 24, "Please accept this file."); -#endif - if (filename != NULL) { ByteStream inner_bs; @@ -1083,7 +822,7 @@ aim_tlvlist_free(inner_tlvlist); aim_tlvlist_free(outer_tlvlist); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs); byte_stream_destroy(&bs); } @@ -1136,17 +875,6 @@ aim_tlvlist_add_raw(&inner_tlvlist, 0x0016, 4, ip_comp); aim_tlvlist_add_16(&inner_tlvlist, 0x0017, ~pin); -#if 0 - /* TODO: If the following is ever enabled, ensure that it is - * not sent with a receive redirect or stage 3 proxy - * redirect for a file receive (same conditions for - * sending 0x000f above) - */ - aim_tlvlist_add_raw(&inner_tlvlist, 0x000e, 2, "en"); - aim_tlvlist_add_raw(&inner_tlvlist, 0x000d, 8, "us-ascii"); - aim_tlvlist_add_raw(&inner_tlvlist, 0x000c, 24, "Please accept this file."); -#endif - if (filename != NULL) { ByteStream filename_bs; @@ -1176,530 +904,57 @@ aim_tlvlist_free(inner_tlvlist); aim_tlvlist_free(outer_tlvlist); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs); byte_stream_destroy(&bs); } -/** - * Subtype 0x0006 - Request the status message of the given ICQ user. - * - * @param od The oscar session. - * @param bn The UIN of the user of whom you wish to request info. - * @param type The type of info you wish to request. This should be the current - * state of the user, as one of the AIM_ICQ_STATE_* defines. - * @return Return 0 if no errors, otherwise return the error number. - */ -int aim_im_sendch2_geticqaway(OscarData *od, const char *bn, int type) -{ - FlapConnection *conn; - ByteStream bs; - aim_snacid_t snacid; - guchar cookie[8]; - - if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)) || !bn) - return -EINVAL; - - aim_icbm_makecookie(cookie); - - byte_stream_new(&bs, 8+2+1+strlen(bn) + 4+0x5e + 4); - - snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0); - - /* ICBM header */ - aim_im_puticbm(&bs, cookie, 0x0002, bn); - - /* TLV t(0005) - Encompasses almost everything below. */ - byte_stream_put16(&bs, 0x0005); /* T */ - byte_stream_put16(&bs, 0x005e); /* L */ - { /* V */ - byte_stream_put16(&bs, 0x0000); - - /* Cookie */ - byte_stream_putraw(&bs, cookie, 8); - - /* Put the 16 byte server relay capability */ - byte_stream_putcaps(&bs, OSCAR_CAPABILITY_ICQSERVERRELAY); - - /* TLV t(000a) */ - byte_stream_put16(&bs, 0x000a); - byte_stream_put16(&bs, 0x0002); - byte_stream_put16(&bs, 0x0001); - - /* TLV t(000f) */ - byte_stream_put16(&bs, 0x000f); - byte_stream_put16(&bs, 0x0000); - - /* TLV t(2711) */ - byte_stream_put16(&bs, 0x2711); - byte_stream_put16(&bs, 0x0036); - { /* V */ - byte_stream_putle16(&bs, 0x001b); /* L */ - byte_stream_putle16(&bs, 0x0009); /* Protocol version */ - byte_stream_putcaps(&bs, OSCAR_CAPABILITY_EMPTY); - byte_stream_putle16(&bs, 0x0000); /* Unknown */ - byte_stream_putle16(&bs, 0x0001); /* Client features? */ - byte_stream_putle16(&bs, 0x0000); /* Unknown */ - byte_stream_putle8(&bs, 0x00); /* Unkizown */ - byte_stream_putle16(&bs, 0xffff); /* Sequence number? XXX - This should decrement by 1 with each request */ - - byte_stream_putle16(&bs, 0x000e); /* L */ - byte_stream_putle16(&bs, 0xffff); /* Sequence number? XXX - This should decrement by 1 with each request */ - byte_stream_putle32(&bs, 0x00000000); /* Unknown */ - byte_stream_putle32(&bs, 0x00000000); /* Unknown */ - byte_stream_putle32(&bs, 0x00000000); /* Unknown */ - - /* The type of status message being requested */ - if (type & AIM_ICQ_STATE_CHAT) - byte_stream_putle16(&bs, 0x03ec); - else if(type & AIM_ICQ_STATE_DND) - byte_stream_putle16(&bs, 0x03eb); - else if(type & AIM_ICQ_STATE_OUT) - byte_stream_putle16(&bs, 0x03ea); - else if(type & AIM_ICQ_STATE_BUSY) - byte_stream_putle16(&bs, 0x03e9); - else if(type & AIM_ICQ_STATE_AWAY) - byte_stream_putle16(&bs, 0x03e8); - - byte_stream_putle16(&bs, 0x0001); /* Status? */ - byte_stream_putle16(&bs, 0x0001); /* Priority of this message? */ - byte_stream_putle16(&bs, 0x0001); /* L */ - byte_stream_putle8(&bs, 0x00); /* String of length L */ - } /* End TLV t(2711) */ - } /* End TLV t(0005) */ - - /* TLV t(0003) */ - byte_stream_put16(&bs, 0x0003); - byte_stream_put16(&bs, 0x0000); - - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; -} - -/** - * Subtype 0x0006 - Send an ICQ-esque ICBM. - * - * This can be used to send an ICQ authorization reply (deny or grant). It is the "old way." - * The new way is to use SSI. I like the new way a lot better. This seems like such a hack, - * mostly because it's in network byte order. Figuring this stuff out sometimes takes a while, - * but thats ok, because it gives me time to try to figure out what kind of drugs the AOL people - * were taking when they merged the two protocols. - * - * @param bn The destination buddy name. - * @param type The type of message. 0x0007 for authorization denied. 0x0008 for authorization granted. - * @param message The message you want to send, it should be null terminated. - * @return Return 0 if no errors, otherwise return the error number. - */ -int aim_im_sendch4(OscarData *od, const char *bn, guint16 type, const char *message) +static void +incomingim_ch1_parsemsg(OscarData *od, aim_userinfo_t *userinfo, ByteStream *message, struct aim_incomingim_ch1_args *args) { - FlapConnection *conn; - ByteStream bs; - aim_snacid_t snacid; - guchar cookie[8]; - - if (!od || !(conn = flap_connection_findbygroup(od, 0x0002))) - return -EINVAL; - - if (!bn || !type || !message) - return -EINVAL; - - byte_stream_new(&bs, 8+3+strlen(bn)+12+strlen(message)+1+4); - - snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0); - - aim_icbm_makecookie(cookie); - - /* ICBM header */ - aim_im_puticbm(&bs, cookie, 0x0004, bn); - + PurpleAccount *account = purple_connection_get_account(od->gc); /* - * TLV t(0005) - * - * ICQ data (the UIN and the message). + * We're interested in the inner TLV 0x101, which contains precious, precious message. */ - byte_stream_put16(&bs, 0x0005); - byte_stream_put16(&bs, 4 + 2+2+strlen(message)+1); - - /* - * Your UIN - */ - byte_stream_putuid(&bs, od); - - /* - * TLV t(type) l(strlen(message)+1) v(message+NULL) - */ - byte_stream_putle16(&bs, type); - byte_stream_putle16(&bs, strlen(message)+1); - byte_stream_putraw(&bs, (const guint8 *)message, strlen(message)+1); - - /* - * TLV t(0006) l(0000) v() - */ - byte_stream_put16(&bs, 0x0006); - byte_stream_put16(&bs, 0x0000); - - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; -} + while (byte_stream_bytes_left(message) >= 4) { + guint16 type = byte_stream_get16(message); + guint16 length = byte_stream_get16(message); + if (type == 0x101) { + gchar *msg; + guint16 msglen = length - 4; /* charset + charsubset */ + guint16 charset = byte_stream_get16(message); + byte_stream_advance(message, 2); /* charsubset */ -/* - * XXX - I don't see when this would ever get called... - */ -static int outgoingim(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) -{ - int ret = 0; - aim_rxcallback_t userfunc; - guchar cookie[8]; - guint16 channel; - GSList *tlvlist; - char *bn; - int bnlen; - guint16 icbmflags = 0; - guint8 flag1 = 0, flag2 = 0; - gchar *msg = NULL; - aim_tlv_t *msgblock; - - /* ICBM Cookie. */ - aim_icbm_makecookie(cookie); - - /* Channel ID */ - channel = byte_stream_get16(bs); - - if (channel != 0x01) { - purple_debug_misc("oscar", "icbm: ICBM received on unsupported channel. Ignoring. (chan = %04x)\n", channel); - return 0; + msg = byte_stream_getstr(message, msglen); + args->msg = oscar_decode_im(account, userinfo->bn, charset, msg, msglen); + } else { + byte_stream_advance(message, length); + } } - - bnlen = byte_stream_get8(bs); - bn = byte_stream_getstr(bs, bnlen); - - tlvlist = aim_tlvlist_read(bs); - - if (aim_tlv_gettlv(tlvlist, 0x0003, 1)) - icbmflags |= AIM_IMFLAGS_ACK; - if (aim_tlv_gettlv(tlvlist, 0x0004, 1)) - icbmflags |= AIM_IMFLAGS_AWAY; - - if ((msgblock = aim_tlv_gettlv(tlvlist, 0x0002, 1))) { - ByteStream mbs; - int featurelen, msglen; - - byte_stream_init(&mbs, msgblock->value, msgblock->length); - - byte_stream_get8(&mbs); - byte_stream_get8(&mbs); - for (featurelen = byte_stream_get16(&mbs); featurelen; featurelen--) - byte_stream_get8(&mbs); - byte_stream_get8(&mbs); - byte_stream_get8(&mbs); - - msglen = byte_stream_get16(&mbs) - 4; /* final block length */ - - flag1 = byte_stream_get16(&mbs); - flag2 = byte_stream_get16(&mbs); - - msg = byte_stream_getstr(&mbs, msglen); - } - - if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) - ret = userfunc(od, conn, frame, channel, bn, msg, icbmflags, flag1, flag2); - - g_free(bn); - g_free(msg); - aim_tlvlist_free(tlvlist); - - return ret; } -/* - * Ahh, the joys of nearly ridiculous over-engineering. - * - * Not only do AIM ICBM's support multiple channels. Not only do they - * support multiple character sets. But they support multiple character - * sets / encodings within the same ICBM. - * - * These multipart messages allow for complex space savings techniques, which - * seem utterly unnecessary by today's standards. In fact, there is only - * one client still in popular use that still uses this method: AOL for the - * Macintosh, Version 5.0. Obscure, yes, I know. - * - * In modern (non-"legacy") clients, if the user tries to send a character - * that is not ISO-8859-1 or ASCII, the client will send the entire message - * as UNICODE, meaning that every character in the message will occupy the - * full 16 bit UNICODE field, even if the high order byte would be zero. - * Multipart messages prevent this wasted space by allowing the client to - * only send the characters in UNICODE that need to be sent that way, and - * the rest of the message can be sent in whatever the native character - * set is (probably ASCII). - * - * An important note is that sections will be displayed in the order that - * they appear in the ICBM. There is no facility for merging or rearranging - * sections at run time. So if you have, say, ASCII then UNICODE then ASCII, - * you must supply two ASCII sections with a UNICODE in the middle, and incur - * the associated overhead. - * - * Normally I would have laughed and given a firm 'no' to supporting this - * seldom-used feature, but something is attracting me to it. In the future, - * it may be possible to abuse this to send mixed-media messages to other - * open source clients (like encryption or something) -- see faimtest for - * examples of how to do this. - * - * I would definitely recommend avoiding this feature unless you really - * know what you are doing, and/or you have something neat to do with it. - * - */ -int aim_mpmsg_init(OscarData *od, aim_mpmsg_t *mpm) -{ - - memset(mpm, 0, sizeof(aim_mpmsg_t)); - - return 0; -} - -static int mpmsg_addsection(OscarData *od, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, gchar *data, guint16 datalen) -{ - aim_mpmsg_section_t *sec; - - sec = g_malloc(sizeof(aim_mpmsg_section_t)); - - sec->charset = charset; - sec->charsubset = charsubset; - sec->data = data; - sec->datalen = datalen; - sec->next = NULL; - - if (!mpm->parts) - mpm->parts = sec; - else { - aim_mpmsg_section_t *cur; - - for (cur = mpm->parts; cur->next; cur = cur->next) - ; - cur->next = sec; - } - - mpm->numparts++; - - return 0; -} - -int aim_mpmsg_addraw(OscarData *od, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, const gchar *data, guint16 datalen) -{ - gchar *dup; - - dup = g_malloc(datalen); - memcpy(dup, data, datalen); - - if (mpmsg_addsection(od, mpm, charset, charsubset, dup, datalen) == -1) { - g_free(dup); - return -1; - } - - return 0; -} - -/* XXX - should provide a way of saying ISO-8859-1 specifically */ -int aim_mpmsg_addascii(OscarData *od, aim_mpmsg_t *mpm, const char *ascii) -{ - gchar *dup; - - if (!(dup = g_strdup(ascii))) - return -1; - - if (mpmsg_addsection(od, mpm, 0x0000, 0x0000, dup, strlen(ascii)) == -1) { - g_free(dup); - return -1; - } - - return 0; -} - -int aim_mpmsg_addunicode(OscarData *od, aim_mpmsg_t *mpm, const guint16 *unicode, guint16 unicodelen) -{ - gchar *buf; - ByteStream bs; - int i; - - buf = g_malloc(unicodelen * 2); - - byte_stream_init(&bs, (guchar *)buf, unicodelen * 2); - - /* We assume unicode is in /host/ byte order -- convert to network */ - for (i = 0; i < unicodelen; i++) - byte_stream_put16(&bs, unicode[i]); - - if (mpmsg_addsection(od, mpm, 0x0002, 0x0000, buf, byte_stream_curpos(&bs)) == -1) { - g_free(buf); - return -1; - } - - return 0; -} - -void aim_mpmsg_free(OscarData *od, aim_mpmsg_t *mpm) +static int +incomingim_ch1(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, ByteStream *bs, guint8 *cookie) { - aim_mpmsg_section_t *cur; - - for (cur = mpm->parts; cur; ) { - aim_mpmsg_section_t *tmp; - - tmp = cur->next; - g_free(cur->data); - g_free(cur); - cur = tmp; - } - - mpm->numparts = 0; - mpm->parts = NULL; - - return; -} - -/* - * Start by building the multipart structures, then pick the first - * human-readable section and stuff it into args->msg so no one gets - * suspicious. - */ -static int incomingim_ch1_parsemsgs(OscarData *od, aim_userinfo_t *userinfo, guint8 *data, int len, struct aim_incomingim_ch1_args *args) -{ - /* Should this be ASCII -> UNICODE -> Custom */ - static const guint16 charsetpri[] = { - AIM_CHARSET_ASCII, /* ASCII first */ - AIM_CHARSET_LATIN_1, /* then ISO-8859-1 */ - AIM_CHARSET_UNICODE, /* UNICODE as last resort */ - }; - static const int charsetpricount = 3; - int i; - ByteStream mbs; - aim_mpmsg_section_t *sec; - - byte_stream_init(&mbs, data, len); - - while (byte_stream_empty(&mbs)) { - guint16 msglen, flag1, flag2; - gchar *msgbuf; - - byte_stream_get8(&mbs); /* 01 */ - byte_stream_get8(&mbs); /* 01 */ - - /* Message string length, including character set info. */ - msglen = byte_stream_get16(&mbs); - if (msglen > byte_stream_empty(&mbs)) - { - purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->bn); - break; - } - - /* Character set info */ - flag1 = byte_stream_get16(&mbs); - flag2 = byte_stream_get16(&mbs); - - /* Message. */ - msglen -= 4; - - /* - * For now, we don't care what the encoding is. Just copy - * it into a multipart struct and deal with it later. However, - * always pad the ending with a NULL. This makes it easier - * to treat ASCII sections as strings. It won't matter for - * UNICODE or binary data, as you should never read past - * the specified data length, which will not include the pad. - * - * XXX - There's an API bug here. For sending, the UNICODE is - * given in host byte order (aim_mpmsg_addunicode), but here - * the received messages are given in network byte order. - * - */ - msgbuf = (gchar *)byte_stream_getraw(&mbs, msglen); - mpmsg_addsection(od, &args->mpmsg, flag1, flag2, msgbuf, msglen); - - } /* while */ - - args->icbmflags |= AIM_IMFLAGS_MULTIPART; /* always set */ - - /* - * Clients that support multiparts should never use args->msg, as it - * will point to an arbitrary section. - * - * Here, we attempt to provide clients that do not support multipart - * messages with something to look at -- hopefully a human-readable - * string. But, failing that, a UNICODE message, or nothing at all. - * - * Which means that even if args->msg is NULL, it does not mean the - * message was blank. - * - */ - for (i = 0; i < charsetpricount; i++) { - for (sec = args->mpmsg.parts; sec; sec = sec->next) { - - if (sec->charset != charsetpri[i]) - continue; - - /* Great. We found one. Fill it in. */ - args->charset = sec->charset; - args->charsubset = sec->charsubset; - - /* Set up the simple flags */ - switch (args->charsubset) - { - case 0x0000: - /* standard subencoding? */ - break; - case 0x000b: - args->icbmflags |= AIM_IMFLAGS_SUBENC_MACINTOSH; - break; - case 0xffff: - /* no subencoding */ - break; - default: - break; - } - - args->msg = sec->data; - args->msglen = sec->datalen; - - return 0; - } - } - - /* No human-readable sections found. Oh well. */ - args->charset = args->charsubset = 0xffff; - args->msg = NULL; - args->msglen = 0; - - return 0; -} - -static int incomingim_ch1(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, ByteStream *bs, guint8 *cookie) -{ - guint16 type, length, magic1, msglen = 0; + guint16 type, length; aim_rxcallback_t userfunc; int ret = 0; - int rev = 0; struct aim_incomingim_ch1_args args; unsigned int endpos; memset(&args, 0, sizeof(args)); - aim_mpmsg_init(od, &args.mpmsg); - /* * This used to be done using tlvchains. For performance reasons, * I've changed it to process the TLVs in-place. This avoids lots * of per-IM memory allocations. */ - while (byte_stream_empty(bs) >= 4) + while (byte_stream_bytes_left(bs) >= 4) { type = byte_stream_get16(bs); length = byte_stream_get16(bs); - if (length > byte_stream_empty(bs)) + if (length > byte_stream_bytes_left(bs)) { purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->bn); break; @@ -1708,93 +963,20 @@ endpos = byte_stream_curpos(bs) + length; if (type == 0x0002) { /* Message Block */ - - /* - * This TLV consists of the following: - * - 0501 -- Unknown - * - Features: Don't know how to interpret these - * - 0101 -- Unknown - * - Message - * - * Slick and possible others reverse 'Features' and 'Messages' section. - * Thus, the TLV could have following layout: - * - 0101 -- Unknown (possibly magic for message section) - * - Message - * - 0501 -- Unknown (possibly magic for features section) - * - Features: Don't know how to interpret these - */ - - magic1 = byte_stream_get16(bs); /* 0501 or 0101 */ - if (magic1 == 0x101) /* Bad, message comes before attributes */ - { - /* Jump to the features section */ - msglen = byte_stream_get16(bs); - bs->offset += msglen; - rev = 1; - - magic1 = byte_stream_get16(bs); /* 0501 */ - } - - if (magic1 != 0x501) - { - purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->bn); - break; - } - - args.featureslen = byte_stream_get16(bs); - if (args.featureslen > byte_stream_empty(bs)) - { - purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->bn); - break; - } - if (args.featureslen == 0) - { - args.features = NULL; - } - else - { - args.features = byte_stream_getraw(bs, args.featureslen); - args.icbmflags |= AIM_IMFLAGS_CUSTOMFEATURES; - } - - if (rev) - { - /* Fix buffer back to message */ - bs->offset -= args.featureslen + 2 + 2 + msglen + 2 + 2; - } - - magic1 = byte_stream_get16(bs); /* 01 01 */ - if (magic1 != 0x101) /* Bad, message comes before attributes */ - { - purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->bn); - break; - } - msglen = byte_stream_get16(bs); - - /* - * The rest of the TLV contains one or more message - * blocks... - */ - incomingim_ch1_parsemsgs(od, userinfo, bs->data + bs->offset - 2 - 2 /* XXX evil!!! */, msglen + 2 + 2, &args); - + ByteStream tlv02; + byte_stream_init(&tlv02, bs->data + bs->offset, length); + incomingim_ch1_parsemsg(od, userinfo, &tlv02, &args); } else if (type == 0x0003) { /* Server Ack Requested */ - args.icbmflags |= AIM_IMFLAGS_ACK; - } else if (type == 0x0004) { /* Message is Auto Response */ - args.icbmflags |= AIM_IMFLAGS_AWAY; - } else if (type == 0x0006) { /* Message was received offline. */ - /* * This flag is set on incoming offline messages for both * AIM and ICQ accounts. */ args.icbmflags |= AIM_IMFLAGS_OFFLINE; - } else if (type == 0x0008) { /* I-HAVE-A-REALLY-PURTY-ICON Flag */ - args.iconlen = byte_stream_get32(bs); byte_stream_get16(bs); /* 0x0001 */ args.iconsum = byte_stream_get16(bs); @@ -1812,39 +994,16 @@ */ if (args.iconlen) args.icbmflags |= AIM_IMFLAGS_HASICON; - } else if (type == 0x0009) { - args.icbmflags |= AIM_IMFLAGS_BUDDYREQ; - } else if (type == 0x000b) { /* Non-direct connect typing notification */ - args.icbmflags |= AIM_IMFLAGS_TYPINGNOT; - } else if (type == 0x0016) { - /* * UTC timestamp for when the message was sent. Only * provided for offline messages. */ args.timestamp = byte_stream_get32(bs); - - } else if (type == 0x0017) { - - if (length > byte_stream_empty(bs)) - { - purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->bn); - break; - } - g_free(args.extdata); - args.extdatalen = length; - if (args.extdatalen == 0) - args.extdata = NULL; - else - args.extdata = byte_stream_getraw(bs, args.extdatalen); - - } else { - purple_debug_misc("oscar", "incomingim_ch1: unknown TLV 0x%04x (len %d)\n", type, length); } /* @@ -1862,10 +1021,7 @@ if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, channel, userinfo, &args); - aim_mpmsg_free(od, &args.mpmsg); - g_free(args.features); - g_free(args.extdata); - + g_free(args.msg); return ret; } @@ -1891,7 +1047,7 @@ * ... * ... */ - while (byte_stream_empty(servdata)) + while (byte_stream_bytes_left(servdata)) { guint16 gnlen, numb; int i; @@ -1963,7 +1119,7 @@ static void incomingim_ch2_icqserverrelay_free(OscarData *od, IcbmArgsCh2 *args) { - g_free((char *)args->info.rtfmsg.rtfmsg); + g_free((char *)args->info.rtfmsg.msg); } /* @@ -1977,33 +1133,34 @@ static void incomingim_ch2_icqserverrelay(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, aim_userinfo_t *userinfo, IcbmArgsCh2 *args, ByteStream *servdata) { - guint16 hdrlen, anslen, msglen; + guint16 hdrlen, msglen; + + args->destructor = (void *)incomingim_ch2_icqserverrelay_free; - if (byte_stream_empty(servdata) < 24) - /* Someone sent us a short server relay ICBM. Weird. (Maybe?) */ - return; - - hdrlen = byte_stream_getle16(servdata); - byte_stream_advance(servdata, hdrlen); - - hdrlen = byte_stream_getle16(servdata); +#define SKIP_HEADER(expected_hdrlen) \ + hdrlen = byte_stream_getle16(servdata); \ + if (hdrlen != expected_hdrlen) { \ + purple_debug_warning("oscar", "Expected to find a header with length " #expected_hdrlen "; ignoring message"); \ + return; \ + } \ byte_stream_advance(servdata, hdrlen); - args->info.rtfmsg.msgtype = byte_stream_getle16(servdata); + SKIP_HEADER(0x001b); + SKIP_HEADER(0x000e); - anslen = byte_stream_getle32(servdata); - byte_stream_advance(servdata, anslen); + args->info.rtfmsg.msgtype = byte_stream_get8(servdata); + /* + * Copied from http://iserverd.khstu.ru/oscar/message.html: + * xx byte message flags + * xx xx word (LE) status code + * xx xx word (LE) priority code + * + * We don't need any of these, so just skip them. + */ + byte_stream_advance(servdata, 1 + 2 + 2); msglen = byte_stream_getle16(servdata); - args->info.rtfmsg.rtfmsg = byte_stream_getstr(servdata, msglen); - - args->info.rtfmsg.fgcolor = byte_stream_getle32(servdata); - args->info.rtfmsg.bgcolor = byte_stream_getle32(servdata); - - hdrlen = byte_stream_getle32(servdata); - byte_stream_advance(servdata, hdrlen); - - args->destructor = (void *)incomingim_ch2_icqserverrelay_free; + args->info.rtfmsg.msg = byte_stream_getstr(servdata, msglen); } static void @@ -2188,20 +1345,6 @@ if (aim_tlv_gettlv(list2, 0x000e, 1)) args.language = aim_tlv_getstr(list2, 0x000e, 1); -#if 0 - /* - * Unknown -- no value - * - * Maybe means we should connect directly to transfer the file? - * Also used in ICQ Lite Beta 4.0 URLs. Also empty. - */ - /* I don't think this indicates a direct transfer; this flag is - * also present in a stage 1 proxied file send request -- Jonathan */ - if (aim_tlv_gettlv(list2, 0x000f, 1)) { - /* Unhandled */ - } -#endif - /* * Flag meaning we should proxy the file transfer through an AIM server */ @@ -2396,38 +1539,6 @@ return ret; } -/* - * Subtype 0x0008 - Send a warning to bn. - * - * Flags: - * AIM_WARN_ANON Send as an anonymous (doesn't count as much) - * - * returns -1 on error (couldn't alloc packet), 0 on success. - * - */ -int aim_im_warn(OscarData *od, FlapConnection *conn, const char *bn, guint32 flags) -{ - ByteStream bs; - aim_snacid_t snacid; - - if (!od || !conn || !bn) - return -EINVAL; - - byte_stream_new(&bs, strlen(bn)+3); - - snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0008, 0x0000, bn, strlen(bn)+1); - - byte_stream_put16(&bs, (flags & AIM_WARN_ANON) ? 0x0001 : 0x0000); - byte_stream_put8(&bs, strlen(bn)); - byte_stream_putstr(&bs, bn); - - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0008, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; -} - /* Subtype 0x000a */ static int missedcall(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { @@ -2436,7 +1547,7 @@ guint16 channel, nummissed, reason; aim_userinfo_t userinfo; - while (byte_stream_empty(bs)) { + while (byte_stream_bytes_left(bs)) { channel = byte_stream_get16(bs); aim_info_extract(od, bs, &userinfo); @@ -2456,9 +1567,7 @@ * Subtype 0x000b * * Possible codes: - * AIM_TRANSFER_DENY_NOTSUPPORTED -- "client does not support" * AIM_TRANSFER_DENY_DECLINE -- "client has declined transfer" - * AIM_TRANSFER_DENY_NOTACCEPTING -- "client is not accepting transfers" * */ int aim_im_denytransfer(OscarData *od, const char *bn, const guchar *cookie, guint16 code) @@ -2485,186 +1594,57 @@ aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x000b, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x000b, snacid, &bs); byte_stream_destroy(&bs); return 0; } -static void parse_status_note_text(OscarData *od, guchar *cookie, char *bn, ByteStream *bs) +/* + * Subtype 0x000b. + * Send confirmation for a channel 2 message (Miranda wants it by default). + */ +void +aim_im_send_icq_confirmation(OscarData *od, const char *bn, const guchar *cookie) { - struct aim_icq_info *info; - struct aim_icq_info *prev_info; - char *response; - char *encoding; - char *stripped_encoding; - char *status_note_title; - char *status_note_text; - char *stripped_status_note_text; - char *status_note; - guint32 length; - guint16 version; - guint32 capability; - guint8 message_type; - guint16 status_code; - guint16 text_length; - guint32 request_length; - guint32 response_length; - guint32 encoding_length; - PurpleAccount *account; - PurpleBuddy *buddy; - PurplePresence *presence; - PurpleStatus *status; - - for (prev_info = NULL, info = od->icq_info; info != NULL; prev_info = info, info = info->next) - { - if (memcmp(&info->icbm_cookie, cookie, 8) == 0) - { - if (prev_info == NULL) - od->icq_info = info->next; - else - prev_info->next = info->next; - - break; - } - } - - if (info == NULL) - return; + ByteStream bs; + aim_snacid_t snacid; + guint32 header_size, data_size; + guint16 cookie2 = (guint16)g_random_int(); - status_note_title = info->status_note_title; - g_free(info); - - length = byte_stream_getle16(bs); - if (length != 27) { - purple_debug_misc("oscar", "clientautoresp: incorrect header " - "size; expected 27, received %u.\n", length); - g_free(status_note_title); - return; - } - - version = byte_stream_getle16(bs); - if (version != 9) { - purple_debug_misc("oscar", "clientautoresp: incorrect version; " - "expected 9, received %u.\n", version); - g_free(status_note_title); - return; - } + purple_debug_misc("oscar", "Sending message ack to %s\n", bn); - capability = aim_locate_getcaps(od, bs, 0x10); - if (capability != OSCAR_CAPABILITY_EMPTY) { - purple_debug_misc("oscar", "clientautoresp: plugin ID is not null.\n"); - g_free(status_note_title); - return; - } + header_size = 8 + 2 + 1 + strlen(bn) + 2; + data_size = 2 + 1 + 16 + 4*2 + 2*3 + 4*3 + 1*2 + 2*3 + 1; + byte_stream_new(&bs, header_size + data_size); - byte_stream_advance(bs, 2); /* unknown */ - byte_stream_advance(bs, 4); /* client capabilities flags */ - byte_stream_advance(bs, 1); /* unknown */ - byte_stream_advance(bs, 2); /* downcouner? */ - - length = byte_stream_getle16(bs); - if (length != 14) { - purple_debug_misc("oscar", "clientautoresp: incorrect header " - "size; expected 14, received %u.\n", length); - g_free(status_note_title); - return; - } - - byte_stream_advance(bs, 2); /* downcounter? */ - byte_stream_advance(bs, 12); /* unknown */ + /* The message header. */ + aim_im_puticbm(&bs, cookie, 0x0002, bn); + byte_stream_put16(&bs, 0x0003); /* reason */ - message_type = byte_stream_get8(bs); - if (message_type != 0x1a) { - purple_debug_misc("oscar", "clientautoresp: incorrect message " - "type; expected 0x1a, received 0x%x.\n", message_type); - g_free(status_note_title); - return; - } - - byte_stream_advance(bs, 1); /* message flags */ - - status_code = byte_stream_getle16(bs); - if (status_code != 0) { - purple_debug_misc("oscar", "clientautoresp: incorrect status " - "code; expected 0, received %u.\n", status_code); - g_free(status_note_title); - return; - } - - byte_stream_advance(bs, 2); /* priority code */ - - text_length = byte_stream_getle16(bs); - byte_stream_advance(bs, text_length); /* text */ - - length = byte_stream_getle16(bs); - byte_stream_advance(bs, 18); /* unknown */ - - request_length = byte_stream_getle32(bs); - if (length != 18 + 4 + request_length + 17) { - purple_debug_misc("oscar", "clientautoresp: incorrect block; " - "expected length is %u, got %u.\n", - 18 + 4 + request_length + 17, length); - g_free(status_note_title); - return; - } - - byte_stream_advance(bs, request_length); /* x request */ - byte_stream_advance(bs, 17); /* unknown */ + /* The actual message. */ + byte_stream_putle16(&bs, 0x1b); /* subheader #1 length */ + byte_stream_put8(&bs, 0x08); /* protocol version */ + byte_stream_putcaps(&bs, OSCAR_CAPABILITY_EMPTY); + byte_stream_put32(&bs, 0x3); /* client features */ + byte_stream_put32(&bs, 0x0004); /* DC type */ + byte_stream_put16(&bs, cookie2); /* a cookie, chosen by fair dice roll */ + byte_stream_putle16(&bs, 0x0e); /* header #2 len? */ + byte_stream_put16(&bs, cookie2); /* the same cookie again */ + byte_stream_put32(&bs, 0); /* unknown */ + byte_stream_put32(&bs, 0); /* unknown */ + byte_stream_put32(&bs, 0); /* unknown */ + byte_stream_put8(&bs, 0x01); /* plain text message */ + byte_stream_put8(&bs, 0x00); /* no message flags */ + byte_stream_put16(&bs, 0x0000); /* no icq status */ + byte_stream_put16(&bs, 0x0100); /* priority */ + byte_stream_putle16(&bs, 1); /* query message len */ + byte_stream_put8(&bs, 0x00); /* empty query message */ - length = byte_stream_getle32(bs); - response_length = byte_stream_getle32(bs); - response = byte_stream_getstr(bs, response_length); - encoding_length = byte_stream_getle32(bs); - if (length != 4 + response_length + 4 + encoding_length) { - purple_debug_misc("oscar", "clientautoresp: incorrect block; " - "expected length is %u, got %u.\n", - 4 + response_length + 4 + encoding_length, length); - g_free(status_note_title); - g_free(response); - return; - } - - encoding = byte_stream_getstr(bs, encoding_length); - - account = purple_connection_get_account(od->gc); - - stripped_encoding = oscar_encoding_extract(encoding); - status_note_text = oscar_encoding_to_utf8(account, stripped_encoding, response, response_length); - stripped_status_note_text = purple_markup_strip_html(status_note_text); - - if (stripped_status_note_text != NULL && stripped_status_note_text[0] != 0) - status_note = g_strdup_printf("%s: %s", status_note_title, stripped_status_note_text); - else - status_note = g_strdup(status_note_title); - - g_free(status_note_title); - g_free(response); - g_free(encoding); - g_free(stripped_encoding); - g_free(status_note_text); - g_free(stripped_status_note_text); - - buddy = purple_find_buddy(account, bn); - if (buddy == NULL) - { - purple_debug_misc("oscar", "clientautoresp: buddy %s was not found.\n", bn); - g_free(status_note); - return; - } - - purple_debug_misc("oscar", "clientautoresp: setting status " - "message to \"%s\".\n", status_note); - - presence = purple_buddy_get_presence(buddy); - status = purple_presence_get_active_status(presence); - - purple_prpl_got_user_status(account, bn, - purple_status_get_id(status), - "message", status_note, NULL); - - g_free(status_note); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x000b, 0x0000, NULL, 0); + flap_connection_send_snac(od, flap_connection_findbygroup(od, SNAC_FAMILY_ICBM), SNAC_FAMILY_ICBM, 0x000b, snacid, &bs); + byte_stream_destroy(&bs); } /* @@ -2819,16 +1799,10 @@ } /* - * Subtype 0x000c - Receive an ack after sending an ICBM. - * - * You have to have send the message with the AIM_IMFLAGS_ACK flag set - * (TLV t(0003)). The ack contains the ICBM header of the message you - * sent. - * + * Subtype 0x000c - Receive an ack after sending an ICBM. The ack contains the ICBM header of the message you sent. */ static int msgack(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { - aim_rxcallback_t userfunc; guint16 ch; guchar *cookie; char *bn; @@ -2838,8 +1812,7 @@ ch = byte_stream_get16(bs); bn = byte_stream_getstr(bs, byte_stream_get8(bs)); - if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) - ret = userfunc(od, conn, frame, ch, bn); + purple_debug_info("oscar", "Sent message to %s.\n", bn); g_free(bn); g_free(cookie); @@ -2914,7 +1887,7 @@ */ byte_stream_put16(&bs, event); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0014, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0014, snacid, &bs); byte_stream_destroy(&bs); @@ -3002,7 +1975,7 @@ aim_tlvlist_write(&bs, &outer_tlvlist); purple_debug_misc("oscar", "X-Status Request\n"); - flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs, TRUE); + flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, snacid, &bs, TRUE); aim_tlvlist_free(outer_tlvlist); byte_stream_destroy(&header); @@ -3088,9 +2061,9 @@ aim_im_puticbm(&bs, cookie, 0x0002, sn); byte_stream_put16(&bs, 0x0003); byte_stream_putraw(&bs, plugindata, sizeof(plugindata)); - byte_stream_putraw(&bs, (const guint8 *)statxml, strlen(statxml)); + byte_stream_putraw(&bs, (const guint8*)statxml, strlen(statxml)); - flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x000b, 0x0000, snacid, &bs, TRUE); + flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x000b, snacid, &bs, TRUE); g_free(statxml); g_free(msg); @@ -3135,8 +2108,6 @@ return error(od, conn, mod, frame, snac, bs); else if (snac->subtype == 0x0005) return aim_im_paraminfo(od, conn, mod, frame, snac, bs); - else if (snac->subtype == 0x0006) - return outgoingim(od, conn, mod, frame, snac, bs); else if (snac->subtype == 0x0007) return incomingim(od, conn, mod, frame, snac, bs); else if (snac->subtype == 0x000a) diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_icq.c --- a/libpurple/protocols/oscar/family_icq.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/family_icq.c Fri Aug 20 08:35:27 2010 +0000 @@ -23,77 +23,104 @@ * */ +#include "encoding.h" #include "oscar.h" -#ifdef OLDSTYLE_ICQ_OFFLINEMSGS -int aim_icq_reqofflinemsgs(OscarData *od) -{ - FlapConnection *conn; - ByteStream bs; - aim_snacid_t snacid; - int bslen; +#define AIM_ICQ_INFO_REQUEST 0x04b2 +#define AIM_ICQ_ALIAS_REQUEST 0x04ba - if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ))) - return -EINVAL; +static +int compare_icq_infos(gconstpointer a, gconstpointer b) +{ + const struct aim_icq_info* aa = a; + const guint16* bb = b; + return aa->reqid - *bb; +} - purple_debug_info("oscar", "Requesting offline messages\n"); - - bslen = 2 + 4 + 2 + 2; - - byte_stream_new(&bs, 4 + bslen); +static void aim_icq_freeinfo(struct aim_icq_info *info) { + int i; - snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0); - - /* For simplicity, don't bother using a tlvlist */ - byte_stream_put16(&bs, 0x0001); - byte_stream_put16(&bs, bslen); - - byte_stream_putle16(&bs, bslen - 2); - byte_stream_putuid(&bs, od); - byte_stream_putle16(&bs, 0x003c); /* I command thee. */ - byte_stream_putle16(&bs, snacid); /* eh. */ - - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; + if (!info) + return; + g_free(info->nick); + g_free(info->first); + g_free(info->last); + g_free(info->email); + g_free(info->homecity); + g_free(info->homestate); + g_free(info->homephone); + g_free(info->homefax); + g_free(info->homeaddr); + g_free(info->mobile); + g_free(info->homezip); + g_free(info->personalwebpage); + if (info->email2) + for (i = 0; i < info->numaddresses; i++) + g_free(info->email2[i]); + g_free(info->email2); + g_free(info->workcity); + g_free(info->workstate); + g_free(info->workphone); + g_free(info->workfax); + g_free(info->workaddr); + g_free(info->workzip); + g_free(info->workcompany); + g_free(info->workdivision); + g_free(info->workposition); + g_free(info->workwebpage); + g_free(info->info); + g_free(info->status_note_title); + g_free(info->auth_request_reason); } -int aim_icq_ackofflinemsgs(OscarData *od) +static +int error(OscarData *od, aim_modsnac_t *error_snac, ByteStream *bs) { - ByteStream bs; - FlapFrame *frame; - aim_snacid_t snacid; - int bslen; - - if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ))) - return -EINVAL; - - purple_debug_info("oscar", "Acknowledged receipt of offline messages\n"); - - bslen = 2 + 4 + 2 + 2; - - byte_stream_new(&bs, 4 + bslen); + aim_snac_t *original_snac = aim_remsnac(od, error_snac->id); + guint16 *request_type; + GSList *original_info_ptr; + struct aim_icq_info *original_info; + guint16 reason; + gchar *uin; - snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0); - - /* For simplicity, don't bother using a tlvlist */ - byte_stream_put16(&bs, 0x0001); - byte_stream_put16(&bs, bslen); + if (!original_snac || (original_snac->family != SNAC_FAMILY_ICQ) || !original_snac->data) { + purple_debug_misc("oscar", "icq: the original snac for the error packet was not found"); + g_free(original_snac); + return 0; + } + + request_type = original_snac->data; + original_info_ptr = g_slist_find_custom(od->icq_info, &original_snac->id, compare_icq_infos); + original_info = original_info_ptr->data; + + if (!original_info_ptr) { + purple_debug_misc("oscar", "icq: the request info for the error packet was not found"); + g_free(original_snac); + return 0; + } + + reason = byte_stream_get16(bs); + uin = g_strdup_printf("%u", original_info->uin); + switch (*request_type) { + case AIM_ICQ_INFO_REQUEST: + oscar_user_info_display_error(od, reason, uin); + break; + case AIM_ICQ_ALIAS_REQUEST: + /* Couldn't retrieve an alias for the buddy requesting authorization; have to make do with UIN only. */ + if (original_info->for_auth_request) + oscar_auth_recvrequest(od->gc, uin, NULL, original_info->auth_request_reason); + break; + default: + purple_debug_misc("oscar", "icq: got an error packet with unknown request type %u", *request_type); + break; + } - byte_stream_putle16(&bs, bslen - 2); - byte_stream_putuid(&bs, od); - byte_stream_putle16(&bs, 0x003e); /* I command thee. */ - byte_stream_putle16(&bs, snacid); /* eh. */ - - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; + aim_icq_freeinfo(original_info); + od->icq_info = g_slist_remove(od->icq_info, original_info_ptr); + g_free(original_snac->data); + g_free(original_snac); + return 1; } -#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */ int aim_icq_setsecurity(OscarData *od, gboolean auth_required, gboolean webaware) @@ -130,7 +157,7 @@ byte_stream_putle8(&bs, 0x00); byte_stream_putle8(&bs, !auth_required); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs); byte_stream_destroy(&bs); @@ -180,7 +207,7 @@ byte_stream_putraw(&bs, (const guint8 *)passwd, passwdlen); byte_stream_putle8(&bs, '\0'); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs); byte_stream_destroy(&bs); @@ -194,6 +221,7 @@ aim_snacid_t snacid; int bslen; struct aim_icq_info *info; + guint16 request_type = AIM_ICQ_INFO_REQUEST; if (!uin || uin[0] < '0' || uin[0] > '9') return -EINVAL; @@ -205,7 +233,7 @@ byte_stream_new(&bs, 4 + bslen); - snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, &request_type, sizeof(request_type)); /* For simplicity, don't bother using a tlvlist */ byte_stream_put16(&bs, 0x0001); @@ -215,10 +243,10 @@ byte_stream_putuid(&bs, od); byte_stream_putle16(&bs, 0x07d0); /* I command thee. */ byte_stream_putle16(&bs, snacid); /* eh. */ - byte_stream_putle16(&bs, 0x04b2); /* shrug. */ + byte_stream_putle16(&bs, request_type); /* shrug. */ byte_stream_putle32(&bs, atoi(uin)); - flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE); + flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs, FALSE); byte_stream_destroy(&bs); @@ -226,19 +254,19 @@ info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1); info->reqid = snacid; info->uin = atoi(uin); - info->next = od->icq_info; - od->icq_info = info; + od->icq_info = g_slist_prepend(od->icq_info, info); return 0; } -int aim_icq_getalias(OscarData *od, const char *uin) +int aim_icq_getalias(OscarData *od, const char *uin, gboolean for_auth_request, char *auth_request_reason) { FlapConnection *conn; ByteStream bs; aim_snacid_t snacid; int bslen; struct aim_icq_info *info; + guint16 request_type = AIM_ICQ_ALIAS_REQUEST; if (!uin || uin[0] < '0' || uin[0] > '9') return -EINVAL; @@ -252,7 +280,7 @@ byte_stream_new(&bs, 4 + bslen); - snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0); + snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, &request_type, sizeof(request_type)); /* For simplicity, don't bother using a tlvlist */ byte_stream_put16(&bs, 0x0001); @@ -262,10 +290,10 @@ byte_stream_putuid(&bs, od); byte_stream_putle16(&bs, 0x07d0); /* I command thee. */ byte_stream_putle16(&bs, snacid); /* eh. */ - byte_stream_putle16(&bs, 0x04ba); /* shrug. */ + byte_stream_putle16(&bs, request_type); /* shrug. */ byte_stream_putle32(&bs, atoi(uin)); - flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE); + flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs, FALSE); byte_stream_destroy(&bs); @@ -273,89 +301,13 @@ info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1); info->reqid = snacid; info->uin = atoi(uin); - info->next = od->icq_info; - od->icq_info = info; + info->for_auth_request = for_auth_request; + info->auth_request_reason = g_strdup(auth_request_reason); + od->icq_info = g_slist_prepend(od->icq_info, info); return 0; } -int aim_icq_getsimpleinfo(OscarData *od, const char *uin) -{ - FlapConnection *conn; - ByteStream bs; - aim_snacid_t snacid; - int bslen; - - if (!uin || uin[0] < '0' || uin[0] > '9') - return -EINVAL; - - if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ))) - return -EINVAL; - - bslen = 2 + 4 + 2 + 2 + 2 + 4; - - byte_stream_new(&bs, 4 + bslen); - - snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0); - - /* For simplicity, don't bother using a tlvlist */ - byte_stream_put16(&bs, 0x0001); - byte_stream_put16(&bs, bslen); - - byte_stream_putle16(&bs, bslen - 2); - byte_stream_putuid(&bs, od); - byte_stream_putle16(&bs, 0x07d0); /* I command thee. */ - byte_stream_putle16(&bs, snacid); /* eh. */ - byte_stream_putle16(&bs, 0x051f); /* shrug. */ - byte_stream_putle32(&bs, atoi(uin)); - - flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE); - - byte_stream_destroy(&bs); - - return 0; -} - -#if 0 -int aim_icq_sendxmlreq(OscarData *od, const char *xml) -{ - FlapConnection *conn; - ByteStream bs; - aim_snacid_t snacid; - int bslen; - - if (!xml || !strlen(xml)) - return -EINVAL; - - if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ))) - return -EINVAL; - - bslen = 2 + 10 + 2 + strlen(xml) + 1; - - byte_stream_new(&bs, 4 + bslen); - - snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0); - - /* For simplicity, don't bother using a tlvlist */ - byte_stream_put16(&bs, 0x0001); - byte_stream_put16(&bs, bslen); - - byte_stream_putle16(&bs, bslen - 2); - byte_stream_putuid(&bs, od); - byte_stream_putle16(&bs, 0x07d0); /* I command thee. */ - byte_stream_putle16(&bs, snacid); /* eh. */ - byte_stream_putle16(&bs, 0x0998); /* shrug. */ - byte_stream_putle16(&bs, strlen(xml) + 1); - byte_stream_putraw(&bs, (guint8 *)xml, strlen(xml) + 1); - - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; -} -#endif - /* * Send an SMS message. This is the non-US way. The US-way is to IM * their cell phone number (+19195551234). @@ -446,7 +398,7 @@ byte_stream_putstr(&bs, xml); byte_stream_put8(&bs, 0x00); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs); byte_stream_destroy(&bs); @@ -456,49 +408,35 @@ return 0; } -static void aim_icq_freeinfo(struct aim_icq_info *info) { - int i; +static int +gotalias(OscarData *od, struct aim_icq_info *info) +{ + PurpleConnection *gc = od->gc; + PurpleAccount *account = purple_connection_get_account(gc); + gchar who[16], *utf8; + PurpleBuddy *b; - if (!info) - return; - g_free(info->nick); - g_free(info->first); - g_free(info->last); - g_free(info->email); - g_free(info->homecity); - g_free(info->homestate); - g_free(info->homephone); - g_free(info->homefax); - g_free(info->homeaddr); - g_free(info->mobile); - g_free(info->homezip); - g_free(info->personalwebpage); - if (info->email2) - for (i = 0; i < info->numaddresses; i++) - g_free(info->email2[i]); - g_free(info->email2); - g_free(info->workcity); - g_free(info->workstate); - g_free(info->workphone); - g_free(info->workfax); - g_free(info->workaddr); - g_free(info->workzip); - g_free(info->workcompany); - g_free(info->workdivision); - g_free(info->workposition); - g_free(info->workwebpage); - g_free(info->info); - g_free(info->status_note_title); - g_free(info); + if (info->nick[0] && (utf8 = oscar_utf8_try_convert(account, od, info->nick))) { + if (info->for_auth_request) { + oscar_auth_recvrequest(gc, g_strdup_printf("%u", info->uin), utf8, info->auth_request_reason); + } else { + g_snprintf(who, sizeof(who), "%u", info->uin); + serv_got_alias(gc, who, utf8); + if ((b = purple_find_buddy(account, who))) { + purple_blist_node_set_string((PurpleBlistNode*)b, "servernick", utf8); + } + g_free(utf8); + } + } + return 1; } /** * Subtype 0x0003 - Response to SNAC_FAMILY_ICQ/0x002, contains an ICQesque packet. */ static int -icqresponse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) +icqresponse(OscarData *od, aim_modsnac_t *snac, ByteStream *bs) { - int ret = 0; GSList *tlvlist; aim_tlv_t *datatlv; ByteStream qbs; @@ -520,53 +458,23 @@ purple_debug_misc("oscar", "icq response: %d bytes, %u, 0x%04x, 0x%04x\n", cmdlen, ouruin, cmd, reqid); - if (cmd == 0x0041) { /* offline message */ -#ifdef OLDSTYLE_ICQ_OFFLINEMSGS - struct aim_icq_offlinemsg msg; - aim_rxcallback_t userfunc; - - memset(&msg, 0, sizeof(msg)); - - msg.sender = byte_stream_getle32(&qbs); - msg.year = byte_stream_getle16(&qbs); - msg.month = byte_stream_getle8(&qbs); - msg.day = byte_stream_getle8(&qbs); - msg.hour = byte_stream_getle8(&qbs); - msg.minute = byte_stream_getle8(&qbs); - msg.type = byte_stream_getle8(&qbs); - msg.flags = byte_stream_getle8(&qbs); - msg.msglen = byte_stream_getle16(&qbs); - msg.msg = byte_stream_getstr(&qbs, msg.msglen); - - if ((userfunc = aim_callhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_OFFLINEMSG))) - ret = userfunc(od, conn, frame, &msg); - - g_free(msg.msg); - - } else if (cmd == 0x0042) { - aim_rxcallback_t userfunc; - - if ((userfunc = aim_callhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_OFFLINEMSGCOMPLETE))) - ret = userfunc(od, conn, frame); -#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */ - - } else if (cmd == 0x07da) { /* information */ + if (cmd == 0x07da) { /* information */ guint16 subtype; + GSList *info_ptr; struct aim_icq_info *info; - aim_rxcallback_t userfunc; subtype = byte_stream_getle16(&qbs); byte_stream_advance(&qbs, 1); /* 0x0a */ /* find other data from the same request */ - for (info = od->icq_info; info && (info->reqid != reqid); info = info->next); - if (!info) { - info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1); - info->reqid = reqid; - info->next = od->icq_info; - od->icq_info = info; + info_ptr = g_slist_find_custom(od->icq_info, &reqid, compare_icq_infos); + if (!info_ptr) { + struct aim_icq_info *new_info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1); + new_info->reqid = reqid; + info_ptr = od->icq_info = g_slist_prepend(od->icq_info, new_info); } + info = info_ptr->data; switch (subtype) { case 0x00a0: { /* hide ip status */ /* nothing */ @@ -818,10 +726,9 @@ memcpy(&info->icbm_cookie, cookie, 8); - info->next = od->icq_info; - od->icq_info = info; + od->icq_info = g_slist_prepend(od->icq_info, info); - flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs, FALSE); + flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, snacid, &bs, FALSE); byte_stream_destroy(&bs); } @@ -834,35 +741,28 @@ if (!(snac->flags & 0x0001)) { if (subtype != 0x0104) - if ((userfunc = aim_callhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_INFO))) - ret = userfunc(od, conn, frame, info); + oscar_user_info_display_icq(od, info); if (info->uin && info->nick) - if ((userfunc = aim_callhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_ALIAS))) - ret = userfunc(od, conn, frame, info); + gotalias(od, info); - if (od->icq_info == info) { - od->icq_info = info->next; - } else { - struct aim_icq_info *cur; - for (cur=od->icq_info; (cur->next && (cur->next!=info)); cur=cur->next); - if (cur->next) - cur->next = cur->next->next; - } aim_icq_freeinfo(info); + od->icq_info = g_slist_remove(od->icq_info, info); } } aim_tlvlist_free(tlvlist); - return ret; + return 1; } static int snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { - if (snac->subtype == 0x0003) - return icqresponse(od, conn, mod, frame, snac, bs); + if (snac->subtype == 0x0001) + return error(od, snac, bs); + else if (snac->subtype == 0x0003) + return icqresponse(od, snac, bs); return 0; } @@ -870,15 +770,10 @@ static void icq_shutdown(OscarData *od, aim_module_t *mod) { - struct aim_icq_info *del; - - while (od->icq_info) { - del = od->icq_info; - od->icq_info = od->icq_info->next; - aim_icq_freeinfo(del); - } - - return; + GSList *cur; + for (cur = od->icq_info; cur; cur = cur->next) + aim_icq_freeinfo(cur->data); + g_slist_free(od->icq_info); } int diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_invite.c --- a/libpurple/protocols/oscar/family_invite.c Fri Aug 20 08:34:12 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * Purple's oscar protocol plugin - * This file is the legal property of its developers. - * Please see the AUTHORS file distributed alongside this file. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA -*/ - -/* - * Family 0x0006 - This isn't really ever used by anyone anymore. - * - * Once upon a time, there used to be a menu item in AIM clients that - * said something like "Invite a friend to use AIM..." and then it would - * ask for an email address and it would sent a mail to them saying - * how perfectly wonderful the AIM service is and why you should use it - * and click here if you hate the person who sent this to you and want to - * complain and yell at them in a small box with pretty fonts. - * - * I could've sworn libfaim had this implemented once, a long long time ago, - * but I can't find it. - * - * I'm mainly adding this so that I can keep advertising that we support - * group 6, even though we don't. - * - */ - -#include "oscar.h" - -int invite_modfirst(OscarData *od, aim_module_t *mod) -{ - - mod->family = SNAC_FAMILY_INVITE; - mod->version = 0x0001; - mod->toolid = 0x0110; - mod->toolversion = 0x0629; - mod->flags = 0; - strncpy(mod->name, "invite", sizeof(mod->name)); - mod->snachandler = NULL; - - return 0; -} diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_locate.c --- a/libpurple/protocols/oscar/family_locate.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/family_locate.c Fri Aug 20 08:35:27 2010 +0000 @@ -245,6 +245,10 @@ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {OSCAR_CAPABILITY_HTML_MSGS, + {0x01, 0x38, 0xca, 0x7b, 0x76, 0x9a, 0x49, 0x15, + 0x88, 0xf2, 0x13, 0xfc, 0x00, 0x97, 0x9e, 0xa8}}, + {OSCAR_CAPABILITY_LAST, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, @@ -583,7 +587,7 @@ guint64 flags = 0; int offset; - for (offset = 0; byte_stream_empty(bs) && (offset < len); offset += 0x10) { + for (offset = 0; byte_stream_bytes_left(bs) && (offset < len); offset += 0x10) { guint8 *cap; int i, identified; @@ -617,7 +621,7 @@ int offset; const char *result = NULL; - for (offset = 0; byte_stream_empty(bs) && (offset < len); offset += 0x10) { + for (offset = 0; byte_stream_bytes_left(bs) && (offset < len); offset += 0x10) { /* check wheather this capability is a custom user icon */ guint8 *cap; int i; @@ -643,7 +647,7 @@ guint64 flags = 0; int offset; - for (offset = 0; byte_stream_empty(bs) && (offset < len); offset += 0x02) { + for (offset = 0; byte_stream_bytes_left(bs) && (offset < len); offset += 0x02) { guint8 *cap; int i, identified; @@ -674,16 +678,13 @@ if (!bs) return -EINVAL; - for (i = 0; byte_stream_empty(bs); i++) { - + for (i = 0; byte_stream_bytes_left(bs); i++) { if (aim_caps[i].flag == OSCAR_CAPABILITY_LAST) break; if (caps & aim_caps[i].flag) byte_stream_putraw(bs, aim_caps[i].data, 0x10); - } - return 0; } @@ -804,7 +805,7 @@ type = byte_stream_get16(bs); length = byte_stream_get16(bs); curpos = byte_stream_curpos(bs); - endpos = curpos + MIN(length, byte_stream_empty(bs)); + endpos = curpos + MIN(length, byte_stream_bytes_left(bs)); if (type == 0x0001) { /* @@ -1010,7 +1011,7 @@ number2 = byte_stream_get8(bs); length2 = byte_stream_get8(bs); - endpos2 = byte_stream_curpos(bs) + MIN(length2, byte_stream_empty(bs)); + endpos2 = byte_stream_curpos(bs) + MIN(length2, byte_stream_bytes_left(bs)); switch (type2) { case 0x0000: { /* This is an official buddy icon? */ @@ -1165,68 +1166,12 @@ return 0; } -/* Apparently, this is never called. - * If you activate it, figure out a way to know what mood to pass to - * aim_tlvlist_add_caps() below. --rlaager */ -#if 0 -/* - * Inverse of aim_info_extract() - */ -int -aim_putuserinfo(ByteStream *bs, aim_userinfo_t *info) -{ - GSList *tlvlist = NULL; - - if (!bs || !info) - return -EINVAL; - - byte_stream_put8(bs, strlen(info->bn)); - byte_stream_putstr(bs, info->bn); - - byte_stream_put16(bs, info->warnlevel); - - if (info->present & AIM_USERINFO_PRESENT_FLAGS) - aim_tlvlist_add_16(&tlvlist, 0x0001, info->flags); - if (info->present & AIM_USERINFO_PRESENT_MEMBERSINCE) - aim_tlvlist_add_32(&tlvlist, 0x0002, info->membersince); - if (info->present & AIM_USERINFO_PRESENT_ONLINESINCE) - aim_tlvlist_add_32(&tlvlist, 0x0003, info->onlinesince); - if (info->present & AIM_USERINFO_PRESENT_IDLE) - aim_tlvlist_add_16(&tlvlist, 0x0004, info->idletime); - -/* XXX - So, ICQ_OSCAR_SUPPORT is never defined anywhere... */ -#ifdef ICQ_OSCAR_SUPPORT - if (atoi(info->bn) != 0) { - if (info->present & AIM_USERINFO_PRESENT_ICQEXTSTATUS) - aim_tlvlist_add_16(&tlvlist, 0x0006, info->icqinfo.status); - if (info->present & AIM_USERINFO_PRESENT_ICQIPADDR) - aim_tlvlist_add_32(&tlvlist, 0x000a, info->icqinfo.ipaddr); - } -#endif - - if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES) { - aim_tlvlist_add_caps(&tlvlist, 0x000d, info->capabilities, NULL); - } - - if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN) - aim_tlvlist_add_32(&tlvlist, (guint16)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen); - - byte_stream_put16(bs, aim_tlvlist_count(tlvlist)); - aim_tlvlist_write(bs, &tlvlist); - aim_tlvlist_free(tlvlist); - - return 0; -} -#endif - /* * Subtype 0x0001 */ static int error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { - int ret = 0; - aim_rxcallback_t userfunc; aim_snac_t *snac2; guint16 reason; char *bn; @@ -1253,14 +1198,12 @@ reason = byte_stream_get16(bs); - /* Notify the user that we do not have info for this buddy */ - if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) - ret = userfunc(od, conn, frame, reason, bn); + oscar_user_info_display_error(od, reason, bn); g_free(snac2->data); g_free(snac2); - return ret; + return 1; } /* @@ -1390,7 +1333,7 @@ aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); - flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, snacid, &bs); byte_stream_destroy(&bs); @@ -1424,41 +1367,7 @@ aim_tlvlist_write(&bs, &tlvlist); aim_tlvlist_free(tlvlist); - flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; -} - -/* - * Subtype 0x0005 - Request info of another AIM user. - * - * @param bn The buddy name whose info you wish to request. - * @param infotype The type of info you wish to request. - * 0x0001 - Info/profile - * 0x0003 - Away message - * 0x0004 - Capabilities - */ -int -aim_locate_getinfo(OscarData *od, const char *bn, guint16 infotype) -{ - FlapConnection *conn; - ByteStream bs; - aim_snacid_t snacid; - - if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !bn) - return -EINVAL; - - byte_stream_new(&bs, 2+1+strlen(bn)); - - snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0005, 0x0000, NULL, 0); - - byte_stream_put16(&bs, infotype); - byte_stream_put8(&bs, strlen(bn)); - byte_stream_putstr(&bs, bn); - - flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0005, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, snacid, &bs); byte_stream_destroy(&bs); @@ -1470,7 +1379,6 @@ userinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { int ret = 0; - aim_rxcallback_t userfunc; aim_userinfo_t *userinfo, *userinfo2; GSList *tlvlist; aim_tlv_t *tlv = NULL; @@ -1522,140 +1430,12 @@ g_free(userinfo); /* Show the info to the user */ - if (userinfo2 != NULL && ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))) - ret = userfunc(od, conn, frame, userinfo2); + oscar_user_info_display_aim(od, userinfo2); return ret; } /* - * Subtype 0x0009 - Set directory profile data. - * - * This is not the same as aim_location_setprofile! - * privacy: 1 to allow searching, 0 to disallow. - * - */ -int aim_locate_setdirinfo(OscarData *od, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, guint16 privacy) -{ - FlapConnection *conn; - ByteStream bs; - aim_snacid_t snacid; - GSList *tlvlist = NULL; - - if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE))) - return -EINVAL; - - aim_tlvlist_add_16(&tlvlist, 0x000a, privacy); - - if (first) - aim_tlvlist_add_str(&tlvlist, 0x0001, first); - if (last) - aim_tlvlist_add_str(&tlvlist, 0x0002, last); - if (middle) - aim_tlvlist_add_str(&tlvlist, 0x0003, middle); - if (maiden) - aim_tlvlist_add_str(&tlvlist, 0x0004, maiden); - - if (state) - aim_tlvlist_add_str(&tlvlist, 0x0007, state); - if (city) - aim_tlvlist_add_str(&tlvlist, 0x0008, city); - - if (nickname) - aim_tlvlist_add_str(&tlvlist, 0x000c, nickname); - if (zip) - aim_tlvlist_add_str(&tlvlist, 0x000d, zip); - - if (street) - aim_tlvlist_add_str(&tlvlist, 0x0021, street); - - byte_stream_new(&bs, aim_tlvlist_size(tlvlist)); - - snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0009, 0x0000, NULL, 0); - - aim_tlvlist_write(&bs, &tlvlist); - aim_tlvlist_free(tlvlist); - - flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0009, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; -} - -/* - * Subtype 0x000b - Huh? What is this? - */ -int aim_locate_000b(OscarData *od, const char *bn) -{ - FlapConnection *conn; - ByteStream bs; - aim_snacid_t snacid; - - return -EINVAL; - - if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !bn) - return -EINVAL; - - byte_stream_new(&bs, 1+strlen(bn)); - - snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x000b, 0x0000, NULL, 0); - - byte_stream_put8(&bs, strlen(bn)); - byte_stream_putstr(&bs, bn); - - flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x000b, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; -} - -/* - * Subtype 0x000f - * - * XXX pass these in better - * - */ -int -aim_locate_setinterests(OscarData *od, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, guint16 privacy) -{ - FlapConnection *conn; - ByteStream bs; - aim_snacid_t snacid; - GSList *tlvlist = NULL; - - if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE))) - return -EINVAL; - - /* ?? privacy ?? */ - aim_tlvlist_add_16(&tlvlist, 0x000a, privacy); - - if (interest1) - aim_tlvlist_add_str(&tlvlist, 0x0000b, interest1); - if (interest2) - aim_tlvlist_add_str(&tlvlist, 0x0000b, interest2); - if (interest3) - aim_tlvlist_add_str(&tlvlist, 0x0000b, interest3); - if (interest4) - aim_tlvlist_add_str(&tlvlist, 0x0000b, interest4); - if (interest5) - aim_tlvlist_add_str(&tlvlist, 0x0000b, interest5); - - byte_stream_new(&bs, aim_tlvlist_size(tlvlist)); - - snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x000f, 0x0000, NULL, 0); - - aim_tlvlist_write(&bs, &tlvlist); - aim_tlvlist_free(tlvlist); - - flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x000f, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - return 0; -} - -/* * Subtype 0x0015 - Request the info of a user using the short method. This is * what iChat uses. It normally is VERY leniently rate limited. * @@ -1683,7 +1463,7 @@ byte_stream_putstr(&bs, bn); snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, bn, strlen(bn)+1); - flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, snacid, &bs, FALSE); + flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_LOCATE, 0x0015, snacid, &bs, FALSE); byte_stream_destroy(&bs); @@ -1731,15 +1511,6 @@ return 0; } -#if 0 //rlaager -const char* aim_get_custom_icon_mood(gint32 no) -{ - if (no >= G_N_ELEMENTS(aim_custom_icons) || no < 1) - return NULL; - return aim_custom_icons[no].mood.mood; -} -#endif - const char* icq_get_custom_icon_description(const char *mood) { diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_odir.c --- a/libpurple/protocols/oscar/family_odir.c Fri Aug 20 08:34:12 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,264 +0,0 @@ -/* - * Purple's oscar protocol plugin - * This file is the legal property of its developers. - * Please see the AUTHORS file distributed alongside this file. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA -*/ - -/* - * Family 0x000f - Newer Search Method - * - * Used for searching for other AIM users by email address, name, - * location, commmon interests, and a few other similar things. - * - */ - -#include "oscar.h" - -/** - * Subtype 0x0002 - Submit a User Search Request - * - * Search for an AIM buddy based on their email address. - * - * @param od The oscar session. - * @param region Should be "us-ascii" unless you know what you're doing. - * @param email The email address you want to search for. - * @return Return 0 if no errors, otherwise return the error number. - */ -int aim_odir_email(OscarData *od, const char *region, const char *email) -{ - FlapConnection *conn; - ByteStream bs; - aim_snacid_t snacid; - GSList *tlvlist = NULL; - - if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ODIR)) || !region || !email) - return -EINVAL; - - /* Create a TLV chain, write it to the outgoing frame, then free the chain */ - aim_tlvlist_add_str(&tlvlist, 0x001c, region); - aim_tlvlist_add_16(&tlvlist, 0x000a, 0x0001); /* Type of search */ - aim_tlvlist_add_str(&tlvlist, 0x0005, email); - - byte_stream_new(&bs, aim_tlvlist_size(tlvlist)); - - aim_tlvlist_write(&bs, &tlvlist); - aim_tlvlist_free(tlvlist); - - snacid = aim_cachesnac(od, SNAC_FAMILY_ODIR, 0x0002, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ODIR, 0x0002, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; -} - - -/** - * Subtype 0x0002 - Submit a User Search Request - * - * Search for an AIM buddy based on various info - * about the person. - * - * @param od The oscar session. - * @param region Should be "us-ascii" unless you know what you're doing. - * @param first The first name of the person you want to search for. - * @param middle The middle name of the person you want to search for. - * @param last The last name of the person you want to search for. - * @param maiden The maiden name of the person you want to search for. - * @param nick The nick name of the person you want to search for. - * @param city The city where the person you want to search for resides. - * @param state The state where the person you want to search for resides. - * @param country The country where the person you want to search for resides. - * @param zip The zip code where the person you want to search for resides. - * @param address The street address where the person you want to seach for resides. - * @return Return 0 if no errors, otherwise return the error number. - */ -int aim_odir_name(OscarData *od, const char *region, const char *first, const char *middle, const char *last, const char *maiden, const char *nick, const char *city, const char *state, const char *country, const char *zip, const char *address) -{ - FlapConnection *conn; - ByteStream bs; - aim_snacid_t snacid; - GSList *tlvlist = NULL; - - if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ODIR)) || !region) - return -EINVAL; - - /* Create a TLV chain, write it to the outgoing frame, then free the chain */ - aim_tlvlist_add_str(&tlvlist, 0x001c, region); - aim_tlvlist_add_16(&tlvlist, 0x000a, 0x0000); /* Type of search */ - if (first) - aim_tlvlist_add_str(&tlvlist, 0x0001, first); - if (last) - aim_tlvlist_add_str(&tlvlist, 0x0002, last); - if (middle) - aim_tlvlist_add_str(&tlvlist, 0x0003, middle); - if (maiden) - aim_tlvlist_add_str(&tlvlist, 0x0004, maiden); - if (country) - aim_tlvlist_add_str(&tlvlist, 0x0006, country); - if (state) - aim_tlvlist_add_str(&tlvlist, 0x0007, state); - if (city) - aim_tlvlist_add_str(&tlvlist, 0x0008, city); - if (nick) - aim_tlvlist_add_str(&tlvlist, 0x000c, nick); - if (zip) - aim_tlvlist_add_str(&tlvlist, 0x000d, zip); - if (address) - aim_tlvlist_add_str(&tlvlist, 0x0021, address); - - byte_stream_new(&bs, aim_tlvlist_size(tlvlist)); - - aim_tlvlist_write(&bs, &tlvlist); - aim_tlvlist_free(tlvlist); - - snacid = aim_cachesnac(od, SNAC_FAMILY_ODIR, 0x0002, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ODIR, 0x0002, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; -} - - -/** - * Subtype 0x0002 - Submit a User Search Request - * - * @param od The oscar session. - * @param interest1 An interest you want to search for. - * @return Return 0 if no errors, otherwise return the error number. - */ -int aim_odir_interest(OscarData *od, const char *region, const char *interest) -{ - FlapConnection *conn; - ByteStream bs; - aim_snacid_t snacid; - GSList *tlvlist = NULL; - - if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ODIR)) || !region) - return -EINVAL; - - /* Create a TLV chain, write it to the outgoing frame, then free the chain */ - aim_tlvlist_add_str(&tlvlist, 0x001c, region); - aim_tlvlist_add_16(&tlvlist, 0x000a, 0x0001); /* Type of search */ - if (interest) - aim_tlvlist_add_str(&tlvlist, 0x0001, interest); - - byte_stream_new(&bs, aim_tlvlist_size(tlvlist)); - - aim_tlvlist_write(&bs, &tlvlist); - aim_tlvlist_free(tlvlist); - - snacid = aim_cachesnac(od, SNAC_FAMILY_ODIR, 0x0002, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_ODIR, 0x0002, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); - - return 0; -} - - -/** - * Subtype 0x0003 - Receive Reply From a User Search - * - */ -static int parseresults(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) -{ - int ret = 0; - aim_rxcallback_t userfunc; - guint16 tmp, numresults; - struct aim_odir *results = NULL; - - tmp = byte_stream_get16(bs); /* Unknown */ - tmp = byte_stream_get16(bs); /* Unknown */ - byte_stream_advance(bs, tmp); - - numresults = byte_stream_get16(bs); /* Number of results to follow */ - - /* Allocate a linked list, 1 node per result */ - while (numresults) { - struct aim_odir *new; - GSList *tlvlist = aim_tlvlist_readnum(bs, byte_stream_get16(bs)); - new = (struct aim_odir *)g_malloc(sizeof(struct aim_odir)); - new->first = aim_tlv_getstr(tlvlist, 0x0001, 1); - new->last = aim_tlv_getstr(tlvlist, 0x0002, 1); - new->middle = aim_tlv_getstr(tlvlist, 0x0003, 1); - new->maiden = aim_tlv_getstr(tlvlist, 0x0004, 1); - new->email = aim_tlv_getstr(tlvlist, 0x0005, 1); - new->country = aim_tlv_getstr(tlvlist, 0x0006, 1); - new->state = aim_tlv_getstr(tlvlist, 0x0007, 1); - new->city = aim_tlv_getstr(tlvlist, 0x0008, 1); - new->bn = aim_tlv_getstr(tlvlist, 0x0009, 1); - new->interest = aim_tlv_getstr(tlvlist, 0x000b, 1); - new->nick = aim_tlv_getstr(tlvlist, 0x000c, 1); - new->zip = aim_tlv_getstr(tlvlist, 0x000d, 1); - new->region = aim_tlv_getstr(tlvlist, 0x001c, 1); - new->address = aim_tlv_getstr(tlvlist, 0x0021, 1); - new->next = results; - results = new; - numresults--; - } - - if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) - ret = userfunc(od, conn, frame, results); - - /* Now free everything from above */ - while (results) { - struct aim_odir *del = results; - results = results->next; - g_free(del->first); - g_free(del->last); - g_free(del->middle); - g_free(del->maiden); - g_free(del->email); - g_free(del->country); - g_free(del->state); - g_free(del->city); - g_free(del->bn); - g_free(del->interest); - g_free(del->nick); - g_free(del->zip); - g_free(del->region); - g_free(del->address); - g_free(del); - } - - return ret; -} - -static int -snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) -{ - if (snac->subtype == 0x0003) - return parseresults(od, conn, mod, frame, snac, bs); - - return 0; -} - -int -odir_modfirst(OscarData *od, aim_module_t *mod) -{ - mod->family = SNAC_FAMILY_ODIR; - mod->version = 0x0001; - mod->toolid = 0x0010; - mod->toolversion = 0x0629; - mod->flags = 0; - strncpy(mod->name, "odir", sizeof(mod->name)); - mod->snachandler = snachandler; - - return 0; -} diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_oservice.c --- a/libpurple/protocols/oscar/family_oservice.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/family_oservice.c Fri Aug 20 08:35:27 2010 +0000 @@ -73,7 +73,7 @@ } snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0002, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0002, snacid, &bs); byte_stream_destroy(&bs); } @@ -97,7 +97,7 @@ { int group; - while (byte_stream_empty(bs)) + while (byte_stream_bytes_left(bs)) { group = byte_stream_get16(bs); conn->groups = g_slist_prepend(conn->groups, GUINT_TO_POINTER(group)); @@ -141,7 +141,7 @@ aim_tlvlist_free(tlvlist); snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0004, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0004, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0004, snacid, &bs); byte_stream_destroy(&bs); } @@ -187,7 +187,7 @@ aim_tlvlist_free(tlvlist); snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0004, 0x0000, &csi, sizeof(csi)); - flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0004, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0004, snacid, &bs); byte_stream_destroy(&bs); @@ -444,30 +444,7 @@ } snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0008, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0008, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); -} - -/* Subtype 0x0009 - Delete Rate Parameter */ -void -aim_srv_rates_delparam(OscarData *od, FlapConnection *conn) -{ - ByteStream bs; - aim_snacid_t snacid; - GSList *tmp; - - byte_stream_new(&bs, 502); - - for (tmp = conn->rateclasses; tmp != NULL; tmp = tmp->next) - { - struct rateclass *rateclass; - rateclass = tmp->data; - byte_stream_put16(&bs, rateclass->classid); - } - - snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0009, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0009, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0008, snacid, &bs); byte_stream_destroy(&bs); } @@ -558,40 +535,6 @@ return ret; } -/* - * Subtype 0x000c - Service Pause Acknowledgement - * - * It is rather important that aim_srv_sendpauseack() gets called for the exact - * same connection that the Server Pause callback was called for, since - * libfaim extracts the data for the SNAC from the connection structure. - * - * Of course, if you don't do that, more bad things happen than just what - * libfaim can cause. - * - */ -void -aim_srv_sendpauseack(OscarData *od, FlapConnection *conn) -{ - ByteStream bs; - aim_snacid_t snacid; - GSList *cur; - - byte_stream_new(&bs, 1014); - - /* - * This list should have all the groups that the original - * Host Online / Server Ready said this host supports. And - * we want them all back after the migration. - */ - for (cur = conn->groups; cur != NULL; cur = cur->next) - byte_stream_put16(&bs, GPOINTER_TO_UINT(cur->data)); - - snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x000c, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x000c, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); -} - /* Subtype 0x000d - Service Resume */ static int serverresume(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) @@ -643,7 +586,7 @@ newevil = byte_stream_get16(bs); - if (byte_stream_empty(bs)) + if (byte_stream_bytes_left(bs)) aim_info_extract(od, bs, &userinfo); if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) @@ -770,36 +713,6 @@ } /* - * Subtype 0x0014 - Set privacy flags - * - * Normally 0x03. - * - * Bit 1: Allows other AIM users to see how long you've been idle. - * Bit 2: Allows other AIM users to see how long you've been a member. - * - */ -void -aim_srv_setprivacyflags(OscarData *od, FlapConnection *conn, guint32 flags) -{ - aim_genericreq_l(od, conn, SNAC_FAMILY_OSERVICE, 0x0014, &flags); -} - -/* - * Subtype 0x0016 - No-op - * - * WinAIM sends these every 4min or so to keep the connection alive. Its not - * really necessary. - * - * Wha? No? Since when? I think WinAIM sends an empty channel 5 - * FLAP as a no-op... - */ -void -aim_srv_nop(OscarData *od, FlapConnection *conn) -{ - aim_genericreq_n(od, conn, SNAC_FAMILY_OSERVICE, 0x0016); -} - -/* * Subtype 0x0017 - Set client versions * * If you've seen the clientonline/clientready SNAC you're probably @@ -837,7 +750,7 @@ } snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0017, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0017, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0017, snacid, &bs); byte_stream_destroy(&bs); } @@ -850,8 +763,8 @@ guint8 *versions; /* This is frivolous. (Thank you SmarterChild.) */ - vercount = byte_stream_empty(bs)/4; - versions = byte_stream_getraw(bs, byte_stream_empty(bs)); + vercount = byte_stream_bytes_left(bs)/4; + versions = byte_stream_getraw(bs, byte_stream_bytes_left(bs)); g_free(versions); /* @@ -899,16 +812,6 @@ AIM_ICQ_STATE_HIDEIP | AIM_ICQ_STATE_DIRECTREQUIREAUTH); } -#if 0 - if (other_stuff_that_isnt_implemented) - { - aim_tlvlist_add_raw(&tlvlist, 0x000c, 0x0025, - chunk_of_x25_bytes_with_ip_address_etc); - aim_tlvlist_add_raw(&tlvlist, 0x0011, 0x0005, unknown 0x01 61 10 f6 41); - aim_tlvlist_add_16(&tlvlist, 0x0012, unknown 0x00 00); - } -#endif - if (setstatusmsg) { size_t statusmsglen, itmsurllen; @@ -932,13 +835,57 @@ aim_tlvlist_free(tlvlist); snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x001e, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x001e, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x001e, snacid, &bs); byte_stream_destroy(&bs); return 0; } +/* Send dummy DC (direct connect) information to the server. + * Direct connect is ICQ's counterpart for AIM's DirectIM, + * as far as I can tell. Anyway, we don't support it; + * the reason to send this packet is that some clients + * (Miranda, QIP) won't send us channel 2 ICBM messages + * unless we specify DC version >= 8. + * + * See #12044 for more information. + */ +void +aim_srv_set_dc_info(OscarData *od) +{ + ByteStream bs, tlv0c; + aim_snacid_t snacid; + GSList *tlvlist = NULL; + + /* http://iserverd.khstu.ru/oscar/snac_01_1e.html has a nice analysis of what goes in 0xc tlv. + * Kopete sends a dummy DC info, too, so I just copied the values from them. + */ + byte_stream_new(&tlv0c, 4*2 + 1 + 2 + 4*6 + 2); + byte_stream_put32(&tlv0c, 0x0); + byte_stream_put32(&tlv0c, 0x0); + byte_stream_put8(&tlv0c, 0x0); /* We don't support DC */ + byte_stream_put16(&tlv0c, 8); /* DC version */ + byte_stream_put32(&tlv0c, 0x0); + byte_stream_put32(&tlv0c, 0x50); + byte_stream_put32(&tlv0c, 0x3); + byte_stream_put32(&tlv0c, 0x0); + byte_stream_put32(&tlv0c, 0x0); + byte_stream_put32(&tlv0c, 0x0); + byte_stream_put16(&tlv0c, 0x0); + aim_tlvlist_add_raw(&tlvlist, 0x000c, byte_stream_curpos(&tlv0c), tlv0c.data); + byte_stream_destroy(&tlv0c); + + byte_stream_new(&bs, aim_tlvlist_size(tlvlist)); + aim_tlvlist_write(&bs, &tlvlist); + aim_tlvlist_free(tlvlist); + + snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x001e, 0x0000, NULL, 0); + flap_connection_send_snac(od, flap_connection_findbygroup(od, SNAC_FAMILY_ICBM), SNAC_FAMILY_OSERVICE, 0x001e, snacid, &bs); + + byte_stream_destroy(&bs); +} + /** * 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. @@ -1077,7 +1024,7 @@ } snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0020, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0020, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0020, snacid, &bs); byte_stream_destroy(&bs); diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_translate.c --- a/libpurple/protocols/oscar/family_translate.c Fri Aug 20 08:34:12 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Purple's oscar protocol plugin - * This file is the legal property of its developers. - * Please see the AUTHORS file distributed alongside this file. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA -*/ - -/* - * Family 0x000c - Translation. - * - * I have no idea why this group was issued. I have never seen anything - * that uses it. From what I remember, the last time I tried to poke at - * the server with this group, it whined about not supporting it. - * - * But we advertise it anyway, because its fun. - * - */ - -#include "oscar.h" - -int translate_modfirst(OscarData *od, aim_module_t *mod) -{ - - mod->family = SNAC_FAMILY_TRANSLATE; - mod->version = 0x0001; - mod->toolid = 0x0104; - mod->toolversion = 0x0001; - mod->flags = 0; - strncpy(mod->name, "translate", sizeof(mod->name)); - mod->snachandler = NULL; - - return 0; -} diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/family_userlookup.c --- a/libpurple/protocols/oscar/family_userlookup.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/family_userlookup.c Fri Aug 20 08:35:27 2010 +0000 @@ -75,7 +75,7 @@ byte_stream_putstr(&bs, address); snacid = aim_cachesnac(od, SNAC_FAMILY_USERLOOKUP, 0x0002, 0x0000, address, strlen(address)+1); - flap_connection_send_snac(od, conn, SNAC_FAMILY_USERLOOKUP, 0x0002, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, SNAC_FAMILY_USERLOOKUP, 0x0002, snacid, &bs); byte_stream_destroy(&bs); diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/flap_connection.c --- a/libpurple/protocols/oscar/flap_connection.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/flap_connection.c Fri Aug 20 08:35:27 2010 +0000 @@ -212,7 +212,7 @@ * only if all high priority SNACs have been sent. */ void -flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data, gboolean high_priority) +flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data, gboolean high_priority) { FlapFrame *frame; guint32 length; @@ -222,7 +222,7 @@ length = data != NULL ? data->offset : 0; frame = flap_frame_new(od, 0x02, 10 + length); - aim_putsnac(&frame->data, family, subtype, flags, snacid); + aim_putsnac(&frame->data, family, subtype, snacid); if (length > 0) { @@ -284,9 +284,9 @@ } void -flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data) +flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data) { - flap_connection_send_snac_with_priority(od, conn, family, subtype, flags, snacid, data, TRUE); + flap_connection_send_snac_with_priority(od, conn, family, subtype, snacid, data, TRUE); } /** @@ -733,7 +733,7 @@ aim_module_t *cur; aim_modsnac_t snac; - if (byte_stream_empty(&frame->data) < 10) + if (byte_stream_bytes_left(&frame->data) < 10) return; snac.family = byte_stream_get16(&frame->data); @@ -800,7 +800,7 @@ GSList *tlvlist; char *msg = NULL; - if (byte_stream_empty(&frame->data) == 0) { + if (byte_stream_bytes_left(&frame->data) == 0) { /* XXX should do something with this */ return; } @@ -931,18 +931,6 @@ break; } - /* Verify the sequence number sent by the server. */ -#if 0 - /* TODO: Need to initialize conn->seqnum_in somewhere before we can use this. */ - if (aimutil_get16(&conn->header[1]) != conn->seqnum_in++) - { - /* Received an out-of-order FLAP! */ - flap_connection_schedule_destroy(conn, - OSCAR_DISCONNECT_INVALID_DATA, NULL); - break; - } -#endif - /* Initialize a new temporary FlapFrame for incoming data */ conn->buffer_incoming.channel = aimutil_get8(&conn->header[1]); conn->buffer_incoming.seqnum = aimutil_get16(&conn->header[2]); @@ -1074,8 +1062,8 @@ return; /* Make sure we don't send past the end of the bs */ - if (count > byte_stream_empty(bs)) - count = byte_stream_empty(bs); /* truncate to remaining space */ + if (count > byte_stream_bytes_left(bs)) + count = byte_stream_bytes_left(bs); /* truncate to remaining space */ if (count == 0) return; diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/libaim.c --- a/libpurple/protocols/oscar/libaim.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/libaim.c Fri Aug 20 08:35:27 2010 +0000 @@ -25,6 +25,7 @@ */ #include "oscarcommon.h" +#include "oscar.h" static PurplePluginProtocolInfo prpl_info = { @@ -57,7 +58,7 @@ oscar_add_deny, /* add_deny */ oscar_rem_permit, /* rem_permit */ oscar_rem_deny, /* rem_deny */ - oscar_set_permit_deny, /* set_permit_deny */ + oscar_set_aim_permdeny, /* set_permit_deny */ oscar_join_chat, /* join_chat */ NULL, /* reject_chat */ oscar_get_chat_name, /* get_chat_name */ diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/libicq.c --- a/libpurple/protocols/oscar/libicq.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/libicq.c Fri Aug 20 08:35:27 2010 +0000 @@ -63,11 +63,11 @@ NULL, /* add_buddies */ oscar_remove_buddy, /* remove_buddy */ NULL, /* remove_buddies */ - oscar_add_permit, /* add_permit */ + NULL, /* add_permit */ oscar_add_deny, /* add_deny */ - oscar_rem_permit, /* rem_permit */ + NULL, /* rem_permit */ oscar_rem_deny, /* rem_deny */ - oscar_set_permit_deny, /* set_permit_deny */ + NULL, /* set_permit_deny */ oscar_join_chat, /* join_chat */ NULL, /* reject_chat */ oscar_get_chat_name, /* get_chat_name */ diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/misc.c --- a/libpurple/protocols/oscar/misc.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/misc.c Fri Aug 20 08:35:27 2010 +0000 @@ -41,7 +41,7 @@ { aim_snacid_t snacid = 0x00000000; - flap_connection_send_snac(od, conn, family, subtype, 0x0000, snacid, NULL); + flap_connection_send_snac(od, conn, family, subtype, snacid, NULL); } void @@ -51,7 +51,7 @@ snacid = aim_cachesnac(od, family, subtype, 0x0000, NULL, 0); - flap_connection_send_snac(od, conn, family, subtype, 0x0000, snacid, NULL); + flap_connection_send_snac(od, conn, family, subtype, snacid, NULL); } void @@ -72,30 +72,7 @@ byte_stream_put32(&bs, *longdata); - flap_connection_send_snac(od, conn, family, subtype, 0x0000, snacid, &bs); - - byte_stream_destroy(&bs); -} - -void -aim_genericreq_s(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint16 *shortdata) -{ - ByteStream bs; - aim_snacid_t snacid; - - if (!shortdata) - { - aim_genericreq_n(od, conn, family, subtype); - return; - } - - byte_stream_new(&bs, 2); - - snacid = aim_cachesnac(od, family, subtype, 0x0000, NULL, 0); - - byte_stream_put16(&bs, *shortdata); - - flap_connection_send_snac(od, conn, family, subtype, 0x0000, snacid, &bs); + flap_connection_send_snac(od, conn, family, subtype, snacid, &bs); byte_stream_destroy(&bs); } @@ -114,7 +91,7 @@ snac2 = aim_remsnac(od, snac->id); - if (byte_stream_empty(bs)) + if (byte_stream_bytes_left(bs)) error = byte_stream_get16(bs); if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/msgcookie.c --- a/libpurple/protocols/oscar/msgcookie.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/msgcookie.c Fri Aug 20 08:35:27 2010 +0000 @@ -177,18 +177,3 @@ return 0; } - -/* XXX I hate switch */ -int aim_msgcookie_gettype(guint64 type) -{ - /* XXX: hokey-assed. needs fixed. */ - switch(type) { - case OSCAR_CAPABILITY_BUDDYICON: return AIM_COOKIETYPE_OFTICON; - case OSCAR_CAPABILITY_TALK: return AIM_COOKIETYPE_OFTVOICE; - case OSCAR_CAPABILITY_DIRECTIM: return AIM_COOKIETYPE_OFTIMAGE; - case OSCAR_CAPABILITY_CHAT: return AIM_COOKIETYPE_CHAT; - case OSCAR_CAPABILITY_GETFILE: return AIM_COOKIETYPE_OFTGET; - case OSCAR_CAPABILITY_SENDFILE: return AIM_COOKIETYPE_OFTSEND; - default: return AIM_COOKIETYPE_UNKNOWN; - } -} diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/odc.c --- a/libpurple/protocols/oscar/odc.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/odc.c Fri Aug 20 08:35:27 2010 +0000 @@ -19,6 +19,7 @@ */ /* From the oscar PRPL */ +#include "encoding.h" #include "oscar.h" #include "peer.h" @@ -89,7 +90,7 @@ ByteStream bs; purple_debug_info("oscar", "Outgoing ODC frame to %s with " - "type=0x%04x, flags=0x%04x, payload length=%u\n", + "type=0x%04x, flags=0x%04x, payload length=%" G_GSIZE_FORMAT "\n", conn->bn, frame->type, frame->flags, frame->payload.len); account = purple_connection_get_account(conn->od->gc); @@ -366,8 +367,7 @@ g_datalist_clear(&attributes); /* Append the message up to the tag */ - utf8 = purple_plugin_oscar_decode_im_part(account, conn->bn, - encoding, 0x0000, tmp, start - tmp); + utf8 = oscar_decode_im(account, conn->bn, encoding, tmp, start - tmp); if (utf8 != NULL) { g_string_append(newmsg, utf8); g_free(utf8); @@ -386,8 +386,7 @@ /* Append any remaining message data */ if (tmp <= msgend) { - utf8 = purple_plugin_oscar_decode_im_part(account, conn->bn, - encoding, 0x0000, tmp, msgend - tmp); + utf8 = oscar_decode_im(account, conn->bn, encoding, tmp, msgend - tmp); if (utf8 != NULL) { g_string_append(newmsg, utf8); g_free(utf8); @@ -506,7 +505,7 @@ byte_stream_getrawbuf(bs, frame->bn, 32); purple_debug_info("oscar", "Incoming ODC frame from %s with " - "type=0x%04x, flags=0x%04x, payload length=%u\n", + "type=0x%04x, flags=0x%04x, payload length=%" G_GSIZE_FORMAT "\n", frame->bn, frame->type, frame->flags, frame->payload.len); if (!conn->ready) diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/oscar.c --- a/libpurple/protocols/oscar/oscar.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/oscar.c Fri Aug 20 08:35:27 2010 +0000 @@ -37,6 +37,7 @@ #include "conversation.h" #include "core.h" #include "debug.h" +#include "encoding.h" #include "imgstore.h" #include "network.h" #include "notify.h" @@ -46,27 +47,12 @@ #include "request.h" #include "util.h" #include "version.h" +#include "visibility.h" #include "oscarcommon.h" #include "oscar.h" #include "peer.h" -#define OSCAR_STATUS_ID_INVISIBLE "invisible" -#define OSCAR_STATUS_ID_OFFLINE "offline" -#define OSCAR_STATUS_ID_AVAILABLE "available" -#define OSCAR_STATUS_ID_AWAY "away" -#define OSCAR_STATUS_ID_DND "dnd" -#define OSCAR_STATUS_ID_NA "na" -#define OSCAR_STATUS_ID_OCCUPIED "occupied" -#define OSCAR_STATUS_ID_FREE4CHAT "free4chat" -#define OSCAR_STATUS_ID_CUSTOM "custom" -#define OSCAR_STATUS_ID_MOBILE "mobile" -#define OSCAR_STATUS_ID_EVIL "evil" -#define OSCAR_STATUS_ID_DEPRESSION "depression" -#define OSCAR_STATUS_ID_ATHOME "athome" -#define OSCAR_STATUS_ID_ATWORK "atwork" -#define OSCAR_STATUS_ID_LUNCH "lunch" - #define AIMHASHDATA "http://pidgin.im/aim_data.php3" #define OSCAR_CONNECT_STEPS 6 @@ -82,7 +68,8 @@ | OSCAR_CAPABILITY_TYPING | OSCAR_CAPABILITY_ICQSERVERRELAY | OSCAR_CAPABILITY_NEWCAPS - | OSCAR_CAPABILITY_XTRAZ; + | OSCAR_CAPABILITY_XTRAZ + | OSCAR_CAPABILITY_HTML_MSGS; static guint8 features_aim[] = {0x01, 0x01, 0x01, 0x02}; static guint8 features_icq[] = {0x01}; @@ -99,35 +86,6 @@ char *who; }; -/* - * Various PRPL-specific buddy info that we want to keep track of - * Some other info is maintained by locate.c, and I'd like to move - * the rest of this to libfaim, mostly im.c - * - * TODO: More of this should use the status API. - */ -struct buddyinfo { - gboolean typingnot; - guint32 ipaddr; - - unsigned long ico_me_len; - unsigned long ico_me_csum; - time_t ico_me_time; - gboolean ico_informed; - - unsigned long ico_len; - unsigned long ico_csum; - time_t ico_time; - gboolean ico_need; - gboolean ico_sent; -}; - -struct name_data { - PurpleConnection *gc; - gchar *name; - gchar *nick; -}; - /* All the libfaim->purple callback functions */ /* Only used when connecting with the old-style BUCP login */ @@ -143,7 +101,6 @@ static int purple_parse_incoming_im(OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_parse_misses (OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_parse_clientauto (OscarData *, FlapConnection *, FlapFrame *, ...); -static int purple_parse_userinfo (OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_parse_motd (OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_chatnav_info (OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_conv_chat_join (OscarData *, FlapConnection *, FlapFrame *, ...); @@ -152,8 +109,6 @@ static int purple_conv_chat_incoming_msg(OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_email_parseupdate(OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_icon_parseicon (OscarData *, FlapConnection *, FlapFrame *, ...); -static int purple_parse_msgack (OscarData *, FlapConnection *, FlapFrame *, ...); -static int purple_parse_evilnotify (OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_parse_searcherror(OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_parse_searchreply(OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_bosrights (OscarData *, FlapConnection *, FlapFrame *, ...); @@ -161,16 +116,9 @@ static int purple_parse_mtn (OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_parse_locaterights(OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_parse_buddyrights(OscarData *, FlapConnection *, FlapFrame *, ...); -static int purple_parse_locerr (OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_parse_genericerr (OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_memrequest (OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_selfinfo (OscarData *, FlapConnection *, FlapFrame *, ...); -#ifdef OLDSTYLE_ICQ_OFFLINEMSGS -static int purple_offlinemsg (OscarData *, FlapConnection *, FlapFrame *, ...); -static int purple_offlinemsgdone (OscarData *, FlapConnection *, FlapFrame *, ...); -#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */ -static int purple_icqalias (OscarData *, FlapConnection *, FlapFrame *, ...); -static int purple_icqinfo (OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_popup (OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_ssi_parseerr (OscarData *, FlapConnection *, FlapFrame *, ...); static int purple_ssi_parserights (OscarData *, FlapConnection *, FlapFrame *, ...); @@ -186,10 +134,10 @@ void oscar_set_info(PurpleConnection *gc, const char *info); static void oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *rawinfo, gboolean setstatus, PurpleStatus *status); -static void oscar_set_extendedstatus(PurpleConnection *gc); +static void oscar_set_extended_status(PurpleConnection *gc); static gboolean purple_ssi_rerequestdata(gpointer data); -static void oscar_free_name_data(struct name_data *data) { +void oscar_free_name_data(struct name_data *data) { g_free(data->name); g_free(data->nick); g_free(data); @@ -204,536 +152,6 @@ } #endif -/** - * 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. - */ -static guint32 -oscar_charset_check(const char *utf8) -{ - int i = 0; - int charset = AIM_CHARSET_ASCII; - - /* - * Can we get away with using our custom encoding? - */ - while (utf8[i]) - { - if ((unsigned char)utf8[i] > 0x7f) { - /* not ASCII! */ - charset = AIM_CHARSET_LATIN_1; - break; - } - i++; - } - - /* - * Must we send this message as UNICODE (in the UTF-16BE encoding)? - */ - 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; - } - charset = AIM_CHARSET_UNICODE; - break; - } - - return charset; -} - -/** - * Take a string of the form charset="bleh" where bleh is - * one of us-ascii, utf-8, iso-8859-1, or unicode-2-0, and - * return a newly allocated string containing bleh. - */ -gchar * -oscar_encoding_extract(const char *encoding) -{ - gchar *ret = NULL; - char *begin, *end; - - g_return_val_if_fail(encoding != NULL, NULL); - - /* Make sure encoding begins with charset= */ - if (strncmp(encoding, "text/aolrtf; charset=", 21) && - strncmp(encoding, "text/x-aolrtf; charset=", 23) && - strncmp(encoding, "text/plain; charset=", 20)) - { - 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; -} - -gchar * -oscar_encoding_to_utf8(PurpleAccount *account, const char *encoding, const char *text, int textlen) -{ - gchar *utf8 = NULL; - - if ((encoding == NULL) || encoding[0] == '\0') { - purple_debug_info("oscar", "Empty encoding, assuming UTF-8\n"); - } else if (!g_ascii_strcasecmp(encoding, "iso-8859-1")) { - utf8 = g_convert(text, textlen, "UTF-8", "iso-8859-1", NULL, NULL, NULL); - } else if (!g_ascii_strcasecmp(encoding, "ISO-8859-1-Windows-3.1-Latin-1") || - !g_ascii_strcasecmp(encoding, "us-ascii")) - { - utf8 = g_convert(text, textlen, "UTF-8", "Windows-1252", NULL, NULL, NULL); - } else if (!g_ascii_strcasecmp(encoding, "unicode-2-0")) { - /* Some official ICQ clients are apparently total crack, - * and have been known to save a UTF-8 string converted - * from the locale character set to UTF-16 (not from UTF-8 - * to UTF-16!) in the away message. This hack should find - * and do something (un)reasonable with that, and not - * mess up too much else. */ - const gchar *charset = purple_account_get_string(account, "encoding", NULL); - if (charset) { - gsize len; - utf8 = g_convert(text, textlen, charset, "UTF-16BE", &len, NULL, NULL); - if (!utf8 || len != textlen || !g_utf8_validate(utf8, -1, NULL)) { - g_free(utf8); - utf8 = NULL; - } else { - purple_debug_info("oscar", "Used broken ICQ fallback encoding\n"); - } - } - if (!utf8) - utf8 = g_convert(text, textlen, "UTF-8", "UTF-16BE", NULL, NULL, NULL); - } else if (g_ascii_strcasecmp(encoding, "utf-8")) { - purple_debug_warning("oscar", "Unrecognized character encoding \"%s\", " - "attempting to convert to UTF-8 anyway\n", encoding); - utf8 = g_convert(text, textlen, "UTF-8", encoding, NULL, NULL, NULL); - } - - /* - * If utf8 is still NULL then either the encoding is 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 == NULL) { - if (textlen != 0 && *text != '\0' - && !g_utf8_validate(text, textlen, NULL)) - utf8 = g_strdup(_("(There was an error receiving this message. The buddy you are speaking with is probably using a different encoding than expected. If you know what encoding he is using, you can specify it in the advanced account options for your AIM/ICQ account.)")); - else - utf8 = g_strndup(text, textlen); - } - - return utf8; -} - -static gchar * -oscar_utf8_try_convert(PurpleAccount *account, OscarData *od, const gchar *msg) -{ - const char *charset = NULL; - char *ret = NULL; - - if (od->icq) - charset = purple_account_get_string(account, "encoding", NULL); - - if(charset && *charset) - ret = g_convert(msg, -1, "UTF-8", charset, NULL, NULL, NULL); - - if(!ret) - ret = purple_utf8_try_convert(msg); - - return ret; -} - -static gchar * -purple_plugin_oscar_convert_to_utf8(const gchar *data, gsize datalen, const char *charsetstr, gboolean fallback) -{ - gchar *ret = NULL; - GError *err = NULL; - - if ((charsetstr == NULL) || (*charsetstr == '\0')) - return NULL; - - if (g_ascii_strcasecmp("UTF-8", charsetstr)) { - if (fallback) - ret = g_convert_with_fallback(data, datalen, "UTF-8", charsetstr, "?", NULL, NULL, &err); - else - ret = g_convert(data, datalen, "UTF-8", charsetstr, NULL, NULL, &err); - if (err != NULL) { - purple_debug_warning("oscar", "Conversion from %s failed: %s.\n", - charsetstr, err->message); - g_error_free(err); - } - } else { - if (g_utf8_validate(data, datalen, NULL)) - ret = g_strndup(data, datalen); - else - purple_debug_warning("oscar", "String is not valid UTF-8.\n"); - } - - return ret; -} - -/** - * This attemps to decode an incoming IM into a UTF8 string. - * - * We try decoding using two different character sets. The charset - * specified in the IM determines the order in which we attempt to - * decode. We do this because there are lots of broken ICQ clients - * that don't correctly send non-ASCII messages. And if Purple isn't - * able to deal with that crap, then people complain like banshees. - * charsetstr1 is always set to what the correct encoding should be. - */ -gchar * -purple_plugin_oscar_decode_im_part(PurpleAccount *account, const char *sourcebn, guint16 charset, guint16 charsubset, const gchar *data, gsize datalen) -{ - gchar *ret = NULL; - const gchar *charsetstr1, *charsetstr2, *charsetstr3 = NULL; - - if ((datalen == 0) || (data == NULL)) - return NULL; - - if (charset == AIM_CHARSET_UNICODE) { - charsetstr1 = "UTF-16BE"; - charsetstr2 = "UTF-8"; - } else if (charset == AIM_CHARSET_LATIN_1) { - if ((sourcebn != NULL) && oscar_util_valid_name_icq(sourcebn)) - charsetstr1 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING); - else - charsetstr1 = "ISO-8859-1"; - charsetstr2 = "UTF-8"; - } else if (charset == AIM_CHARSET_ASCII) { - /* Should just be "ASCII" */ - charsetstr1 = "ASCII"; - charsetstr2 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING); - } else if (charset == 0x000d) { - /* iChat sending unicode over a Direct IM connection = UTF-8 */ - /* Mobile AIM client on multiple devices (including Blackberry Tour, Nokia 3100, and LG VX6000) = ISO-8859-1 */ - charsetstr1 = "UTF-8"; - charsetstr2 = "ISO-8859-1"; - charsetstr3 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING); - } else { - /* Unknown, hope for valid UTF-8... */ - charsetstr1 = "UTF-8"; - charsetstr2 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING); - } - - purple_debug_info("oscar", "Parsing IM part, charset=0x%04hx, charsubset=0x%04hx, datalen=%" G_GSIZE_FORMAT ", choice1=%s, choice2=%s, choice3=%s\n", - charset, charsubset, datalen, charsetstr1, charsetstr2, (charsetstr3 ? charsetstr3 : "")); - - ret = purple_plugin_oscar_convert_to_utf8(data, datalen, charsetstr1, FALSE); - if (ret == NULL) { - if (charsetstr3 != NULL) { - /* Try charsetstr2 without allowing substitutions, then fall through to charsetstr3 if needed */ - ret = purple_plugin_oscar_convert_to_utf8(data, datalen, charsetstr2, FALSE); - if (ret == NULL) - ret = purple_plugin_oscar_convert_to_utf8(data, datalen, charsetstr3, TRUE); - } else { - /* Try charsetstr2, allowing substitutions */ - ret = purple_plugin_oscar_convert_to_utf8(data, datalen, charsetstr2, TRUE); - } - } - if (ret == NULL) { - char *str, *salvage, *tmp; - - str = g_malloc(datalen + 1); - strncpy(str, data, datalen); - str[datalen] = '\0'; - salvage = purple_utf8_salvage(str); - tmp = g_strdup_printf(_("(There was an error receiving this message. Either you and %s have different encodings selected, or %s has a buggy client.)"), - sourcebn, sourcebn); - ret = g_strdup_printf("%s %s", salvage, tmp); - g_free(tmp); - g_free(str); - g_free(salvage); - } - - return ret; -} - -/** - * Figure out what encoding to use when sending a given outgoing message. - */ -static void -purple_plugin_oscar_convert_to_best_encoding(PurpleConnection *gc, - const char *destbn, const gchar *from, - gchar **msg, int *msglen_int, - guint16 *charset, guint16 *charsubset) -{ - OscarData *od = purple_connection_get_protocol_data(gc); - PurpleAccount *account = purple_connection_get_account(gc); - GError *err = NULL; - aim_userinfo_t *userinfo = NULL; - const gchar *charsetstr; - gsize msglen; - - /* Attempt to send as ASCII */ - if (oscar_charset_check(from) == AIM_CHARSET_ASCII) { - *msg = g_convert(from, -1, "ASCII", "UTF-8", NULL, &msglen, NULL); - *charset = AIM_CHARSET_ASCII; - *charsubset = 0x0000; - *msglen_int = msglen; - return; - } - - /* - * If we're sending to an ICQ user, and they are in our - * buddy list, and they are advertising the Unicode - * capability, and they are online, then attempt to send - * as UTF-16BE. - */ - if ((destbn != NULL) && oscar_util_valid_name_icq(destbn)) - userinfo = aim_locate_finduserinfo(od, destbn); - - if ((userinfo != NULL) && (userinfo->capabilities & OSCAR_CAPABILITY_UNICODE)) - { - PurpleBuddy *b; - b = purple_find_buddy(account, destbn); - if ((b != NULL) && (PURPLE_BUDDY_IS_ONLINE(b))) - { - *msg = g_convert(from, -1, "UTF-16BE", "UTF-8", NULL, &msglen, &err); - if (*msg != NULL) - { - *charset = AIM_CHARSET_UNICODE; - *charsubset = 0x0000; - *msglen_int = msglen; - return; - } - - purple_debug_error("oscar", "Conversion from UTF-8 to UTF-16BE failed: %s.\n", - err->message); - g_error_free(err); - err = NULL; - } - } - - /* - * If this is AIM then attempt to send as ISO-8859-1. If this is - * ICQ then attempt to send as the user specified character encoding. - */ - charsetstr = "ISO-8859-1"; - if ((destbn != NULL) && oscar_util_valid_name_icq(destbn)) - charsetstr = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING); - - /* - * XXX - We need a way to only attempt to convert if we KNOW "from" - * can be converted to "charsetstr" - */ - *msg = g_convert(from, -1, charsetstr, "UTF-8", NULL, &msglen, &err); - if (*msg != NULL) { - *charset = AIM_CHARSET_LATIN_1; - *charsubset = 0x0000; - *msglen_int = msglen; - return; - } - - purple_debug_info("oscar", "Conversion from UTF-8 to %s failed (%s). Falling back to unicode.\n", - charsetstr, err->message); - g_error_free(err); - err = NULL; - - /* - * Nothing else worked, so send as UTF-16BE. - */ - *msg = g_convert(from, -1, "UTF-16BE", "UTF-8", NULL, &msglen, &err); - if (*msg != NULL) { - *charset = AIM_CHARSET_UNICODE; - *charsubset = 0x0000; - *msglen_int = msglen; - return; - } - - purple_debug_error("oscar", "Error converting a Unicode message: %s\n", err->message); - g_error_free(err); - err = NULL; - - purple_debug_error("oscar", "This should NEVER happen! Sending UTF-8 text flagged as ASCII.\n"); - *msg = g_strdup(from); - *msglen_int = strlen(*msg); - *charset = AIM_CHARSET_ASCII; - *charsubset = 0x0000; - return; -} - -/** - * Looks for %n, %d, or %t in a string, and replaces them with the - * specified name, date, and time, respectively. - * - * @param str The string that may contain the special variables. - * @param name The sender name. - * - * @return A newly allocated string where the special variables are - * expanded. This should be g_free'd by the caller. - */ -static gchar * -purple_str_sub_away_formatters(const char *str, const char *name) -{ - char *c; - GString *cpy; - time_t t; - struct tm *tme; - - g_return_val_if_fail(str != NULL, NULL); - g_return_val_if_fail(name != NULL, NULL); - - /* Create an empty GString that is hopefully big enough for most messages */ - cpy = g_string_sized_new(1024); - - t = time(NULL); - tme = localtime(&t); - - c = (char *)str; - while (*c) { - switch (*c) { - case '%': - if (*(c + 1)) { - switch (*(c + 1)) { - case 'n': - /* append name */ - g_string_append(cpy, name); - c++; - break; - case 'd': - /* append date */ - g_string_append(cpy, purple_date_format_short(tme)); - c++; - break; - case 't': - /* append time */ - g_string_append(cpy, purple_time_format(tme)); - c++; - break; - default: - g_string_append_c(cpy, *c); - } - } else { - g_string_append_c(cpy, *c); - } - break; - default: - g_string_append_c(cpy, *c); - } - c++; - } - - return g_string_free(cpy, FALSE); -} - -static gchar *oscar_caps_to_string(guint64 caps) -{ - GString *str; - const gchar *tmp; - guint64 bit = 1; - - str = g_string_new(""); - - if (!caps) { - return NULL; - } else while (bit <= OSCAR_CAPABILITY_LAST) { - if (bit & caps) { - switch (bit) { - case OSCAR_CAPABILITY_BUDDYICON: - tmp = _("Buddy Icon"); - break; - case OSCAR_CAPABILITY_TALK: - tmp = _("Voice"); - break; - case OSCAR_CAPABILITY_DIRECTIM: - tmp = _("AIM Direct IM"); - break; - case OSCAR_CAPABILITY_CHAT: - tmp = _("Chat"); - break; - case OSCAR_CAPABILITY_GETFILE: - tmp = _("Get File"); - break; - case OSCAR_CAPABILITY_SENDFILE: - tmp = _("Send File"); - break; - case OSCAR_CAPABILITY_GAMES: - case OSCAR_CAPABILITY_GAMES2: - tmp = _("Games"); - break; - case OSCAR_CAPABILITY_XTRAZ: - case OSCAR_CAPABILITY_NEWCAPS: - tmp = _("ICQ Xtraz"); - break; - case OSCAR_CAPABILITY_ADDINS: - tmp = _("Add-Ins"); - break; - case OSCAR_CAPABILITY_SENDBUDDYLIST: - tmp = _("Send Buddy List"); - break; - case OSCAR_CAPABILITY_ICQ_DIRECT: - tmp = _("ICQ Direct Connect"); - break; - case OSCAR_CAPABILITY_APINFO: - tmp = _("AP User"); - break; - case OSCAR_CAPABILITY_ICQRTF: - tmp = _("ICQ RTF"); - break; - case OSCAR_CAPABILITY_EMPTY: - tmp = _("Nihilist"); - break; - case OSCAR_CAPABILITY_ICQSERVERRELAY: - tmp = _("ICQ Server Relay"); - break; - case OSCAR_CAPABILITY_UNICODEOLD: - tmp = _("Old ICQ UTF8"); - break; - case OSCAR_CAPABILITY_TRILLIANCRYPT: - tmp = _("Trillian Encryption"); - break; - case OSCAR_CAPABILITY_UNICODE: - tmp = _("ICQ UTF8"); - break; - case OSCAR_CAPABILITY_HIPTOP: - tmp = _("Hiptop"); - break; - case OSCAR_CAPABILITY_SECUREIM: - tmp = _("Security Enabled"); - break; - case OSCAR_CAPABILITY_VIDEO: - tmp = _("Video Chat"); - break; - /* Not actually sure about this one... WinAIM doesn't show anything */ - case OSCAR_CAPABILITY_ICHATAV: - tmp = _("iChat AV"); - break; - case OSCAR_CAPABILITY_LIVEVIDEO: - tmp = _("Live Video"); - break; - case OSCAR_CAPABILITY_CAMERA: - tmp = _("Camera"); - break; - case OSCAR_CAPABILITY_ICHAT_SCREENSHARE: - tmp = _("Screen Sharing"); - break; - default: - tmp = NULL; - break; - } - if (tmp) - g_string_append_printf(str, "%s%s", (*(str->str) == '\0' ? "" : ", "), tmp); - } - bit <<= 1; - } - - return g_string_free(str, FALSE); -} - static char *oscar_icqstatus(int state) { /* Make a cute little string that shows the status of the dude or dudet */ if (state & AIM_ICQ_STATE_CHAT) @@ -764,255 +182,6 @@ return g_strdup(_("Online")); } -static void -oscar_user_info_add_pair(PurpleNotifyUserInfo *user_info, const char *name, const char *value) -{ - if (value && value[0]) { - purple_notify_user_info_add_pair(user_info, name, value); - } -} - -static void -oscar_user_info_convert_and_add_pair(PurpleAccount *account, OscarData *od, PurpleNotifyUserInfo *user_info, - const char *name, const char *value) -{ - gchar *utf8; - - if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, od, value))) { - purple_notify_user_info_add_pair(user_info, name, utf8); - g_free(utf8); - } -} - -static void -oscar_user_info_convert_and_add(PurpleAccount *account, OscarData *od, PurpleNotifyUserInfo *user_info, - const char *name, const char *value) -{ - gchar *utf8; - - if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, od, value))) { - purple_notify_user_info_add_pair(user_info, name, utf8); - g_free(utf8); - } -} - -/** - * @brief Append the status information to a user_info struct - * - * The returned information is HTML-ready, appropriately escaped, as all information in a user_info struct should be HTML. - * - * @param gc The PurpleConnection - * @param user_info A PurpleNotifyUserInfo object to which status information will be added - * @param b The PurpleBuddy whose status is desired. This or the aim_userinfo_t (or both) must be passed to oscar_user_info_append_status(). - * @param userinfo The aim_userinfo_t of the buddy whose status is desired. This or the PurpleBuddy (or both) must be passed to oscar_user_info_append_status(). - * @param strip_html_tags If strip_html_tags is TRUE, tags embedded in the status message will be stripped, returning a non-formatted string. The string will still be HTML escaped. - */ -static void oscar_user_info_append_status(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo, gboolean strip_html_tags) -{ - PurpleAccount *account = purple_connection_get_account(gc); - OscarData *od; - PurplePresence *presence = NULL; - PurpleStatus *status = NULL; - gchar *message = NULL, *itmsurl = NULL, *tmp; - gboolean is_away; - - od = purple_connection_get_protocol_data(gc); - - if (b == NULL && userinfo == NULL) - return; - - if (b == NULL) - b = purple_find_buddy(purple_connection_get_account(gc), userinfo->bn); - else - userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b)); - - if (b) { - presence = purple_buddy_get_presence(b); - status = purple_presence_get_active_status(presence); - } - - /* If we have both b and userinfo we favor userinfo, because if we're - viewing someone's profile then we want the HTML away message, and - the "message" attribute of the status contains only the plaintext - message. */ - if (userinfo) { - if ((userinfo->flags & AIM_FLAG_AWAY) - && userinfo->away_len > 0 - && userinfo->away != NULL - && userinfo->away_encoding != NULL) - { - /* Away message */ - tmp = oscar_encoding_extract(userinfo->away_encoding); - message = oscar_encoding_to_utf8(account, - tmp, userinfo->away, userinfo->away_len); - g_free(tmp); - } else { - /* - * Available message or non-HTML away message (because that's - * all we have right now. - */ - if ((userinfo->status != NULL) && userinfo->status[0] != '\0') { - message = oscar_encoding_to_utf8(account, - userinfo->status_encoding, userinfo->status, - userinfo->status_len); - } -#if defined (_WIN32) || defined (__APPLE__) - if (userinfo->itmsurl && (userinfo->itmsurl[0] != '\0')) - itmsurl = oscar_encoding_to_utf8(account, userinfo->itmsurl_encoding, - userinfo->itmsurl, userinfo->itmsurl_len); -#endif - } - } else { - message = g_strdup(purple_status_get_attr_string(status, "message")); - itmsurl = g_strdup(purple_status_get_attr_string(status, "itmsurl")); - } - - is_away = ((status && !purple_status_is_available(status)) || - (userinfo && (userinfo->flags & AIM_FLAG_AWAY))); - - if (strip_html_tags) { - /* Away messages are HTML, but available messages were originally plain text. - * We therefore need to strip away messages but not available messages if we're asked to remove HTML tags. - */ - /* - * It seems like the above comment no longer applies. All messages need - * to be escaped. - */ - if (message) { - gchar *tmp2; - tmp = purple_markup_strip_html(message); - g_free(message); - tmp2 = g_markup_escape_text(tmp, -1); - g_free(tmp); - message = tmp2; - } - - } else { - if (itmsurl) { - tmp = g_strdup_printf("%s", - itmsurl, message); - g_free(message); - message = tmp; - } - } - g_free(itmsurl); - - if (message) { - tmp = purple_str_sub_away_formatters(message, purple_account_get_username(account)); - g_free(message); - message = tmp; - } - - if (b) { - if (purple_presence_is_online(presence)) { - if (oscar_util_valid_name_icq(purple_buddy_get_name(b)) || is_away || !message || !(*message)) { - /* Append the status name for online ICQ statuses, away AIM statuses, and for all buddies with no message. - * If the status name and the message are the same, only show one. */ - const char *status_name = purple_status_get_name(status); - if (status_name && message && !strcmp(status_name, message)) - status_name = NULL; - - tmp = g_strdup_printf("%s%s%s", - status_name ? status_name : "", - ((status_name && message) && *message) ? ": " : "", - (message && *message) ? message : ""); - g_free(message); - message = tmp; - } - - } else if (aim_ssi_waitingforauth(od->ssi.local, - aim_ssi_itemlist_findparentname(od->ssi.local, purple_buddy_get_name(b)), - purple_buddy_get_name(b))) - { - /* Note if an offline buddy is not authorized */ - tmp = g_strdup_printf("%s%s%s", - _("Not Authorized"), - (message && *message) ? ": " : "", - (message && *message) ? message : ""); - g_free(message); - message = tmp; - } else { - g_free(message); - message = g_strdup(_("Offline")); - } - } - - if (presence) { - const char *mood; - const char *description; - status = purple_presence_get_status(presence, "mood"); - mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME); - description = icq_get_custom_icon_description(mood); - if (description && *description) - purple_notify_user_info_add_pair(user_info, _("Mood"), _(description)); - } - - purple_notify_user_info_add_pair(user_info, _("Status"), message); - g_free(message); -} - -static void oscar_user_info_append_extra_info(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo) -{ - OscarData *od; - PurpleAccount *account; - PurplePresence *presence = NULL; - PurpleStatus *status = NULL; - PurpleGroup *g = NULL; - struct buddyinfo *bi = NULL; - char *tmp; - const char *bname = NULL, *gname = NULL; - - od = purple_connection_get_protocol_data(gc); - account = purple_connection_get_account(gc); - - if ((user_info == NULL) || ((b == NULL) && (userinfo == NULL))) - return; - - if (userinfo == NULL) - userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b)); - - if (b == NULL) - b = purple_find_buddy(account, userinfo->bn); - - if (b != NULL) { - bname = purple_buddy_get_name(b); - g = purple_buddy_get_group(b); - gname = purple_group_get_name(g); - presence = purple_buddy_get_presence(b); - status = purple_presence_get_active_status(presence); - } - - if (userinfo != NULL) - bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, userinfo->bn)); - - if ((bi != NULL) && (bi->ipaddr != 0)) { - tmp = g_strdup_printf("%hhu.%hhu.%hhu.%hhu", - (bi->ipaddr & 0xff000000) >> 24, - (bi->ipaddr & 0x00ff0000) >> 16, - (bi->ipaddr & 0x0000ff00) >> 8, - (bi->ipaddr & 0x000000ff)); - oscar_user_info_add_pair(user_info, _("IP Address"), tmp); - g_free(tmp); - } - - if ((userinfo != NULL) && (userinfo->warnlevel != 0)) { - tmp = g_strdup_printf("%d", (int)(userinfo->warnlevel/10.0 + .5)); - oscar_user_info_add_pair(user_info, _("Warning Level"), tmp); - g_free(tmp); - } - - if ((b != NULL) && (bname != NULL) && (g != NULL) && (gname != NULL)) { - tmp = aim_ssi_getcomment(od->ssi.local, gname, bname); - if (tmp != NULL) { - char *tmp2 = g_markup_escape_text(tmp, strlen(tmp)); - g_free(tmp); - - oscar_user_info_convert_and_add_pair(account, od, user_info, _("Buddy Comment"), tmp2); - g_free(tmp2); - } - } -} - static char *extract_name(const char *name) { char *tmp, *x; int i, j; @@ -1496,22 +665,12 @@ oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_MISSEDCALL, purple_parse_misses, 0); oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_CLIENTAUTORESP, purple_parse_clientauto, 0); oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_MTN, purple_parse_mtn, 0); - oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_ACK, purple_parse_msgack, 0); -#ifdef OLDSTYLE_ICQ_OFFLINEMSGS - oscar_data_addhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_OFFLINEMSG, purple_offlinemsg, 0); - oscar_data_addhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_OFFLINEMSGCOMPLETE, purple_offlinemsgdone, 0); -#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */ - oscar_data_addhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_ALIAS, purple_icqalias, 0); - oscar_data_addhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_INFO, purple_icqinfo, 0); oscar_data_addhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_RIGHTSINFO, purple_parse_locaterights, 0); - oscar_data_addhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_USERINFO, purple_parse_userinfo, 0); - oscar_data_addhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_ERROR, purple_parse_locerr, 0); oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x0001, purple_parse_genericerr, 0); oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x000f, purple_selfinfo, 0); oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x001f, purple_memrequest, 0); oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_REDIRECT, purple_handle_redirect, 0); oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_MOTD, purple_parse_motd, 0); - oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_EVIL, purple_parse_evilnotify, 0); oscar_data_addhandler(od, SNAC_FAMILY_POPUP, 0x0002, purple_popup, 0); oscar_data_addhandler(od, SNAC_FAMILY_USERLOOKUP, SNAC_SUBTYPE_USERLOOKUP_ERROR, purple_parse_searcherror, 0); oscar_data_addhandler(od, SNAC_FAMILY_USERLOOKUP, 0x0003, purple_parse_searchreply, 0); @@ -1771,34 +930,6 @@ AIM_SENDMEMBLOCK_FLAG_ISREQUEST); return 1; } - /* uncomment this when you're convinced it's right. remember, it's been wrong before. */ -#if 0 - if (offset > AIM_MAX_FILE_SIZE || len > AIM_MAX_FILE_SIZE) { - char *buf; - int i = 8; - if (modname) - i += strlen(modname); - buf = g_malloc(i); - i = 0; - if (modname) { - memcpy(buf, modname, strlen(modname)); - i += strlen(modname); - } - buf[i++] = offset & 0xff; - buf[i++] = (offset >> 8) & 0xff; - buf[i++] = (offset >> 16) & 0xff; - buf[i++] = (offset >> 24) & 0xff; - buf[i++] = len & 0xff; - buf[i++] = (len >> 8) & 0xff; - buf[i++] = (len >> 16) & 0xff; - buf[i++] = (len >> 24) & 0xff; - purple_debug_misc("oscar", "len + offset is invalid, " - "hashing request\n"); - aim_sendmemblock(od, command->conn, offset, i, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST); - g_free(buf); - return 1; - } -#endif pos = g_new0(struct pieceofcrap, 1); pos->gc = od->gc; @@ -2253,18 +1384,18 @@ purple_prpl_got_user_status_deactive(account, info->bn, OSCAR_STATUS_ID_MOBILE); } - if (info->status != NULL && info->status[0] != '\0') + if (info->status != NULL && info->status[0] != '\0') { /* Grab the available message */ - message = oscar_encoding_to_utf8(account, info->status_encoding, - info->status, info->status_len); + message = oscar_encoding_to_utf8(info->status_encoding, info->status, info->status_len); + } tmp2 = tmp = (message ? purple_markup_escape_text(message, -1) : NULL); if (strcmp(status_id, OSCAR_STATUS_ID_AVAILABLE) == 0) { - if (info->itmsurl_encoding && info->itmsurl && info->itmsurl_len) + if (info->itmsurl_encoding && info->itmsurl && info->itmsurl_len) { /* Grab the iTunes Music Store URL */ - itmsurl = oscar_encoding_to_utf8(account, info->itmsurl_encoding, - info->itmsurl, info->itmsurl_len); + itmsurl = oscar_encoding_to_utf8(info->itmsurl_encoding, info->itmsurl, info->itmsurl_len); + } if (tmp2 == NULL && itmsurl != NULL) /* @@ -2370,17 +1501,11 @@ PurpleMessageFlags flags = 0; struct buddyinfo *bi; PurpleStoredImage *img; - GString *message; gchar *tmp; - aim_mpmsg_section_t *curpart; const char *start, *end; GData *attribs; - purple_debug_misc("oscar", "Received IM from %s with %d parts\n", - userinfo->bn, args->mpmsg.numparts); - - if (args->mpmsg.numparts == 0) - return 1; + purple_debug_misc("oscar", "Received IM from %s\n", userinfo->bn); bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, userinfo->bn)); if (!bi) { @@ -2420,19 +1545,7 @@ } purple_imgstore_unref(img); - message = g_string_new(""); - curpart = args->mpmsg.parts; - while (curpart != NULL) { - tmp = purple_plugin_oscar_decode_im_part(account, userinfo->bn, curpart->charset, - curpart->charsubset, curpart->data, curpart->datalen); - if (tmp != NULL) { - g_string_append(message, tmp); - g_free(tmp); - } - - curpart = curpart->next; - } - tmp = g_string_free(message, FALSE); + tmp = g_strdup(args->msg); /* * Convert iChat color tags to normal font tags. @@ -2516,8 +1629,7 @@ tmp = tmp2; } - serv_got_im(gc, userinfo->bn, tmp, flags, - (args->icbmflags & AIM_IMFLAGS_OFFLINE) ? args->timestamp : time(NULL)); + serv_got_im(gc, userinfo->bn, tmp, flags, (args->icbmflags & AIM_IMFLAGS_OFFLINE) ? args->timestamp : time(NULL)); g_free(tmp); return 1; @@ -2545,35 +1657,20 @@ G_GUINT64_FORMAT ", user %s, status %hu\n", args->type, userinfo->bn, args->status); - if (args->msg != NULL) - { - if (args->encoding != NULL) - { - char *encoding = NULL; - encoding = oscar_encoding_extract(args->encoding); - message = oscar_encoding_to_utf8(account, encoding, args->msg, - args->msglen); - g_free(encoding); - } else { - if (g_utf8_validate(args->msg, args->msglen, NULL)) - message = g_strdup(args->msg); - } + if (args->msg != NULL) { + message = oscar_encoding_to_utf8(args->encoding, args->msg, args->msglen); } if (args->type & OSCAR_CAPABILITY_CHAT) { - char *encoding, *utf8name, *tmp; + char *utf8name, *tmp; GHashTable *components; if (!args->info.chat.roominfo.name || !args->info.chat.roominfo.exchange) { g_free(message); return 1; } - encoding = args->encoding ? oscar_encoding_extract(args->encoding) : NULL; - utf8name = oscar_encoding_to_utf8(account, encoding, - args->info.chat.roominfo.name, - args->info.chat.roominfo.namelen); - g_free(encoding); + utf8name = oscar_encoding_to_utf8(args->encoding, args->info.chat.roominfo.name, args->info.chat.roominfo.namelen); tmp = extract_name(utf8name); if (tmp != NULL) @@ -2594,8 +1691,7 @@ components); } - else if ((args->type & OSCAR_CAPABILITY_SENDFILE) || - (args->type & OSCAR_CAPABILITY_DIRECTIM)) + else if ((args->type & OSCAR_CAPABILITY_SENDFILE) || (args->type & OSCAR_CAPABILITY_DIRECTIM)) { if (args->status == AIM_RENDEZVOUS_PROPOSE) { @@ -2648,24 +1744,22 @@ purple_debug_info("oscar", "Got an ICQ Server Relay message of " "type %d\n", args->info.rtfmsg.msgtype); - if (args->info.rtfmsg.msgtype == 1) - { - if (args->info.rtfmsg.rtfmsg != NULL) - { - char *rtfmsg = NULL; - if (args->encoding != NULL) { - char *encoding = oscar_encoding_extract(args->encoding); - rtfmsg = oscar_encoding_to_utf8(account, encoding, - args->info.rtfmsg.rtfmsg, strlen(args->info.rtfmsg.rtfmsg)); - g_free(encoding); - } else { - if (g_utf8_validate(args->info.rtfmsg.rtfmsg, strlen(args->info.rtfmsg.rtfmsg), NULL)) - rtfmsg = g_strdup(args->info.rtfmsg.rtfmsg); - } - if (rtfmsg) { - serv_got_im(gc, userinfo->bn, rtfmsg, flags, time(NULL)); - g_free(rtfmsg); - } + if (args->info.rtfmsg.msgtype == 1) { + if (args->info.rtfmsg.msg != NULL) { + char *rtfmsg = oscar_encoding_to_utf8(args->encoding, args->info.rtfmsg.msg, strlen(args->info.rtfmsg.msg)); + char *tmp, *tmp2; + + /* Channel 2 messages are supposed to be plain-text (never mind the name "rtfmsg", even + * the official client doesn't parse them as RTF). Therefore, we should escape them before + * showing to the user. */ + tmp = g_markup_escape_text(rtfmsg, -1); + g_free(rtfmsg); + tmp2 = purple_strreplace(tmp, "\r\n", "
"); + g_free(tmp); + + serv_got_im(gc, userinfo->bn, tmp2, flags, time(NULL)); + aim_im_send_icq_confirmation(od, userinfo->bn, args->cookie); + g_free(tmp2); } } else if (args->info.rtfmsg.msgtype == 26) { purple_debug_info("oscar", "Sending X-Status Reply\n"); @@ -2683,122 +1777,6 @@ return 1; } -/* - * Authorization Functions - * Most of these are callbacks from dialogs. They're used by both - * methods of authorization (SSI and old-school channel 4 ICBM) - */ -/* When you ask other people for authorization */ -static void -purple_auth_request(struct name_data *data, char *msg) -{ - PurpleConnection *gc; - OscarData *od; - PurpleAccount *account; - PurpleBuddy *buddy; - PurpleGroup *group; - const char *bname, *gname; - - gc = data->gc; - od = purple_connection_get_protocol_data(gc); - account = purple_connection_get_account(gc); - buddy = purple_find_buddy(account, data->name); - if (buddy != NULL) - group = purple_buddy_get_group(buddy); - else - group = NULL; - - if (group != NULL) - { - bname = purple_buddy_get_name(buddy); - gname = purple_group_get_name(group); - purple_debug_info("oscar", "ssi: adding buddy %s to group %s\n", - bname, gname); - aim_ssi_sendauthrequest(od, data->name, msg ? msg : _("Please authorize me so I can add you to my buddy list.")); - if (!aim_ssi_itemlist_finditem(od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY)) - { - aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, TRUE); - - /* Mobile users should always be online */ - if (bname[0] == '+') { - purple_prpl_got_user_status(account, - purple_buddy_get_name(buddy), - OSCAR_STATUS_ID_AVAILABLE, NULL); - purple_prpl_got_user_status(account, - purple_buddy_get_name(buddy), - OSCAR_STATUS_ID_MOBILE, NULL); - } - } - } - - oscar_free_name_data(data); -} - -static void -purple_auth_sendrequest(PurpleConnection *gc, const char *name) -{ - struct name_data *data; - - data = g_new0(struct name_data, 1); - data->gc = gc; - data->name = g_strdup(name); - - purple_request_input(data->gc, NULL, _("Authorization Request Message:"), - NULL, _("Please authorize me!"), TRUE, FALSE, NULL, - _("_OK"), G_CALLBACK(purple_auth_request), - _("_Cancel"), G_CALLBACK(oscar_free_name_data), - purple_connection_get_account(gc), name, NULL, - data); -} - -static void -purple_auth_sendrequest_menu(PurpleBlistNode *node, gpointer ignored) -{ - PurpleBuddy *buddy; - PurpleConnection *gc; - - g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); - - buddy = (PurpleBuddy *) node; - gc = purple_account_get_connection(purple_buddy_get_account(buddy)); - purple_auth_sendrequest(gc, purple_buddy_get_name(buddy)); -} - -/* When other people ask you for authorization */ -static void -purple_auth_grant(gpointer cbdata) -{ - struct name_data *data = cbdata; - PurpleConnection *gc = data->gc; - OscarData *od = purple_connection_get_protocol_data(gc); - - aim_ssi_sendauthreply(od, data->name, 0x01, NULL); - - oscar_free_name_data(data); -} - -/* When other people ask you for authorization */ -static void -purple_auth_dontgrant(struct name_data *data, char *msg) -{ - PurpleConnection *gc = data->gc; - OscarData *od = purple_connection_get_protocol_data(gc); - - aim_ssi_sendauthreply(od, data->name, 0x00, msg ? msg : _("No reason given.")); -} - -static void -purple_auth_dontgrant_msgprompt(gpointer cbdata) -{ - struct name_data *data = cbdata; - purple_request_input(data->gc, NULL, _("Authorization Denied Message:"), - NULL, _("No reason given."), TRUE, FALSE, NULL, - _("_OK"), G_CALLBACK(purple_auth_dontgrant), - _("_Cancel"), G_CALLBACK(oscar_free_name_data), - purple_connection_get_account(data->gc), data->name, NULL, - data); -} - /* When someone sends you buddies */ static void purple_icq_buddyadd(struct name_data *data) @@ -2842,7 +1820,7 @@ purple_str_strip_char(msg1[i], '\r'); /* TODO: Should use an encoding other than ASCII? */ - msg2[i] = purple_plugin_oscar_decode_im_part(account, uin, AIM_CHARSET_ASCII, 0x0000, msg1[i], strlen(msg1[i])); + msg2[i] = oscar_decode_im(account, uin, AIM_CHARSET_ASCII, msg1[i], strlen(msg1[i])); g_free(uin); } msg2[i] = NULL; @@ -2895,24 +1873,17 @@ case 0x06: { /* Someone requested authorization */ if (i >= 6) { - struct name_data *data = g_new(struct name_data, 1); gchar *bn = g_strdup_printf("%u", args->uin); gchar *reason = NULL; if (msg2[5] != NULL) - reason = purple_plugin_oscar_decode_im_part(account, bn, AIM_CHARSET_LATIN_1, 0x0000, msg2[5], strlen(msg2[5])); + reason = oscar_decode_im(account, bn, AIM_CHARSET_LATIN_1, msg2[5], strlen(msg2[5])); purple_debug_info("oscar", "Received an authorization request from UIN %u\n", args->uin); - data->gc = gc; - data->name = bn; - data->nick = NULL; - - purple_account_request_authorization(account, bn, NULL, NULL, - reason, purple_find_buddy(account, bn) != NULL, - purple_auth_grant, - purple_auth_dontgrant_msgprompt, data); + aim_icq_getalias(od, bn, TRUE, reason); + g_free(bn); g_free(reason); } } break; @@ -3376,105 +2347,6 @@ return 1; } -/* - * We get this error when there was an error in the locate family. This - * happens when you request info of someone who is offline. - */ -static int purple_parse_locerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { - gchar *buf; - va_list ap; - guint16 reason; - char *destn; - PurpleNotifyUserInfo *user_info; - - va_start(ap, fr); - reason = (guint16) va_arg(ap, unsigned int); - destn = va_arg(ap, char *); - va_end(ap); - - if (destn == NULL) - return 1; - - user_info = purple_notify_user_info_new(); - buf = g_strdup_printf(_("User information not available: %s"), oscar_get_msgerr_reason(reason)); - purple_notify_user_info_add_pair(user_info, NULL, buf); - purple_notify_userinfo(od->gc, destn, user_info, NULL, NULL); - purple_notify_user_info_destroy(user_info); - purple_conv_present_error(destn, purple_connection_get_account(od->gc), buf); - g_free(buf); - - return 1; -} - -static int purple_parse_userinfo(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { - PurpleConnection *gc = od->gc; - PurpleAccount *account = purple_connection_get_account(gc); - PurpleNotifyUserInfo *user_info; - gchar *tmp = NULL, *info_utf8 = NULL, *base_profile_url = NULL; - va_list ap; - aim_userinfo_t *userinfo; - - va_start(ap, fr); - userinfo = va_arg(ap, aim_userinfo_t *); - va_end(ap); - - user_info = purple_notify_user_info_new(); - - oscar_user_info_append_status(gc, user_info, /* PurpleBuddy */ NULL, userinfo, /* strip_html_tags */ FALSE); - - if ((userinfo->present & AIM_USERINFO_PRESENT_IDLE) && userinfo->idletime != 0) { - tmp = purple_str_seconds_to_string(userinfo->idletime*60); - oscar_user_info_add_pair(user_info, _("Idle"), tmp); - g_free(tmp); - } - - oscar_user_info_append_extra_info(gc, user_info, NULL, userinfo); - - if ((userinfo->present & AIM_USERINFO_PRESENT_ONLINESINCE) && !oscar_util_valid_name_sms(userinfo->bn)) { - /* An SMS contact is always online; its Online Since value is not useful */ - time_t t = userinfo->onlinesince; - oscar_user_info_add_pair(user_info, _("Online Since"), purple_date_format_full(localtime(&t))); - } - - if (userinfo->present & AIM_USERINFO_PRESENT_MEMBERSINCE) { - time_t t = userinfo->membersince; - oscar_user_info_add_pair(user_info, _("Member Since"), purple_date_format_full(localtime(&t))); - } - - if (userinfo->capabilities != 0) { - tmp = oscar_caps_to_string(userinfo->capabilities); - oscar_user_info_add_pair(user_info, _("Capabilities"), tmp); - g_free(tmp); - } - - /* Info */ - if ((userinfo->info_len > 0) && (userinfo->info != NULL) && (userinfo->info_encoding != NULL)) { - tmp = oscar_encoding_extract(userinfo->info_encoding); - info_utf8 = oscar_encoding_to_utf8(account, tmp, userinfo->info, - userinfo->info_len); - g_free(tmp); - if (info_utf8 != NULL) { - tmp = purple_str_sub_away_formatters(info_utf8, purple_account_get_username(account)); - purple_notify_user_info_add_section_break(user_info); - oscar_user_info_add_pair(user_info, _("Profile"), tmp); - g_free(tmp); - g_free(info_utf8); - } - } - - purple_notify_user_info_add_section_break(user_info); - base_profile_url = oscar_util_valid_name_icq(userinfo->bn) ? "http://www.icq.com/people" : "http://profiles.aim.com"; - tmp = g_strdup_printf("%s", - base_profile_url, purple_normalize(account, userinfo->bn), _("View web profile")); - purple_notify_user_info_add_pair(user_info, NULL, tmp); - g_free(tmp); - - purple_notify_userinfo(gc, userinfo->bn, user_info, NULL, NULL); - purple_notify_user_info_destroy(user_info); - - return 1; -} - static int purple_parse_motd(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { char *msg; @@ -3617,13 +2489,7 @@ static int purple_conv_chat_info_update(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { va_list ap; - aim_userinfo_t *userinfo; - struct aim_chat_roominfo *roominfo; - char *roomname; - int usercount; - char *roomdesc; - guint16 unknown_c9, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen; - guint32 creationtime; + guint16 maxmsglen, maxvisiblemsglen; PurpleConnection *gc = od->gc; struct chat_connection *ccon = find_oscar_chat_by_conn(gc, conn); @@ -3631,16 +2497,7 @@ return 1; va_start(ap, fr); - roominfo = va_arg(ap, struct aim_chat_roominfo *); - roomname = va_arg(ap, char *); - usercount= va_arg(ap, int); - userinfo = va_arg(ap, aim_userinfo_t *); - roomdesc = va_arg(ap, char *); - unknown_c9 = (guint16)va_arg(ap, unsigned int); - creationtime = va_arg(ap, guint32); maxmsglen = (guint16)va_arg(ap, unsigned int); - unknown_d2 = (guint16)va_arg(ap, unsigned int); - unknown_d5 = (guint16)va_arg(ap, unsigned int); maxvisiblemsglen = (guint16)va_arg(ap, unsigned int); va_end(ap); @@ -3656,7 +2513,6 @@ static int purple_conv_chat_incoming_msg(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { PurpleConnection *gc = od->gc; - PurpleAccount *account = purple_connection_get_account(gc); struct chat_connection *ccon = find_oscar_chat_by_conn(gc, conn); gchar *utf8; va_list ap; @@ -3675,10 +2531,7 @@ charset = va_arg(ap, char *); va_end(ap); - utf8 = oscar_encoding_to_utf8(account, charset, msg, len); - if (utf8 == NULL) - /* The conversion failed! */ - utf8 = g_strdup(_("[Unable to display a message from this user because it contained invalid characters.]")); + utf8 = oscar_encoding_to_utf8(charset, msg, len); serv_got_chat_in(gc, ccon->id, info->bn, 0, utf8, time(NULL)); g_free(utf8); @@ -3796,41 +2649,6 @@ purple_debug_misc("oscar", "no more icons to request\n"); } -/* - * Received in response to an IM sent with the AIM_IMFLAGS_ACK option. - */ -static int purple_parse_msgack(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { - va_list ap; - guint16 type; - char *bn; - - va_start(ap, fr); - type = (guint16) va_arg(ap, unsigned int); - bn = va_arg(ap, char *); - va_end(ap); - - purple_debug_info("oscar", "Sent message to %s.\n", bn); - - return 1; -} - -static int purple_parse_evilnotify(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { -#ifdef CRAZY_WARNING - va_list ap; - guint16 newevil; - aim_userinfo_t *userinfo; - - va_start(ap, fr); - newevil = (guint16) va_arg(ap, unsigned int); - userinfo = va_arg(ap, aim_userinfo_t *); - va_end(ap); - - purple_prpl_got_account_warning_level(account, (userinfo && userinfo->bn) ? userinfo->bn : NULL, (newevil/10.0) + 0.5); -#endif - - return 1; -} - static int purple_selfinfo(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { int warning_level; va_list ap; @@ -3851,10 +2669,6 @@ */ warning_level = info->warnlevel/10.0 + 0.5; -#ifdef CRAZY_WARNING - purple_presence_set_warning_level(presence, warning_level); -#endif - return 1; } @@ -3993,16 +2807,14 @@ tmp = purple_markup_strip_html(message); itmsurl = purple_status_get_attr_string(status, "itmsurl"); aim_srv_setextrainfo(od, FALSE, 0, is_available, tmp, itmsurl); + aim_srv_set_dc_info(od); g_free(tmp); presence = purple_status_get_presence(status); aim_srv_setidle(od, !purple_presence_is_idle(presence) ? 0 : time(NULL) - purple_presence_get_idle_time(presence)); if (od->icq) { -#ifdef OLDSTYLE_ICQ_OFFLINEMSGS - aim_icq_reqofflinemsgs(od); -#endif - oscar_set_extendedstatus(gc); + oscar_set_extended_status(gc); aim_icq_setsecurity(od, purple_account_get_bool(account, "authorization", OSCAR_DEFAULT_AUTHORIZATION), purple_account_get_bool(account, "web_aware", OSCAR_DEFAULT_WEB_AWARE)); @@ -4034,206 +2846,6 @@ return 1; } -#ifdef OLDSTYLE_ICQ_OFFLINEMSGS -static int purple_offlinemsg(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { - va_list ap; - struct aim_icq_offlinemsg *msg; - struct aim_incomingim_ch4_args args; - time_t t; - - va_start(ap, fr); - msg = va_arg(ap, struct aim_icq_offlinemsg *); - va_end(ap); - - purple_debug_info("oscar", - "Received offline message. Converting to channel 4 ICBM...\n"); - args.uin = msg->sender; - args.type = msg->type; - args.flags = msg->flags; - args.msglen = msg->msglen; - args.msg = msg->msg; - t = purple_time_build(msg->year, msg->month, msg->day, msg->hour, msg->minute, 0); - incomingim_chan4(od, conn, NULL, &args, t); - - return 1; -} - -static int purple_offlinemsgdone(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) -{ - aim_icq_ackofflinemsgs(od); - return 1; -} -#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */ - -static int purple_icqinfo(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) -{ - PurpleConnection *gc; - PurpleAccount *account; - PurpleBuddy *buddy; - struct buddyinfo *bi; - gchar who[16]; - PurpleNotifyUserInfo *user_info; - gchar *utf8; - gchar *buf; - const gchar *alias; - va_list ap; - struct aim_icq_info *info; - - gc = od->gc; - account = purple_connection_get_account(gc); - - va_start(ap, fr); - info = va_arg(ap, struct aim_icq_info *); - va_end(ap); - - if (!info->uin) - return 0; - - user_info = purple_notify_user_info_new(); - - g_snprintf(who, sizeof(who), "%u", info->uin); - buddy = purple_find_buddy(account, who); - if (buddy != NULL) - bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, purple_buddy_get_name(buddy))); - else - bi = NULL; - - purple_notify_user_info_add_pair(user_info, _("UIN"), who); - oscar_user_info_convert_and_add(account, od, user_info, _("Nick"), info->nick); - if ((bi != NULL) && (bi->ipaddr != 0)) { - char *tstr = g_strdup_printf("%hhu.%hhu.%hhu.%hhu", - (bi->ipaddr & 0xff000000) >> 24, - (bi->ipaddr & 0x00ff0000) >> 16, - (bi->ipaddr & 0x0000ff00) >> 8, - (bi->ipaddr & 0x000000ff)); - purple_notify_user_info_add_pair(user_info, _("IP Address"), tstr); - g_free(tstr); - } - oscar_user_info_convert_and_add(account, od, user_info, _("First Name"), info->first); - oscar_user_info_convert_and_add(account, od, user_info, _("Last Name"), info->last); - if (info->email && info->email[0] && (utf8 = oscar_utf8_try_convert(account, od, info->email))) { - buf = g_strdup_printf("%s", utf8, utf8); - purple_notify_user_info_add_pair(user_info, _("Email Address"), buf); - g_free(buf); - g_free(utf8); - } - if (info->numaddresses && info->email2) { - int i; - for (i = 0; i < info->numaddresses; i++) { - if (info->email2[i] && info->email2[i][0] && (utf8 = oscar_utf8_try_convert(account, od, info->email2[i]))) { - buf = g_strdup_printf("%s", utf8, utf8); - purple_notify_user_info_add_pair(user_info, _("Email Address"), buf); - g_free(buf); - g_free(utf8); - } - } - } - oscar_user_info_convert_and_add(account, od, user_info, _("Mobile Phone"), info->mobile); - - if (info->gender != 0) - purple_notify_user_info_add_pair(user_info, _("Gender"), (info->gender == 1 ? _("Female") : _("Male"))); - - if ((info->birthyear > 1900) && (info->birthmonth > 0) && (info->birthday > 0)) { - /* Initialize the struct properly or strftime() will crash - * under some conditions (e.g. Debian sarge w/ LANG=en_HK). */ - time_t t = time(NULL); - struct tm *tm = localtime(&t); - - tm->tm_mday = (int)info->birthday; - tm->tm_mon = (int)info->birthmonth - 1; - tm->tm_year = (int)info->birthyear - 1900; - - /* To be 100% sure that the fields are re-normalized. - * If you're sure strftime() ALWAYS does this EVERYWHERE, - * feel free to remove it. --rlaager */ - mktime(tm); - - oscar_user_info_convert_and_add(account, od, user_info, _("Birthday"), purple_date_format_short(tm)); - } - if ((info->age > 0) && (info->age < 255)) { - char age[5]; - snprintf(age, sizeof(age), "%hhd", info->age); - purple_notify_user_info_add_pair(user_info, _("Age"), age); - } - if (info->personalwebpage && info->personalwebpage[0] && (utf8 = oscar_utf8_try_convert(account, od, info->personalwebpage))) { - buf = g_strdup_printf("%s", utf8, utf8); - purple_notify_user_info_add_pair(user_info, _("Personal Web Page"), buf); - g_free(buf); - g_free(utf8); - } - - if (buddy != NULL) - oscar_user_info_append_status(gc, user_info, buddy, /* aim_userinfo_t */ NULL, /* strip_html_tags */ FALSE); - - oscar_user_info_convert_and_add(account, od, user_info, _("Additional Information"), info->info); - purple_notify_user_info_add_section_break(user_info); - - if ((info->homeaddr && (info->homeaddr[0])) || (info->homecity && info->homecity[0]) || (info->homestate && info->homestate[0]) || (info->homezip && info->homezip[0])) { - purple_notify_user_info_add_section_header(user_info, _("Home Address")); - - oscar_user_info_convert_and_add(account, od, user_info, _("Address"), info->homeaddr); - oscar_user_info_convert_and_add(account, od, user_info, _("City"), info->homecity); - oscar_user_info_convert_and_add(account, od, user_info, _("State"), info->homestate); - oscar_user_info_convert_and_add(account, od, user_info, _("Zip Code"), info->homezip); - } - if ((info->workaddr && info->workaddr[0]) || (info->workcity && info->workcity[0]) || (info->workstate && info->workstate[0]) || (info->workzip && info->workzip[0])) { - purple_notify_user_info_add_section_header(user_info, _("Work Address")); - - oscar_user_info_convert_and_add(account, od, user_info, _("Address"), info->workaddr); - oscar_user_info_convert_and_add(account, od, user_info, _("City"), info->workcity); - oscar_user_info_convert_and_add(account, od, user_info, _("State"), info->workstate); - oscar_user_info_convert_and_add(account, od, user_info, _("Zip Code"), info->workzip); - } - if ((info->workcompany && info->workcompany[0]) || (info->workdivision && info->workdivision[0]) || (info->workposition && info->workposition[0]) || (info->workwebpage && info->workwebpage[0])) { - purple_notify_user_info_add_section_header(user_info, _("Work Information")); - - oscar_user_info_convert_and_add(account, od, user_info, _("Company"), info->workcompany); - oscar_user_info_convert_and_add(account, od, user_info, _("Division"), info->workdivision); - oscar_user_info_convert_and_add(account, od, user_info, _("Position"), info->workposition); - - if (info->workwebpage && info->workwebpage[0] && (utf8 = oscar_utf8_try_convert(account, od, info->workwebpage))) { - char *webpage = g_strdup_printf("%s", utf8, utf8); - purple_notify_user_info_add_pair(user_info, _("Web Page"), webpage); - g_free(webpage); - g_free(utf8); - } - } - - if (buddy != NULL) - alias = purple_buddy_get_alias(buddy); - else - alias = who; - purple_notify_userinfo(gc, who, user_info, NULL, NULL); - purple_notify_user_info_destroy(user_info); - - return 1; -} - -static int purple_icqalias(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) -{ - PurpleConnection *gc = od->gc; - PurpleAccount *account = purple_connection_get_account(gc); - gchar who[16], *utf8; - PurpleBuddy *b; - va_list ap; - struct aim_icq_info *info; - - va_start(ap, fr); - info = va_arg(ap, struct aim_icq_info *); - va_end(ap); - - if (info->uin && info->nick && info->nick[0] && (utf8 = oscar_utf8_try_convert(account, od, info->nick))) { - g_snprintf(who, sizeof(who), "%u", info->uin); - serv_got_alias(gc, who, utf8); - if ((b = purple_find_buddy(account, who))) { - purple_blist_node_set_string((PurpleBlistNode*)b, "servernick", utf8); - } - g_free(utf8); - } - - return 1; -} - static int purple_popup(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { PurpleConnection *gc = od->gc; @@ -4458,8 +3070,8 @@ GString *msg; GString *data; gchar *tmp; - int tmplen; - guint16 charset, charsubset; + gsize tmplen; + guint16 charset; GData *attribs; const char *start, *end, *last; int oscar_id = 0; @@ -4520,8 +3132,7 @@ g_string_append(msg, ""); /* Convert the message to a good encoding */ - purple_plugin_oscar_convert_to_best_encoding(conn->od->gc, - conn->bn, msg->str, &tmp, &tmplen, &charset, &charsubset); + tmp = oscar_encode_im(msg->str, &tmplen, &charset, NULL); g_string_free(msg, TRUE); msg = g_string_new_len(tmp, tmplen); g_free(tmp); @@ -4568,7 +3179,7 @@ } if (imflags & PURPLE_MESSAGE_AUTO_RESP) - tmp1 = purple_str_sub_away_formatters(message, name); + tmp1 = oscar_util_format_string(message, name); else tmp1 = g_strdup(message); @@ -4601,7 +3212,7 @@ g_hash_table_insert(od->buddyinfo, g_strdup(purple_normalize(account, name)), bi); } - args.flags = AIM_IMFLAGS_ACK | AIM_IMFLAGS_CUSTOMFEATURES; + args.flags = 0; if (!is_sms && (!buddy || !PURPLE_BUDDY_IS_ONLINE(buddy))) args.flags |= AIM_IMFLAGS_OFFLINE; @@ -4670,7 +3281,7 @@ g_free(tmp1); tmp1 = tmp2; - purple_plugin_oscar_convert_to_best_encoding(gc, name, tmp1, (char **)&args.msg, &args.msglen, &args.charset, &args.charsubset); + args.msg = oscar_encode_im(tmp1, &args.msglen, &args.charset, NULL); if (is_html && (args.msglen > MAXMSGLEN)) { /* If the length was too long, try stripping the HTML and then running it back through * purple_strdup_withhtml() and the encoding process. The result may be shorter. */ @@ -4687,14 +3298,12 @@ g_free(tmp1); tmp1 = tmp2; - purple_plugin_oscar_convert_to_best_encoding(gc, name, tmp1, (char **)&args.msg, &args.msglen, &args.charset, &args.charsubset); - + args.msg = oscar_encode_im(tmp1, &args.msglen, &args.charset, NULL); purple_debug_info("oscar", "Sending %s as %s because the original was too long.\n", message, (char *)args.msg); } - purple_debug_info("oscar", "Sending IM, charset=0x%04hx, charsubset=0x%04hx, length=%d\n", - args.charset, args.charsubset, args.msglen); + purple_debug_info("oscar", "Sending IM, charset=0x%04hx, length=%" G_GSIZE_FORMAT "\n", args.charset, args.msglen); ret = aim_im_sendch1_ext(od, &args); g_free((char *)args.msg); } @@ -4721,43 +3330,11 @@ aim_locate_getinfoshort(od, name, 0x00000003); } -#if 0 -static void oscar_set_dir(PurpleConnection *gc, const char *first, const char *middle, const char *last, - const char *maiden, const char *city, const char *state, const char *country, int web) { - /* XXX - some of these things are wrong, but i'm lazy */ - OscarData *od = purple_connection_get_protocol_data(gc); - aim_locate_setdirinfo(od, first, middle, last, - maiden, NULL, NULL, city, state, NULL, 0, web); -} -#endif - void oscar_set_idle(PurpleConnection *gc, int time) { OscarData *od = purple_connection_get_protocol_data(gc); aim_srv_setidle(od, time); } -static -gchar *purple_prpl_oscar_convert_to_infotext(const gchar *str, gsize *ret_len, char **encoding) -{ - int charset = 0; - char *encoded = NULL; - - charset = oscar_charset_check(str); - if (charset == AIM_CHARSET_UNICODE) { - encoded = g_convert(str, -1, "UTF-16BE", "UTF-8", NULL, ret_len, NULL); - *encoding = "unicode-2-0"; - } else if (charset == AIM_CHARSET_LATIN_1) { - encoded = g_convert(str, -1, "ISO-8859-1", "UTF-8", NULL, ret_len, NULL); - *encoding = "iso-8859-1"; - } else { - encoded = g_strdup(str); - *ret_len = strlen(str); - *encoding = "us-ascii"; - } - - return encoded; -} - void oscar_set_info(PurpleConnection *gc, const char *rawinfo) { @@ -4769,8 +3346,8 @@ oscar_set_info_and_status(account, TRUE, rawinfo, FALSE, status); } -static void -oscar_set_extendedstatus(PurpleConnection *gc) +static guint32 +oscar_get_extended_status(PurpleConnection *gc) { OscarData *od; PurpleAccount *account; @@ -4814,7 +3391,13 @@ else if (!strcmp(status_id, OSCAR_STATUS_ID_CUSTOM)) data |= AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY; - aim_srv_setextrainfo(od, TRUE, data, FALSE, NULL, NULL); + return data; +} + +static void +oscar_set_extended_status(PurpleConnection *gc) +{ + aim_srv_setextrainfo(purple_connection_get_protocol_data(gc), TRUE, oscar_get_extended_status(gc), FALSE, NULL, NULL); } static void @@ -4855,7 +3438,7 @@ else if (rawinfo != NULL) { char *htmlinfo = purple_strdup_withhtml(rawinfo); - info = purple_prpl_oscar_convert_to_infotext(htmlinfo, &infolen, &info_encoding); + info = oscar_encode_im(htmlinfo, &infolen, NULL, &info_encoding); g_free(htmlinfo); if (infolen > od->rights.maxsiglen) @@ -4888,7 +3471,7 @@ /* We do this for icq too so that they work for old third party clients */ linkified = purple_markup_linkify(status_html); - away = purple_prpl_oscar_convert_to_infotext(linkified, &awaylen, &away_encoding); + away = oscar_encode_im(linkified, &awaylen, NULL, &away_encoding); g_free(linkified); if (awaylen > od->rights.maxawaymsglen) @@ -4917,8 +3500,6 @@ const char *status_html; status_html = purple_status_get_attr_string(status, "message"); - if (od->icq && (status_html == NULL || status_html[0] == '\0')) - status_html = purple_status_type_get_name(status_type); if (status_html != NULL) { status_text = purple_markup_strip_html(status_html); @@ -4931,28 +3512,27 @@ } itmsurl = purple_status_get_attr_string(status, "itmsurl"); - - /* TODO: Combine these two calls! */ - aim_srv_setextrainfo(od, FALSE, 0, TRUE, status_text, itmsurl); - oscar_set_extendedstatus(gc); + + aim_srv_setextrainfo(od, TRUE, oscar_get_extended_status(gc), TRUE, status_text, itmsurl); g_free(status_text); } } static void -oscar_set_status_icq(PurpleAccount *account) +oscar_set_icq_permdeny(PurpleAccount *account) { PurpleConnection *gc = purple_account_get_connection(account); - - /* Our permit/deny setting affects our invisibility */ - oscar_set_permit_deny(gc); + OscarData *od = purple_connection_get_protocol_data(gc); + gboolean invisible = purple_account_is_status_active(account, OSCAR_STATUS_ID_INVISIBLE); /* - * TODO: I guess we should probably wait and do this after we get - * confirmation from the above SSI call? Right now other people - * see our status blip to "invisible" before we appear offline. + * For ICQ the permit/deny setting controls who can see you + * online. Mimicking the official client's behavior, we use PURPLE_PRIVACY_ALLOW_USERS + * when our status is "invisible" and PURPLE_PRIVACY_DENY_USERS otherwise. + * In the former case, we are visible only to buddies on our "permanently visible" list. + * In the latter, we are invisible only to buddies on our "permanently invisible" list. */ - oscar_set_extendedstatus(gc); + aim_ssi_setpermdeny(od, invisible ? PURPLE_PRIVACY_ALLOW_USERS : PURPLE_PRIVACY_DENY_USERS); } void @@ -4978,22 +3558,15 @@ return; } + if (od->icq) { + /* Set visibility */ + oscar_set_icq_permdeny(account); + } + /* Set the AIM-style away message for both AIM and ICQ accounts */ oscar_set_info_and_status(account, FALSE, NULL, TRUE, status); - - /* Set the ICQ status for ICQ accounts only */ - if (od->icq) - oscar_set_status_icq(account); } -#ifdef CRAZY_WARN -void -oscar_warn(PurpleConnection *gc, const char *name, gboolean anonymous) { - OscarData *od = purple_connection_get_protocol_data(gc); - aim_im_warn(od, od->conn, name, anonymous ? AIM_WARN_ANON : 0); -} -#endif - void oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { OscarData *od; @@ -5035,13 +3608,13 @@ aim_ssi_itemlist_findparentname(od->ssi.local, bname), bname)) { /* Not authorized -- Re-request authorization */ - purple_auth_sendrequest(gc, bname); + oscar_auth_sendrequest(gc, bname); } } /* XXX - Should this be done from AIM accounts, as well? */ if (od->icq) - aim_icq_getalias(od, bname); + aim_icq_getalias(od, bname, FALSE, NULL); } void oscar_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { @@ -5151,8 +3724,6 @@ return 1; } - oscar_set_status_icq(purple_connection_get_account(gc)); - return 1; } @@ -5193,12 +3764,14 @@ PurpleAccount *account; PurpleGroup *g; PurpleBuddy *b; + GSList *cur, *next, *buddies; struct aim_ssi_item *curitem; guint32 tmp; PurpleStoredImage *img; va_list ap; guint16 fmtver, numitems; guint32 timestamp; + guint16 deny_entry_type = aim_ssi_getdenyentrytype(od); gc = od->gc; od = purple_connection_get_protocol_data(gc); @@ -5211,110 +3784,109 @@ va_end(ap); /* Don't attempt to re-request our buddy list later */ - if (od->getblisttimer != 0) + if (od->getblisttimer != 0) { purple_timeout_remove(od->getblisttimer); - od->getblisttimer = 0; - - purple_debug_info("oscar", - "ssi: syncing local list and server list\n"); + od->getblisttimer = 0; + } + + purple_debug_info("oscar", "ssi: syncing local list and server list\n"); /* Clean the buddy list */ aim_ssi_cleanlist(od); - { /* If not in server list then prune from local list */ - GSList *cur, *next; - GSList *buddies = purple_find_buddies(account, NULL); - - /* Buddies */ - cur = NULL; - - while(buddies) { - PurpleGroup *g; - const char *gname; - const char *bname; - - b = buddies->data; - g = purple_buddy_get_group(b); - gname = purple_group_get_name(g); - bname = purple_buddy_get_name(b); - - if (aim_ssi_itemlist_exists(od->ssi.local, bname)) { - /* If the buddy is an ICQ user then load his nickname */ - const char *servernick = purple_blist_node_get_string((PurpleBlistNode*)b, "servernick"); - char *alias; - const char *balias; - if (servernick) - serv_got_alias(gc, bname, servernick); - - /* Store local alias on server */ - alias = aim_ssi_getalias(od->ssi.local, gname, bname); - balias = purple_buddy_get_local_buddy_alias(b); - if (!alias && balias && *balias) - aim_ssi_aliasbuddy(od, gname, bname, balias); - g_free(alias); - } else { + /*** Begin code for pruning buddies from local list if they're not in server list ***/ + + /* Buddies */ + cur = NULL; + for (buddies = purple_find_buddies(account, NULL); + buddies; + buddies = g_slist_delete_link(buddies, buddies)) + { + PurpleGroup *g; + const char *gname; + const char *bname; + + b = buddies->data; + g = purple_buddy_get_group(b); + gname = purple_group_get_name(g); + bname = purple_buddy_get_name(b); + + if (aim_ssi_itemlist_exists(od->ssi.local, bname)) { + /* If the buddy is an ICQ user then load his nickname */ + const char *servernick = purple_blist_node_get_string((PurpleBlistNode*)b, "servernick"); + char *alias; + const char *balias; + if (servernick) + serv_got_alias(gc, bname, servernick); + + /* Store local alias on server */ + alias = aim_ssi_getalias(od->ssi.local, gname, bname); + balias = purple_buddy_get_local_buddy_alias(b); + if (!alias && balias && *balias) + aim_ssi_aliasbuddy(od, gname, bname, balias); + g_free(alias); + } else { + purple_debug_info("oscar", + "ssi: removing buddy %s from local list\n", bname); + /* Queue the buddy for removal from the local list */ + cur = g_slist_prepend(cur, b); + } + } + while (cur != NULL) { + purple_blist_remove_buddy(cur->data); + cur = g_slist_delete_link(cur, cur); + } + + /* Permit list (ICQ doesn't have one) */ + if (!od->icq) { + next = account->permit; + while (next != NULL) { + cur = next; + next = next->next; + if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, AIM_SSI_TYPE_PERMIT)) { purple_debug_info("oscar", - "ssi: removing buddy %s from local list\n", bname); - /* We can't actually remove now because it will screw up our looping */ - cur = g_slist_prepend(cur, b); - } - buddies = g_slist_delete_link(buddies, buddies); - } - - while (cur != NULL) { - b = cur->data; - cur = g_slist_remove(cur, b); - purple_blist_remove_buddy(b); - } - - /* Permit list */ - if (account->permit) { - next = account->permit; - while (next != NULL) { - cur = next; - next = next->next; - if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, AIM_SSI_TYPE_PERMIT)) { - purple_debug_info("oscar", - "ssi: removing permit %s from local list\n", (const char *)cur->data); - purple_privacy_permit_remove(account, cur->data, TRUE); - } + "ssi: removing permit %s from local list\n", (const char *)cur->data); + purple_privacy_permit_remove(account, cur->data, TRUE); } } - - /* Deny list */ - if (account->deny) { - next = account->deny; - while (next != NULL) { - cur = next; - next = next->next; - if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, AIM_SSI_TYPE_DENY)) { - purple_debug_info("oscar", - "ssi: removing deny %s from local list\n", (const char *)cur->data); - purple_privacy_deny_remove(account, cur->data, TRUE); - } - } + } + + /* Deny list */ + next = account->deny; + while (next != NULL) { + cur = next; + next = next->next; + if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, deny_entry_type)) { + purple_debug_info("oscar", + "ssi: removing deny %s from local list\n", (const char *)cur->data); + purple_privacy_deny_remove(account, cur->data, TRUE); } - /* Presence settings (idle time visibility) */ - tmp = aim_ssi_getpresence(od->ssi.local); - if (tmp != 0xFFFFFFFF) { - const char *idle_reporting_pref; - gboolean report_idle; - - idle_reporting_pref = purple_prefs_get_string("/purple/away/idle_reporting"); - report_idle = strcmp(idle_reporting_pref, "none") != 0; - - if (report_idle) - aim_ssi_setpresence(od, tmp | AIM_SSI_PRESENCE_FLAG_SHOWIDLE); - else - aim_ssi_setpresence(od, tmp & ~AIM_SSI_PRESENCE_FLAG_SHOWIDLE); - } - - - } /* end pruning buddies from local list */ - - /* Add from server list to local list */ + } + + /* Presence settings (idle time visibility) */ + tmp = aim_ssi_getpresence(od->ssi.local); + if (tmp != 0xFFFFFFFF) { + const char *idle_reporting_pref; + gboolean report_idle; + + idle_reporting_pref = purple_prefs_get_string("/purple/away/idle_reporting"); + report_idle = strcmp(idle_reporting_pref, "none") != 0; + + if (report_idle) + aim_ssi_setpresence(od, tmp | AIM_SSI_PRESENCE_FLAG_SHOWIDLE); + else + aim_ssi_setpresence(od, tmp & ~AIM_SSI_PRESENCE_FLAG_SHOWIDLE); + } + + /*** End code for pruning buddies from local list ***/ + + /*** Begin code for adding from server list to local list ***/ + for (curitem=od->ssi.local; curitem; curitem=curitem->next) { - if ((curitem->name == NULL) || (g_utf8_validate(curitem->name, -1, NULL))) + if (curitem->name && !g_utf8_validate(curitem->name, -1, NULL)) + /* Got node with invalid UTF-8 in the name. Skip it. */ + break; + switch (curitem->type) { case AIM_SSI_TYPE_BUDDY: { /* Buddy */ if (curitem->name) { @@ -5323,13 +3895,7 @@ groupitem = aim_ssi_itemlist_find(od->ssi.local, curitem->gid, 0x0000); gname = groupitem ? groupitem->name : NULL; - if (gname != NULL) { - if (g_utf8_validate(gname, -1, NULL)) - gname_utf8 = g_strdup(gname); - else - gname_utf8 = oscar_utf8_try_convert(account, od, gname); - } else - gname_utf8 = NULL; + gname_utf8 = oscar_utf8_try_convert(account, od, gname); g = purple_find_group(gname_utf8 ? gname_utf8 : _("Orphans")); if (g == NULL) { @@ -5338,14 +3904,7 @@ } alias = aim_ssi_getalias(od->ssi.local, gname, curitem->name); - if (alias != NULL) { - if (g_utf8_validate(alias, -1, NULL)) - alias_utf8 = g_strdup(alias); - else - alias_utf8 = oscar_utf8_try_convert(account, od, alias); - g_free(alias); - } else - alias_utf8 = NULL; + alias_utf8 = oscar_utf8_try_convert(account, od, alias); b = purple_find_buddy_in_group(account, curitem->name, g); if (b) { @@ -5387,13 +3946,7 @@ char *gname_utf8; gname = curitem->name; - if (gname != NULL) { - if (g_utf8_validate(gname, -1, NULL)) - gname_utf8 = g_strdup(gname); - else - gname_utf8 = oscar_utf8_try_convert(account, od, gname); - } else - gname_utf8 = NULL; + gname_utf8 = oscar_utf8_try_convert(account, od, gname); if (gname_utf8 != NULL && purple_find_group(gname_utf8) == NULL) { g = purple_group_new(gname_utf8); @@ -5402,12 +3955,10 @@ g_free(gname_utf8); } break; - case AIM_SSI_TYPE_PERMIT: { /* Permit buddy */ - if (curitem->name) { - /* if (!find_permdeny_by_name(gc->permit, curitem->name)) { AAA */ - GSList *list; - for (list=account->permit; (list && oscar_util_name_compare(curitem->name, list->data)); list=list->next); - if (!list) { + case AIM_SSI_TYPE_PERMIT: { /* Permit buddy (unless we're on ICQ) */ + if (!od->icq && curitem->name) { + for (cur = account->permit; (cur && oscar_util_name_compare(curitem->name, cur->data)); cur = cur->next); + if (!cur) { purple_debug_info("oscar", "ssi: adding permit buddy %s to local list\n", curitem->name); purple_privacy_permit_add(account, curitem->name, TRUE); @@ -5415,11 +3966,11 @@ } } break; + case AIM_SSI_TYPE_ICQDENY: case AIM_SSI_TYPE_DENY: { /* Deny buddy */ - if (curitem->name) { - GSList *list; - for (list=account->deny; (list && oscar_util_name_compare(curitem->name, list->data)); list=list->next); - if (!list) { + if (curitem->type == deny_entry_type && curitem->name) { + for (cur = account->deny; (cur && oscar_util_name_compare(curitem->name, cur->data)); cur = cur->next); + if (!cur) { purple_debug_info("oscar", "ssi: adding deny buddy %s to local list\n", curitem->name); purple_privacy_deny_add(account, curitem->name, TRUE); @@ -5451,7 +4002,13 @@ } /* End of switch on curitem->type */ } /* End of for loop */ - oscar_set_status_icq(account); + /*** End code for adding from server list to local list ***/ + + if (od->icq) { + oscar_set_icq_permdeny(account); + } else { + oscar_set_aim_permdeny(gc); + } /* Activate SSI */ /* Sending the enable causes other people to be able to see you, and you to see them */ @@ -5513,7 +4070,7 @@ case 0x000e: { /* buddy requires authorization */ if ((retval->action == SNAC_SUBTYPE_FEEDBAG_ADD) && (retval->name)) - purple_auth_sendrequest(gc, retval->name); + oscar_auth_sendrequest(gc, retval->name); } break; default: { /* La la la */ @@ -5562,15 +4119,7 @@ gname_utf8 = gname ? oscar_utf8_try_convert(account, od, gname) : NULL; alias = aim_ssi_getalias(od->ssi.local, gname, name); - if (alias != NULL) - { - if (g_utf8_validate(alias, -1, NULL)) - alias_utf8 = g_strdup(alias); - else - alias_utf8 = oscar_utf8_try_convert(account, od, alias); - } - else - alias_utf8 = NULL; + alias_utf8 = oscar_utf8_try_convert(account, od, alias); g_free(alias); b = purple_find_buddy(account, name); @@ -5665,24 +4214,18 @@ static int purple_ssi_authrequest(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { - PurpleConnection *gc = od->gc; va_list ap; const char *bn; - const char *msg; - PurpleAccount *account = purple_connection_get_account(gc); - struct name_data *data; - PurpleBuddy *buddy; + char *msg; va_start(ap, fr); bn = va_arg(ap, const char *); - msg = va_arg(ap, const char *); + msg = va_arg(ap, char *); va_end(ap); purple_debug_info("oscar", "ssi: received authorization request from %s\n", bn); - buddy = purple_find_buddy(account, bn); - if (!msg) { purple_debug_warning("oscar", "Received auth request from %s with " "empty message\n", bn); @@ -5692,16 +4235,7 @@ msg = NULL; } - data = g_new(struct name_data, 1); - data->gc = gc; - data->name = g_strdup(bn); - data->nick = (buddy ? g_strdup(purple_buddy_get_alias_only(buddy)) : NULL); - - purple_account_request_authorization(account, bn, NULL, - (buddy ? purple_buddy_get_alias_only(buddy) : NULL), - msg, buddy != NULL, purple_auth_grant, - purple_auth_dontgrant_msgprompt, data); - + aim_icq_getalias(od, bn, TRUE, msg); return 1; } @@ -5874,9 +4408,9 @@ PurpleConversation *conv = NULL; struct chat_connection *c = NULL; char *buf, *buf2, *buf3; - guint16 charset, charsubset; - char *charsetstr = NULL; - int len; + guint16 charset; + char *charsetstr; + gsize len; if (!(conv = purple_find_chat(gc, id))) return -EINVAL; @@ -5892,7 +4426,7 @@ "You cannot send IM Images in AIM chats."), PURPLE_MESSAGE_ERROR, time(NULL)); - purple_plugin_oscar_convert_to_best_encoding(gc, NULL, buf, &buf2, &len, &charset, &charsubset); + buf2 = oscar_encode_im(buf, &len, &charset, &charsetstr); /* * Evan S. suggested that maxvis really does mean "number of * visible characters" and not "number of bytes" @@ -5908,10 +4442,11 @@ buf = purple_strdup_withhtml(buf3); g_free(buf3); - purple_plugin_oscar_convert_to_best_encoding(gc, NULL, buf, &buf2, &len, &charset, &charsubset); + buf2 = oscar_encode_im(buf, &len, &charset, &charsetstr); if ((len > c->maxlen) || (len > c->maxvis)) { - purple_debug_warning("oscar", "Could not send %s because (%i > maxlen %i) or (%i > maxvis %i)\n", + purple_debug_warning("oscar", + "Could not send %s because (%" G_GSIZE_FORMAT " > maxlen %i) or (%" G_GSIZE_FORMAT " > maxvis %i)\n", buf2, len, c->maxlen, len, c->maxvis); g_free(buf); g_free(buf2); @@ -5922,12 +4457,6 @@ message, buf2); } - if (charset == AIM_CHARSET_ASCII) - charsetstr = "us-ascii"; - else if (charset == AIM_CHARSET_UNICODE) - charsetstr = "unicode-2-0"; - else if (charset == AIM_CHARSET_LATIN_1) - charsetstr = "iso-8859-1"; aim_chat_send_im(od, c->conn, 0, buf2, len, charsetstr, "en"); g_free(buf2); g_free(buf); @@ -6082,7 +4611,7 @@ tmp1 = purple_markup_strip_html(message); purple_util_chrreplace(tmp1, '\n', ' '); tmp2 = g_markup_escape_text(tmp1, -1); - ret = purple_str_sub_away_formatters(tmp2, purple_account_get_username(account)); + ret = oscar_util_format_string(tmp2, purple_account_get_username(account)); g_free(tmp1); g_free(tmp2); } @@ -6099,67 +4628,40 @@ return ret; } -void oscar_set_permit_deny(PurpleConnection *gc) { +void oscar_set_aim_permdeny(PurpleConnection *gc) { PurpleAccount *account = purple_connection_get_account(gc); OscarData *od = purple_connection_get_protocol_data(gc); - PurplePrivacyType perm_deny; /* - * For ICQ the permit/deny setting controls who you can see you - * online when you set your status to "invisible." If we're ICQ - * and we're invisible then we need to use one of - * PURPLE_PRIVACY_ALLOW_USERS or PURPLE_PRIVACY_ALLOW_BUDDYLIST or - * PURPLE_PRIVACY_DENY_USERS if we actually want to be invisible - * to anyone. - * - * These three permit/deny settings correspond to: - * 1. Invisible to everyone except the people on my "permit" list - * 2. Invisible to everyone except the people on my buddy list - * 3. Invisible only to the people on my "deny" list - * - * It would be nice to allow cases 2 and 3, but our UI doesn't have - * a nice way to do it. For now we just force case 1. + * Conveniently there is a one-to-one mapping between the + * values of libpurple's PurplePrivacyType and the values used + * by the oscar protocol. */ - if (od->icq && purple_account_is_status_active(account, OSCAR_STATUS_ID_INVISIBLE)) - perm_deny = PURPLE_PRIVACY_ALLOW_USERS; - else - perm_deny = account->perm_deny; - - if (od->ssi.received_data) - /* - * Conveniently there is a one-to-one mapping between the - * values of libpurple's PurplePrivacyType and the values used - * by the oscar protocol. - */ - aim_ssi_setpermdeny(od, perm_deny, 0xffffffff); + aim_ssi_setpermdeny(od, account->perm_deny); } void oscar_add_permit(PurpleConnection *gc, const char *who) { OscarData *od = purple_connection_get_protocol_data(gc); purple_debug_info("oscar", "ssi: About to add a permit\n"); - if (od->ssi.received_data) - aim_ssi_addpermit(od, who); + aim_ssi_add_to_private_list(od, who, AIM_SSI_TYPE_PERMIT); } void oscar_add_deny(PurpleConnection *gc, const char *who) { OscarData *od = purple_connection_get_protocol_data(gc); purple_debug_info("oscar", "ssi: About to add a deny\n"); - if (od->ssi.received_data) - aim_ssi_adddeny(od, who); + aim_ssi_add_to_private_list(od, who, aim_ssi_getdenyentrytype(od)); } void oscar_rem_permit(PurpleConnection *gc, const char *who) { OscarData *od = purple_connection_get_protocol_data(gc); purple_debug_info("oscar", "ssi: About to delete a permit\n"); - if (od->ssi.received_data) - aim_ssi_delpermit(od, who); + aim_ssi_del_from_private_list(od, who, AIM_SSI_TYPE_PERMIT); } void oscar_rem_deny(PurpleConnection *gc, const char *who) { OscarData *od = purple_connection_get_protocol_data(gc); purple_debug_info("oscar", "ssi: About to delete a deny\n"); - if (od->ssi.received_data) - aim_ssi_deldeny(od, who); + aim_ssi_del_from_private_list(od, who, aim_ssi_getdenyentrytype(od)); } GList * @@ -6491,7 +4993,6 @@ static GList * oscar_buddy_menu(PurpleBuddy *buddy) { - PurpleConnection *gc; OscarData *od; GList *menu; @@ -6529,6 +5030,7 @@ PURPLE_CALLBACK(oscar_get_icqxstatusmsg), NULL, NULL); menu = g_list_prepend(menu, act); + menu = g_list_prepend(menu, create_visibility_menu_item(od, bname)); } if (userinfo && @@ -6554,15 +5056,6 @@ } menu = g_list_prepend(menu, act); } -#if 0 - /* TODO: This menu item should be added by the core */ - if (userinfo->capabilities & OSCAR_CAPABILITY_GETFILE) { - act = purple_menu_action_new(_("Get File"), - PURPLE_CALLBACK(oscar_ask_getfile), - NULL, NULL); - menu = g_list_prepend(menu, act); - } -#endif } if (od->ssi.received_data && purple_buddy_get_group(buddy) != NULL) @@ -6576,7 +5069,7 @@ if (gname && aim_ssi_waitingforauth(od->ssi.local, gname, bname)) { act = purple_menu_action_new(_("Re-request Authorization"), - PURPLE_CALLBACK(purple_auth_sendrequest_menu), + PURPLE_CALLBACK(oscar_auth_sendrequest_menu), NULL, NULL); menu = g_list_prepend(menu, act); } @@ -6613,7 +5106,7 @@ purple_account_set_bool(account, "authorization", auth); purple_account_set_bool(account, "web_aware", web_aware); - oscar_set_extendedstatus(gc); + oscar_set_extended_status(gc); aim_icq_setsecurity(od, auth, web_aware); } @@ -6728,41 +5221,29 @@ { PurpleConnection *gc = (PurpleConnection *) action->context; OscarData *od = purple_connection_get_protocol_data(gc); - gchar *text, *tmp; - GSList *buddies; - PurpleAccount *account; - int num=0; - - text = g_strdup(""); - account = purple_connection_get_account(gc); + PurpleAccount *account = purple_connection_get_account(gc); + GSList *buddies, *filtered_buddies, *cur; + gchar *text; buddies = purple_find_buddies(account, NULL); - while (buddies) { + filtered_buddies = NULL; + for (cur = buddies; cur != NULL; cur = cur->next) { PurpleBuddy *buddy; const gchar *bname, *gname; - buddy = buddies->data; + buddy = cur->data; bname = purple_buddy_get_name(buddy); gname = purple_group_get_name(purple_buddy_get_group(buddy)); if (aim_ssi_waitingforauth(od->ssi.local, gname, bname)) { - const gchar *alias = purple_buddy_get_alias_only(buddy); - if (alias) - tmp = g_strdup_printf("%s %s (%s)
", text, bname, alias); - else - tmp = g_strdup_printf("%s %s
", text, bname); - g_free(text); - text = tmp; - - num++; + filtered_buddies = g_slist_prepend(filtered_buddies, buddy); } - - buddies = g_slist_delete_link(buddies, buddies); } - if (!num) { - g_free(text); - text = g_strdup(_("you are not waiting for authorization")); - } + g_slist_free(buddies); + + filtered_buddies = g_slist_reverse(filtered_buddies); + text = oscar_format_buddies(filtered_buddies, _("you are not waiting for authorization")); + g_slist_free(filtered_buddies); purple_notify_formatted(gc, NULL, _("You are awaiting authorization from " "the following buddies"), _("You can re-request " @@ -6977,6 +5458,12 @@ act = purple_plugin_action_new(_("Set Privacy Options..."), oscar_show_icq_privacy_opts); menu = g_list_prepend(menu, act); + + act = purple_plugin_action_new("Show Visible List", oscar_show_visible_list); + menu = g_list_prepend(menu, act); + + act = purple_plugin_action_new("Show Invisible List", oscar_show_invisible_list); + menu = g_list_prepend(menu, act); } else { @@ -7006,12 +5493,6 @@ oscar_show_find_email); menu = g_list_prepend(menu, act); -#if 0 - act = purple_plugin_action_new(_("Search for Buddy by Information"), - show_find_info); - menu = g_list_prepend(menu, act); -#endif - menu = g_list_reverse(menu); return menu; diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/oscar.h --- a/libpurple/protocols/oscar/oscar.h Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/oscar.h Fri Aug 20 08:35:27 2010 +0000 @@ -103,16 +103,6 @@ #define AIM_ICONIDENT "AVT1picture.id" /* - * Current Maximum Length for Chat Room Messages - * - * This is actually defined by the protocol to be - * dynamic, but I have yet to see due cause to - * define it dynamically here. Maybe later. - * - */ -#define MAXCHATMSGLEN 512 - -/* * Found by trial and error. */ #define MAXAVAILMSGLEN 251 @@ -143,167 +133,6 @@ const char *lang; /* two-letter abbrev */ }; -/* Needs to be checked */ -#define CLIENTINFO_AIM_3_5_1670 { \ - "AOL Instant Messenger (SM), version 3.5.1670/WIN32", \ - 0x0004, \ - 0x0003, 0x0005, \ - 0x0000, 0x0686, \ - 0x0000002a, \ - "us", "en", \ -} - -/* Needs to be checked */ -/* Latest winaim without ssi */ -#define CLIENTINFO_AIM_4_1_2010 { \ - "AOL Instant Messenger (SM), version 4.1.2010/WIN32", \ - 0x0004, \ - 0x0004, 0x0001, \ - 0x0000, 0x07da, \ - 0x0000004b, \ - "us", "en", \ -} - -/* Needs to be checked */ -#define CLIENTINFO_AIM_4_3_2188 { \ - "AOL Instant Messenger (SM), version 4.3.2188/WIN32", \ - 0x0109, \ - 0x0400, 0x0003, \ - 0x0000, 0x088c, \ - 0x00000086, \ - "us", "en", \ -} - -/* Needs to be checked */ -#define CLIENTINFO_AIM_4_8_2540 { \ - "AOL Instant Messenger (SM), version 4.8.2540/WIN32", \ - 0x0109, \ - 0x0004, 0x0008, \ - 0x0000, 0x09ec, \ - 0x000000af, \ - "us", "en", \ -} - -/* Needs to be checked */ -#define CLIENTINFO_AIM_5_0_2938 { \ - "AOL Instant Messenger, version 5.0.2938/WIN32", \ - 0x0109, \ - 0x0005, 0x0000, \ - 0x0000, 0x0b7a, \ - 0x00000000, \ - "us", "en", \ -} - -#define CLIENTINFO_AIM_5_1_3036 { \ - "AOL Instant Messenger, version 5.1.3036/WIN32", \ - 0x0109, \ - 0x0005, 0x0001, \ - 0x0000, 0x0bdc, \ - 0x000000d2, \ - "us", "en", \ -} - -#define CLIENTINFO_AIM_5_5_3415 { \ - "AOL Instant Messenger, version 5.5.3415/WIN32", \ - 0x0109, \ - 0x0005, 0x0005, \ - 0x0000, 0x0057, \ - 0x000000ef, \ - "us", "en", \ -} - -#define CLIENTINFO_AIM_5_9_3702 { \ - "AOL Instant Messenger, version 5.9.3702/WIN32", \ - 0x0109, \ - 0x0005, 0x0009, \ - 0x0000, 0x0e76, \ - 0x00000111, \ - "us", "en", \ -} - -#define CLIENTINFO_ICHAT_1_0 { \ - "Apple iChat", \ - 0x311a, \ - 0x0001, 0x0000, \ - 0x0000, 0x003c, \ - 0x000000c6, \ - "us", "en", \ -} - -/* Needs to be checked */ -#define CLIENTINFO_ICQ_4_65_3281 { \ - "ICQ Inc. - Product of ICQ (TM) 2000b.4.65.1.3281.85", \ - 0x010a, \ - 0x0004, 0x0041, \ - 0x0001, 0x0cd1, \ - 0x00000055, \ - "us", "en", \ -} - -/* Needs to be checked */ -#define CLIENTINFO_ICQ_5_34_3728 { \ - "ICQ Inc. - Product of ICQ (TM).2002a.5.34.1.3728.85", \ - 0x010a, \ - 0x0005, 0x0022, \ - 0x0001, 0x0e8f, \ - 0x00000055, \ - "us", "en", \ -} - -#define CLIENTINFO_ICQ_5_45_3777 { \ - "ICQ Inc. - Product of ICQ (TM).2003a.5.45.1.3777.85", \ - 0x010a, \ - 0x0005, 0x002d, \ - 0x0001, 0x0ec1, \ - 0x00000055, \ - "us", "en", \ -} - -#define CLIENTINFO_ICQ6_6_0_6059 { \ - "ICQ Client", \ - 0x010a, \ - 0x0006, 0x0000, \ - 0x0000, 0x17ab, \ - 0x00007535, \ - "us", "en", \ -} - -#define CLIENTINFO_ICQBASIC_14_3_1068 { \ - "ICQBasic", \ - 0x010a, \ - 0x0014, 0x0003, \ - 0x0000, 0x042c, \ - 0x0000043d, \ - "us", "en", \ -} - -#define CLIENTINFO_ICQBASIC_14_34_3000 { \ - "ICQBasic", \ - 0x010a, \ - 0x0014, 0x0034, \ - 0x0000, 0x0bb8, \ - 0x0000043d, \ - "us", "en", \ -} - -#define CLIENTINFO_ICQBASIC_14_34_3096 { \ - "ICQBasic", \ - 0x010a, \ - 0x0014, 0x0034, \ - 0x0000, 0x0c18, \ - 0x0000043d, \ - "us", "en", \ -} - -#define CLIENTINFO_NETSCAPE_7_0_1 { \ - "Netscape 2000 an approved user of AOL Instant Messenger (SM)", \ - 0x1d0d, \ - 0x0007, 0x0000, \ - 0x0001, 0x0000, \ - 0x00000058, \ - "us", "en", \ -} - /* * We need to use the major-minor-micro versions from the official * AIM and ICQ programs here or AOL won't let us use certain features. @@ -329,9 +158,6 @@ "us", "en", \ } -#define CLIENTINFO_AIM_KNOWNGOOD CLIENTINFO_AIM_5_1_3036 -#define CLIENTINFO_ICQ_KNOWNGOOD CLIENTINFO_ICQBASIC_14_34_3096 - typedef enum { OSCAR_DISCONNECT_DONE, /* not considered an error */ @@ -376,7 +202,24 @@ #define OSCAR_CAPABILITY_NEWCAPS 0x0000000020000000LL #define OSCAR_CAPABILITY_XTRAZ 0x0000000040000000LL #define OSCAR_CAPABILITY_GENERICUNKNOWN 0x0000000080000000LL -#define OSCAR_CAPABILITY_LAST 0x0000000100000000LL +#define OSCAR_CAPABILITY_HTML_MSGS 0x0000000100000000LL +#define OSCAR_CAPABILITY_LAST 0x0000000200000000LL + +#define OSCAR_STATUS_ID_INVISIBLE "invisible" +#define OSCAR_STATUS_ID_OFFLINE "offline" +#define OSCAR_STATUS_ID_AVAILABLE "available" +#define OSCAR_STATUS_ID_AWAY "away" +#define OSCAR_STATUS_ID_DND "dnd" +#define OSCAR_STATUS_ID_NA "na" +#define OSCAR_STATUS_ID_OCCUPIED "occupied" +#define OSCAR_STATUS_ID_FREE4CHAT "free4chat" +#define OSCAR_STATUS_ID_CUSTOM "custom" +#define OSCAR_STATUS_ID_MOBILE "mobile" +#define OSCAR_STATUS_ID_EVIL "evil" +#define OSCAR_STATUS_ID_DEPRESSION "depression" +#define OSCAR_STATUS_ID_ATHOME "athome" +#define OSCAR_STATUS_ID_ATWORK "atwork" +#define OSCAR_STATUS_ID_LUNCH "lunch" /* * Byte Stream type. Sort of. @@ -395,8 +238,8 @@ struct _ByteStream { guint8 *data; - guint32 len; - guint32 offset; + size_t len; + size_t offset; }; struct _QueuedSnac @@ -526,7 +369,7 @@ */ IcbmCookie *msgcookies; - struct aim_icq_info *icq_info; + GSList *icq_info; /** Only used when connecting with the old-style BUCP login. */ struct aim_authresp_info *authinfo; @@ -580,10 +423,8 @@ #define AIM_ICQ_STATE_WEBAWARE 0x00010000 #define AIM_ICQ_STATE_HIDEIP 0x00020000 #define AIM_ICQ_STATE_BIRTHDAY 0x00080000 -#define AIM_ICQ_STATE_DIRECTDISABLED 0x00100000 #define AIM_ICQ_STATE_ICQHOMEPAGE 0x00200000 #define AIM_ICQ_STATE_DIRECTREQUIREAUTH 0x10000000 -#define AIM_ICQ_STATE_DIRECTCONTACTLIST 0x20000000 /** * Only used when connecting with the old-style BUCP login. @@ -669,8 +510,8 @@ void flap_connection_send_version(OscarData *od, FlapConnection *conn); void flap_connection_send_version_with_cookie(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy); void flap_connection_send_version_with_cookie_and_clientinfo(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy, ClientInfo *ci, gboolean allow_multiple_login); -void flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data); -void flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data, gboolean high_priority); +void flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data); +void flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data, gboolean high_priority); void flap_connection_send_keepalive(OscarData *od, FlapConnection *conn); FlapFrame *flap_frame_new(OscarData *od, guint16 channel, int datalen); @@ -682,64 +523,26 @@ void oscar_data_addhandler(OscarData *od, guint16 family, guint16 subtype, aim_rxcallback_t newhandler, guint16 flags); aim_rxcallback_t aim_callhandler(OscarData *od, guint16 family, guint16 subtype); -/* misc.c */ -#define AIM_VISIBILITYCHANGE_PERMITADD 0x05 -#define AIM_VISIBILITYCHANGE_PERMITREMOVE 0x06 -#define AIM_VISIBILITYCHANGE_DENYADD 0x07 -#define AIM_VISIBILITYCHANGE_DENYREMOVE 0x08 - -#define AIM_PRIVFLAGS_ALLOWIDLE 0x01 -#define AIM_PRIVFLAGS_ALLOWMEMBERSINCE 0x02 - -#define AIM_WARN_ANON 0x01 - - - /* 0x0001 - family_oservice.c */ /* 0x0002 */ void aim_srv_clientready(OscarData *od, FlapConnection *conn); /* 0x0004 */ void aim_srv_requestnew(OscarData *od, guint16 serviceid); /* 0x0006 */ void aim_srv_reqrates(OscarData *od, FlapConnection *conn); /* 0x0008 */ void aim_srv_rates_addparam(OscarData *od, FlapConnection *conn); -/* 0x0009 */ void aim_srv_rates_delparam(OscarData *od, FlapConnection *conn); -/* 0x000c */ void aim_srv_sendpauseack(OscarData *od, FlapConnection *conn); /* 0x000e */ void aim_srv_reqpersonalinfo(OscarData *od, FlapConnection *conn); /* 0x0011 */ void aim_srv_setidle(OscarData *od, guint32 idletime); -/* 0x0014 */ void aim_srv_setprivacyflags(OscarData *od, FlapConnection *conn, guint32); -/* 0x0016 */ void aim_srv_nop(OscarData *od, FlapConnection *conn); /* 0x0017 */ void aim_srv_setversions(OscarData *od, FlapConnection *conn); /* 0x001e */ int aim_srv_setextrainfo(OscarData *od, gboolean seticqstatus, guint32 icqstatus, gboolean setstatusmsg, const char *statusmsg, const char *itmsurl); +void aim_srv_set_dc_info(OscarData *od); void aim_bos_reqrights(OscarData *od, FlapConnection *conn); -int aim_bos_changevisibility(OscarData *od, FlapConnection *conn, int, const char *); -void aim_bos_setgroupperm(OscarData *od, FlapConnection *conn, guint32 mask); - - -#define AIM_CLIENTTYPE_UNKNOWN 0x0000 -#define AIM_CLIENTTYPE_MC 0x0001 -#define AIM_CLIENTTYPE_WINAIM 0x0002 -#define AIM_CLIENTTYPE_WINAIM41 0x0003 -#define AIM_CLIENTTYPE_AOL_TOC 0x0004 -guint16 aim_im_fingerprint(const guint8 *msghdr, int len); - -#define AIM_RATE_CODE_CHANGE 0x0001 -#define AIM_RATE_CODE_WARNING 0x0002 #define AIM_RATE_CODE_LIMIT 0x0003 -#define AIM_RATE_CODE_CLEARLIMIT 0x0004 -void aim_ads_requestads(OscarData *od, FlapConnection *conn); - - /* family_icbm.c */ -#define AIM_OFT_SUBTYPE_SEND_FILE 0x0001 #define AIM_OFT_SUBTYPE_SEND_DIR 0x0002 -#define AIM_OFT_SUBTYPE_GET_FILE 0x0011 -#define AIM_OFT_SUBTYPE_GET_LIST 0x0012 -#define AIM_TRANSFER_DENY_NOTSUPPORTED 0x0000 #define AIM_TRANSFER_DENY_DECLINE 0x0001 -#define AIM_TRANSFER_DENY_NOTACCEPTING 0x0002 #define AIM_IMPARAM_FLAG_CHANNEL_MSGS_ALLOWED 0x00000001 #define AIM_IMPARAM_FLAG_MISSED_CALLS_ENABLED 0x00000002 @@ -761,26 +564,6 @@ */ #define AIM_IMPARAM_FLAG_USE_HTML_FOR_ICQ 0x00000400 -/* This is what the server will give you if you don't set them yourself. */ -/* This is probably out of date. */ -#define AIM_IMPARAM_DEFAULTS { \ - 0, \ - AIM_IMPARAM_FLAG_CHANNEL_MSGS_ALLOWED | AIM_IMPARAM_FLAG_MISSED_CALLS_ENABLED, \ - 512, /* !! Note how small this is. */ \ - (99.9)*10, (99.9)*10, \ - 1000 /* !! And how large this is. */ \ -} - -/* This is what most AIM versions use. */ -/* This is probably out of date. */ -#define AIM_IMPARAM_REASONABLE { \ - 0, \ - AIM_IMPARAM_FLAG_CHANNEL_MSGS_ALLOWED | AIM_IMPARAM_FLAG_MISSED_CALLS_ENABLED, \ - 8000, \ - (99.9)*10, (99.9)*10, \ - 0 \ -} - struct aim_icbmparameters { guint16 maxchan; @@ -827,9 +610,6 @@ #define AIM_IMFLAGS_HASICON 0x0020 /* already has icon */ #define AIM_IMFLAGS_SUBENC_MACINTOSH 0x0040 /* damn that Steve Jobs! */ #define AIM_IMFLAGS_CUSTOMFEATURES 0x0080 /* features field present */ -#define AIM_IMFLAGS_EXTDATA 0x0100 -#define AIM_IMFLAGS_X 0x0200 -#define AIM_IMFLAGS_MULTIPART 0x0400 /* ->mpmsg section valid */ #define AIM_IMFLAGS_OFFLINE 0x0800 /* send to offline user */ #define AIM_IMFLAGS_TYPINGNOT 0x1000 /* typing notification */ @@ -838,30 +618,6 @@ #define AIM_CHARSET_LATIN_1 0x0003 /* ISO 8859-1 */ /* - * Multipart message structures. - */ -typedef struct aim_mpmsg_section_s -{ - guint16 charset; - guint16 charsubset; - gchar *data; - guint16 datalen; - struct aim_mpmsg_section_s *next; -} aim_mpmsg_section_t; - -typedef struct aim_mpmsg_s -{ - unsigned int numparts; - aim_mpmsg_section_t *parts; -} aim_mpmsg_t; - -int aim_mpmsg_init(OscarData *od, aim_mpmsg_t *mpm); -int aim_mpmsg_addraw(OscarData *od, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, const gchar *data, guint16 datalen); -int aim_mpmsg_addascii(OscarData *od, aim_mpmsg_t *mpm, const char *ascii); -int aim_mpmsg_addunicode(OscarData *od, aim_mpmsg_t *mpm, const guint16 *unicode, guint16 unicodelen); -void aim_mpmsg_free(OscarData *od, aim_mpmsg_t *mpm); - -/* * Arguments to aim_send_im_ext(). * * This is really complicated. But immensely versatile. @@ -869,84 +625,39 @@ */ struct aim_sendimext_args { - /* These are _required_ */ const char *destbn; guint32 flags; /* often 0 */ - /* Only required if not using multipart messages */ const char *msg; - int msglen; - - /* Required if ->msg is not provided */ - aim_mpmsg_t *mpmsg; + gsize msglen; /* Only used if AIM_IMFLAGS_HASICON is set */ guint32 iconlen; time_t iconstamp; guint32 iconsum; - /* Only used if AIM_IMFLAGS_CUSTOMFEATURES is set */ guint16 featureslen; guint8 *features; - /* Only used if AIM_IMFLAGS_CUSTOMCHARSET is set and mpmsg not used */ guint16 charset; - guint16 charsubset; -}; - -/* - * Arguments to aim_send_rtfmsg(). - */ -struct aim_sendrtfmsg_args -{ - const char *destbn; - guint32 fgcolor; - guint32 bgcolor; - const char *rtfmsg; /* must be in RTF */ }; /* * This information is provided in the Incoming ICBM callback for * Channel 1 ICBM's. - * - * Note that although CUSTOMFEATURES and CUSTOMCHARSET say they - * are optional, both are always set by the current libfaim code. - * That may or may not change in the future. It is mainly for - * consistency with aim_sendimext_args. - * - * Multipart messages require some explanation. If you want to use them, - * I suggest you read all the comments in family_icbm.c. - * */ struct aim_incomingim_ch1_args { - - /* Always provided */ - aim_mpmsg_t mpmsg; guint32 icbmflags; /* some flags apply only to ->msg, not all mpmsg */ time_t timestamp; /* Only set for offline messages */ - /* Only provided if message has a human-readable section */ gchar *msg; - int msglen; /* Only provided if AIM_IMFLAGS_HASICON is set */ time_t iconstamp; guint32 iconlen; guint16 iconsum; - - /* Only provided if AIM_IMFLAGS_CUSTOMFEATURES is set */ - guint8 *features; - guint8 featureslen; - - /* Only provided if AIM_IMFLAGS_EXTDATA is set */ - guint8 extdatalen; - guint8 *extdata; - - /* Only used if AIM_IMFLAGS_CUSTOMCHARSET is set */ - guint16 charset; - guint16 charsubset; }; /* Valid values for channel 2 args->status */ @@ -981,10 +692,8 @@ struct aim_chat_roominfo roominfo; } chat; struct { - guint16 msgtype; - guint32 fgcolor; - guint32 bgcolor; - const char *rtfmsg; + guint8 msgtype; + const char *msg; } rtfmsg; struct { guint16 subtype; @@ -996,11 +705,6 @@ void *destructor; /* used internally only */ }; -/* Valid values for channel 4 args->type */ -#define AIM_ICQMSG_AUTHREQUEST 0x0006 -#define AIM_ICQMSG_AUTHDENIED 0x0007 -#define AIM_ICQMSG_AUTHGRANTED 0x0008 - struct aim_incomingim_ch4_args { guint32 uin; /* Of the sender of the ICBM */ @@ -1017,7 +721,6 @@ /* 0x0006 */ int aim_im_sendch1(OscarData *, const char *destbn, guint16 flags, const char *msg); /* 0x0006 */ int aim_im_sendch2_chatinvite(OscarData *od, const char *bn, const char *msg, guint16 exchange, const char *roomname, guint16 instance); /* 0x0006 */ int aim_im_sendch2_icon(OscarData *od, const char *bn, const guint8 *icon, int iconlen, time_t stamp, guint16 iconsum); -/* 0x0006 */ int aim_im_sendch2_rtfmsg(OscarData *od, struct aim_sendrtfmsg_args *args); /* 0x0006 */ void aim_im_sendch2_cancel(PeerConnection *peer_conn); /* 0x0006 */ void aim_im_sendch2_connected(PeerConnection *peer_conn); @@ -1026,38 +729,23 @@ /* 0x0006 */ void aim_im_sendch2_sendfile_requestdirect(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 port, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles); /* 0x0006 */ void aim_im_sendch2_sendfile_requestproxy(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 pin, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles); -/* 0x0006 */ int aim_im_sendch2_geticqaway(OscarData *od, const char *bn, int type); -/* 0x0006 */ int aim_im_sendch4(OscarData *od, const char *bn, guint16 type, const char *message); -/* 0x0008 */ int aim_im_warn(OscarData *od, FlapConnection *conn, const char *destbn, guint32 flags); /* 0x000b */ int aim_im_denytransfer(OscarData *od, const char *bn, const guchar *cookie, guint16 code); /* 0x0010 */ int aim_im_reqofflinemsgs(OscarData *od); /* 0x0014 */ int aim_im_sendmtn(OscarData *od, guint16 type1, const char *bn, guint16 type2); /* 0x000b */ int icq_relay_xstatus (OscarData *od, const char *sn, const guchar* cookie); void aim_icbm_makecookie(guchar* cookie); -gchar *oscar_encoding_extract(const char *encoding); -gchar *oscar_encoding_to_utf8(PurpleAccount *account, const char *encoding, const char *text, int textlen); -gchar *purple_plugin_oscar_decode_im_part(PurpleAccount *account, const char *sourcebn, guint16 charset, guint16 charsubset, const gchar *data, gsize datalen); - +void aim_im_send_icq_confirmation(OscarData *od, const char *bn, const guchar *cookie); /* 0x0002 - family_locate.c */ /* * AIM User Info, Standard Form. */ -#define AIM_FLAG_UNCONFIRMED 0x0001 /* "damned transients" */ #define AIM_FLAG_ADMINISTRATOR 0x0002 #define AIM_FLAG_AOL 0x0004 -#define AIM_FLAG_OSCAR_PAY 0x0008 -#define AIM_FLAG_FREE 0x0010 #define AIM_FLAG_AWAY 0x0020 -#define AIM_FLAG_ICQ 0x0040 #define AIM_FLAG_WIRELESS 0x0080 -#define AIM_FLAG_UNKNOWN100 0x0100 -#define AIM_FLAG_IMFORWARDING 0x0200 +#define AIM_FLAG_ICQ 0x0040 #define AIM_FLAG_ACTIVEBUDDY 0x0400 -#define AIM_FLAG_UNKNOWN800 0x0800 -#define AIM_FLAG_ONEWAYWIRELESS 0x1000 -#define AIM_FLAG_NOKNOCKKNOCK 0x00040000 -#define AIM_FLAG_FORWARD_MOBILE 0x00080000 #define AIM_USERINFO_PRESENT_FLAGS 0x00000001 #define AIM_USERINFO_PRESENT_MEMBERSINCE 0x00000002 @@ -1130,22 +818,8 @@ guint16 instance; }; -#define AIM_COOKIETYPE_UNKNOWN 0x00 -#define AIM_COOKIETYPE_ICBM 0x01 -#define AIM_COOKIETYPE_ADS 0x02 -#define AIM_COOKIETYPE_BOS 0x03 -#define AIM_COOKIETYPE_IM 0x04 -#define AIM_COOKIETYPE_CHAT 0x05 -#define AIM_COOKIETYPE_CHATNAV 0x06 -#define AIM_COOKIETYPE_INVITE 0x07 -/* we'll move OFT up a bit to give breathing room. not like it really - * matters. */ -#define AIM_COOKIETYPE_OFTIM 0x10 -#define AIM_COOKIETYPE_OFTGET 0x11 -#define AIM_COOKIETYPE_OFTSEND 0x12 -#define AIM_COOKIETYPE_OFTVOICE 0x13 -#define AIM_COOKIETYPE_OFTIMAGE 0x14 -#define AIM_COOKIETYPE_OFTICON 0x15 +#define AIM_COOKIETYPE_CHAT 0x01 +#define AIM_COOKIETYPE_INVITE 0x02 aim_userinfo_t *aim_locate_finduserinfo(OscarData *od, const char *bn); void aim_locate_dorequest(OscarData *od); @@ -1153,10 +827,6 @@ /* 0x0002 */ int aim_locate_reqrights(OscarData *od); /* 0x0004 */ int aim_locate_setcaps(OscarData *od, guint64 caps); /* 0x0004 */ int aim_locate_setprofile(OscarData *od, const char *profile_encoding, const gchar *profile, const int profile_len, const char *awaymsg_encoding, const gchar *awaymsg, const int awaymsg_len); -/* 0x0005 */ int aim_locate_getinfo(OscarData *od, const char *, guint16); -/* 0x0009 */ int aim_locate_setdirinfo(OscarData *od, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, guint16 privacy); -/* 0x000b */ int aim_locate_000b(OscarData *od, const char *bn); -/* 0x000f */ int aim_locate_setinterests(OscarData *od, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, guint16 privacy); /* 0x0015 */ int aim_locate_getinfoshort(OscarData *od, const char *bn, guint32 flags); guint64 aim_locate_getcaps(OscarData *od, ByteStream *bs, int len); @@ -1171,25 +841,11 @@ /* 0x0003 - family_buddy.c */ /* 0x0002 */ void aim_buddylist_reqrights(OscarData *, FlapConnection *); -/* 0x0004 */ int aim_buddylist_set(OscarData *, FlapConnection *, const char *); -/* 0x0004 */ int aim_buddylist_addbuddy(OscarData *, FlapConnection *, const char *); -/* 0x0005 */ int aim_buddylist_removebuddy(OscarData *, FlapConnection *, const char *); - /* 0x000a - family_userlookup.c */ int aim_search_address(OscarData *, const char *); - - -/* 0x000d - family_chatnav.c */ -/* 0x000e - family_chat.c */ -/* These apply to exchanges as well. */ -#define AIM_CHATROOM_FLAG_EVILABLE 0x0001 -#define AIM_CHATROOM_FLAG_NAV_ONLY 0x0002 -#define AIM_CHATROOM_FLAG_INSTANCING_ALLOWED 0x0004 -#define AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED 0x0008 - struct aim_chat_exchangeinfo { guint16 number; @@ -1205,41 +861,10 @@ #define AIM_CHATFLAGS_AWAY 0x0002 int aim_chat_send_im(OscarData *od, FlapConnection *conn, guint16 flags, const gchar *msg, int msglen, const char *encoding, const char *language); int aim_chat_join(OscarData *od, guint16 exchange, const char *roomname, guint16 instance); -int aim_chat_attachname(FlapConnection *conn, guint16 exchange, const char *roomname, guint16 instance); -char *aim_chat_getname(FlapConnection *conn); -FlapConnection *aim_chat_getconn(OscarData *, const char *name); void aim_chatnav_reqrights(OscarData *od, FlapConnection *conn); int aim_chatnav_createroom(OscarData *od, FlapConnection *conn, const char *name, guint16 exchange); -int aim_chat_leaveroom(OscarData *od, const char *name); - - - -/* 0x000f - family_odir.c */ -struct aim_odir -{ - char *first; - char *last; - char *middle; - char *maiden; - char *email; - char *country; - char *state; - char *city; - char *bn; - char *interest; - char *nick; - char *zip; - char *region; - char *address; - struct aim_odir *next; -}; - -int aim_odir_email(OscarData *, const char *, const char *); -int aim_odir_name(OscarData *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *); -int aim_odir_interest(OscarData *, const char *, const char *); - /* 0x0010 - family_bart.c */ @@ -1255,15 +880,9 @@ #define AIM_SSI_TYPE_DENY 0x0003 #define AIM_SSI_TYPE_PDINFO 0x0004 #define AIM_SSI_TYPE_PRESENCEPREFS 0x0005 +#define AIM_SSI_TYPE_ICQDENY 0x000e #define AIM_SSI_TYPE_ICONINFO 0x0014 -#define AIM_SSI_ACK_SUCCESS 0x0000 -#define AIM_SSI_ACK_ITEMNOTFOUND 0x0002 -#define AIM_SSI_ACK_IDNUMINUSE 0x000a -#define AIM_SSI_ACK_ATMAX 0x000c -#define AIM_SSI_ACK_INVALIDNAME 0x000d -#define AIM_SSI_ACK_AUTHREQUIRED 0x000e - /* These flags are set in the 0x00c9 TLV of SSI type 0x0005 */ #define AIM_SSI_PRESENCE_FLAG_SHOWIDLE 0x00000400 #define AIM_SSI_PRESENCE_FLAG_NORECENTBUDDIES 0x00020000 @@ -1290,11 +909,9 @@ /* These build the actual SNACs and queue them to be sent */ /* 0x0002 */ int aim_ssi_reqrights(OscarData *od); /* 0x0004 */ int aim_ssi_reqdata(OscarData *od); -/* 0x0005 */ int aim_ssi_reqifchanged(OscarData *od, time_t localstamp, guint16 localrev); /* 0x0007 */ int aim_ssi_enable(OscarData *od); /* 0x0011 */ int aim_ssi_modbegin(OscarData *od); /* 0x0012 */ int aim_ssi_modend(OscarData *od); -/* 0x0014 */ int aim_ssi_sendauth(OscarData *od, char *bn, char *msg); /* 0x0018 */ int aim_ssi_sendauthrequest(OscarData *od, char *bn, const char *msg); /* 0x001a */ int aim_ssi_sendauthreply(OscarData *od, char *bn, guint8 reply, const char *msg); @@ -1311,49 +928,22 @@ /* Client functions for changing SSI data */ int aim_ssi_addbuddy(OscarData *od, const char *name, const char *group, GSList *tlvlist, const char *alias, const char *comment, const char *smsnum, gboolean needauth); -int aim_ssi_addpermit(OscarData *od, const char *name); -int aim_ssi_adddeny(OscarData *od, const char *name); int aim_ssi_delbuddy(OscarData *od, const char *name, const char *group); int aim_ssi_delgroup(OscarData *od, const char *group); -int aim_ssi_delpermit(OscarData *od, const char *name); -int aim_ssi_deldeny(OscarData *od, const char *name); int aim_ssi_movebuddy(OscarData *od, const char *oldgn, const char *newgn, const char *bn); int aim_ssi_aliasbuddy(OscarData *od, const char *gn, const char *bn, const char *alias); int aim_ssi_editcomment(OscarData *od, const char *gn, const char *bn, const char *alias); int aim_ssi_rename_group(OscarData *od, const char *oldgn, const char *newgn); int aim_ssi_cleanlist(OscarData *od); int aim_ssi_deletelist(OscarData *od); -int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny, guint32 vismask); +int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny); int aim_ssi_setpresence(OscarData *od, guint32 presence); int aim_ssi_seticon(OscarData *od, const guint8 *iconsum, guint8 iconsumlen); int aim_ssi_delicon(OscarData *od); - - +int aim_ssi_add_to_private_list(OscarData *od, const char* name, guint16 list_type); +int aim_ssi_del_from_private_list(OscarData* od, const char* name, guint16 list_type); -/* 0x0015 - family_icq.c */ -#define AIM_ICQ_INFO_SIMPLE 0x001 -#define AIM_ICQ_INFO_SUMMARY 0x002 -#define AIM_ICQ_INFO_EMAIL 0x004 -#define AIM_ICQ_INFO_PERSONAL 0x008 -#define AIM_ICQ_INFO_ADDITIONAL 0x010 -#define AIM_ICQ_INFO_WORK 0x020 -#define AIM_ICQ_INFO_INTERESTS 0x040 -#define AIM_ICQ_INFO_ORGS 0x080 -#define AIM_ICQ_INFO_UNKNOWN 0x100 -#define AIM_ICQ_INFO_HAVEALL 0x1ff - -#ifdef OLDSTYLE_ICQ_OFFLINEMSGS -struct aim_icq_offlinemsg -{ - guint32 sender; - guint16 year; - guint8 month, day, hour, minute; - guint8 type; - guint8 flags; - char *msg; - int msglen; -}; -#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */ +guint16 aim_ssi_getdenyentrytype(OscarData* od); struct aim_icq_info { @@ -1410,22 +1000,17 @@ guint16 numaddresses; char **email2; - /* we keep track of these in a linked list because we're 1337 */ - struct aim_icq_info *next; - /* status note info */ guint8 icbm_cookie[8]; char *status_note_title; + + gboolean for_auth_request; + char *auth_request_reason; }; -#ifdef OLDSTYLE_ICQ_OFFLINEMSGS -int aim_icq_reqofflinemsgs(OscarData *od); -int aim_icq_ackofflinemsgs(OscarData *od); -#endif int aim_icq_setsecurity(OscarData *od, gboolean auth_required, gboolean webaware); int aim_icq_changepasswd(OscarData *od, const char *passwd); -int aim_icq_getsimpleinfo(OscarData *od, const char *uin); -int aim_icq_getalias(OscarData *od, const char *uin); +int aim_icq_getalias(OscarData *od, const char *uin, gboolean for_auth_request, char *auth_request_reason); int aim_icq_getallinfo(OscarData *od, const char *uin); int aim_icq_sendsms(OscarData *od, const char *name, const char *msg, const char *alias); @@ -1565,17 +1150,13 @@ gchar *oscar_get_clientstring(void); guint16 aimutil_iconsum(const guint8 *buf, int buflen); -int aimutil_tokslen(char *toSearch, int theindex, char dl); -int aimutil_itemcnt(char *toSearch, char dl); -char *aimutil_itemindex(char *toSearch, int theindex, char dl); gboolean oscar_util_valid_name(const char *bn); gboolean oscar_util_valid_name_icq(const char *bn); gboolean oscar_util_valid_name_sms(const char *bn); int oscar_util_name_compare(const char *bn1, const char *bn2); - - - +gchar *oscar_util_format_string(const char *str, const char *name); +gchar *oscar_format_buddies(GSList *buddies, const gchar *no_buddies_message); typedef struct { guint16 family; @@ -1617,11 +1198,7 @@ int chat_modfirst(OscarData *od, aim_module_t *mod); int locate_modfirst(OscarData *od, aim_module_t *mod); int service_modfirst(OscarData *od, aim_module_t *mod); -int invite_modfirst(OscarData *od, aim_module_t *mod); -int translate_modfirst(OscarData *od, aim_module_t *mod); int popups_modfirst(OscarData *od, aim_module_t *mod); -int adverts_modfirst(OscarData *od, aim_module_t *mod); -int odir_modfirst(OscarData *od, aim_module_t *mod); int bart_modfirst(OscarData *od, aim_module_t *mod); int ssi_modfirst(OscarData *od, aim_module_t *mod); int icq_modfirst(OscarData *od, aim_module_t *mod); @@ -1630,15 +1207,14 @@ void aim_genericreq_n(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype); void aim_genericreq_n_snacid(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype); void aim_genericreq_l(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint32 *); -void aim_genericreq_s(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint16 *); /* bstream.c */ -int byte_stream_new(ByteStream *bs, guint32 len); -int byte_stream_init(ByteStream *bs, guint8 *data, int len); +int byte_stream_new(ByteStream *bs, size_t len); +int byte_stream_init(ByteStream *bs, guint8 *data, size_t len); void byte_stream_destroy(ByteStream *bs); -int byte_stream_empty(ByteStream *bs); +int byte_stream_bytes_left(ByteStream *bs); int byte_stream_curpos(ByteStream *bs); -int byte_stream_setpos(ByteStream *bs, unsigned int off); +int byte_stream_setpos(ByteStream *bs, size_t off); void byte_stream_rewind(ByteStream *bs); int byte_stream_advance(ByteStream *bs, int n); guint8 byte_stream_get8(ByteStream *bs); @@ -1647,18 +1223,18 @@ guint8 byte_stream_getle8(ByteStream *bs); guint16 byte_stream_getle16(ByteStream *bs); guint32 byte_stream_getle32(ByteStream *bs); -int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, int len); -guint8 *byte_stream_getraw(ByteStream *bs, int len); -char *byte_stream_getstr(ByteStream *bs, int len); +int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, size_t len); +guint8 *byte_stream_getraw(ByteStream *bs, size_t len); +char *byte_stream_getstr(ByteStream *bs, size_t len); int byte_stream_put8(ByteStream *bs, guint8 v); int byte_stream_put16(ByteStream *bs, guint16 v); int byte_stream_put32(ByteStream *bs, guint32 v); int byte_stream_putle8(ByteStream *bs, guint8 v); int byte_stream_putle16(ByteStream *bs, guint16 v); int byte_stream_putle32(ByteStream *bs, guint32 v); -int byte_stream_putraw(ByteStream *bs, const guint8 *v, int len); +int byte_stream_putraw(ByteStream *bs, const guint8 *v, size_t len); int byte_stream_putstr(ByteStream *bs, const char *str); -int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, int len); +int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, size_t len); int byte_stream_putuid(ByteStream *bs, OscarData *od); int byte_stream_putcaps(ByteStream *bs, guint64 caps); @@ -1693,7 +1269,7 @@ aim_snacid_t aim_cachesnac(OscarData *od, const guint16 family, const guint16 type, const guint16 flags, const void *data, const int datalen); aim_snac_t *aim_remsnac(OscarData *, aim_snacid_t id); void aim_cleansnacs(OscarData *, int maxage); -int aim_putsnac(ByteStream *, guint16 family, guint16 type, guint16 flags, aim_snacid_t id); +int aim_putsnac(ByteStream *, guint16 family, guint16 type, aim_snacid_t id); struct chatsnacinfo { guint16 exchange; @@ -1720,13 +1296,53 @@ IcbmCookie *aim_mkcookie(guint8 *, int, void *); IcbmCookie *aim_checkcookie(OscarData *, const unsigned char *, const int); int aim_freecookie(OscarData *od, IcbmCookie *cookie); -int aim_msgcookie_gettype(guint64 type); int aim_cookie_free(OscarData *od, IcbmCookie *cookie); int aim_chat_readroominfo(ByteStream *bs, struct aim_chat_roominfo *outinfo); void flap_connection_destroy_chat(OscarData *od, FlapConnection *conn); +/* userinfo.c - displaying user information */ + +void oscar_user_info_append_status(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo, gboolean strip_html_tags); +void oscar_user_info_append_extra_info(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo); +void oscar_user_info_display_error(OscarData *od, guint16 error_reason, char *buddy); +void oscar_user_info_display_icq(OscarData *od, struct aim_icq_info *info); +void oscar_user_info_display_aim(OscarData *od, aim_userinfo_t *userinfo); + +/* authorization.c - OSCAR authorization requests */ +void oscar_auth_sendrequest(PurpleConnection *gc, const char *name); +void oscar_auth_sendrequest_menu(PurpleBlistNode *node, gpointer ignored); +void oscar_auth_recvrequest(PurpleConnection *gc, gchar *name, gchar *nick, gchar *reason); + +void oscar_set_aim_permdeny(PurpleConnection *gc); + +struct buddyinfo +{ + gboolean typingnot; + guint32 ipaddr; + + unsigned long ico_me_len; + unsigned long ico_me_csum; + time_t ico_me_time; + gboolean ico_informed; + + unsigned long ico_len; + unsigned long ico_csum; + time_t ico_time; + gboolean ico_need; + gboolean ico_sent; +}; + +struct name_data +{ + PurpleConnection *gc; + gchar *name; + gchar *nick; +}; + +void oscar_free_name_data(struct name_data *data); + #ifdef __cplusplus } #endif diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/oscar_data.c --- a/libpurple/protocols/oscar/oscar_data.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/oscar_data.c Fri Aug 20 08:35:27 2010 +0000 @@ -53,17 +53,13 @@ aim__registermodule(od, locate_modfirst); aim__registermodule(od, buddylist_modfirst); aim__registermodule(od, msg_modfirst); - /* aim__registermodule(od, adverts_modfirst); */ - /* aim__registermodule(od, invite_modfirst); */ aim__registermodule(od, admin_modfirst); aim__registermodule(od, popups_modfirst); aim__registermodule(od, bos_modfirst); aim__registermodule(od, search_modfirst); aim__registermodule(od, stats_modfirst); - /* aim__registermodule(od, translate_modfirst); */ aim__registermodule(od, chatnav_modfirst); aim__registermodule(od, chat_modfirst); - aim__registermodule(od, odir_modfirst); aim__registermodule(od, bart_modfirst); /* missing 0x11 - 0x12 */ aim__registermodule(od, ssi_modfirst); diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/oscarcommon.h --- a/libpurple/protocols/oscar/oscarcommon.h Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/oscarcommon.h Fri Aug 20 08:35:27 2010 +0000 @@ -77,7 +77,6 @@ void oscar_add_deny(PurpleConnection *gc, const char *who); void oscar_rem_permit(PurpleConnection *gc, const char *who); void oscar_rem_deny(PurpleConnection *gc, const char *who); -void oscar_set_permit_deny(PurpleConnection *gc); void oscar_join_chat(PurpleConnection *gc, GHashTable *data); char *oscar_get_chat_name(GHashTable *data); void oscar_chat_invite(PurpleConnection *gc, int id, const char *message, const char *name); diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/peer_proxy.c --- a/libpurple/protocols/oscar/peer_proxy.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/peer_proxy.c Fri Aug 20 08:35:27 2010 +0000 @@ -32,8 +32,8 @@ ByteStream bs; purple_debug_info("oscar", "Outgoing peer proxy frame with " - "type=0x%04hx, unknown=0x%08x, " - "flags=0x%04hx, and payload length=%hd\n", + "type=0x%04hx, unknown=0x%08x, flags=0x%04hx, and " + "payload length=%" G_GSIZE_FORMAT "\n", frame->type, frame->unknown, frame->flags, frame->payload.len); @@ -129,8 +129,8 @@ peer_proxy_recv_frame(PeerConnection *conn, ProxyFrame *frame) { purple_debug_info("oscar", "Incoming peer proxy frame with " - "type=0x%04hx, unknown=0x%08x, " - "flags=0x%04hx, and payload length=%hd\n", frame->type, + "type=0x%04hx, unknown=0x%08x, flags=0x%04hx, and " + "payload length=%" G_GSIZE_FORMAT "\n", frame->type, frame->unknown, frame->flags, frame->payload.len); if (frame->type == PEER_PROXY_TYPE_CREATED) @@ -168,7 +168,7 @@ } else if (frame->type == PEER_PROXY_TYPE_ERROR) { - if (byte_stream_empty(&frame->payload) >= 2) + if (byte_stream_bytes_left(&frame->payload) >= 2) { guint16 error; const char *msg; diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/rxhandlers.c --- a/libpurple/protocols/oscar/rxhandlers.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/rxhandlers.c Fri Aug 20 08:35:27 2010 +0000 @@ -95,194 +95,3 @@ return; } - -#if 0 -/* - * Bleck functions get called when there's no non-bleck functions - * around to cleanup the mess... - */ -static int bleck(OscarData *od, FlapFrame *frame, ...) -{ - guint16 family, subtype; - guint16 maxf, maxs; - - static const char *channels[6] = { - "Invalid (0)", - "FLAP Version", - "SNAC", - "Invalid (3)", - "Negotiation", - "FLAP NOP" - }; - static const int maxchannels = 5; - - /* XXX: this is ugly. and big just for debugging. */ - static const char *literals[14][25] = { - {"Invalid", - NULL - }, - {"General", - "Invalid", - "Error", - "Client Ready", - "Server Ready", - "Service Request", - "Redirect", - "Rate Information Request", - "Rate Information", - "Rate Information Ack", - NULL, - "Rate Information Change", - "Server Pause", - NULL, - "Server Resume", - "Request Personal User Information", - "Personal User Information", - "Evil Notification", - NULL, - "Migration notice", - "Message of the Day", - "Set Privacy Flags", - "Well Known URL", - "NOP" - }, - {"Location", - "Invalid", - "Error", - "Request Rights", - "Rights Information", - "Set user information", - "Request User Information", - "User Information", - "Watcher Sub Request", - "Watcher Notification" - }, - {"Buddy List Management", - "Invalid", - "Error", - "Request Rights", - "Rights Information", - "Add Buddy", - "Remove Buddy", - "Watcher List Query", - "Watcher List Response", - "Watcher SubRequest", - "Watcher Notification", - "Reject Notification", - "Oncoming Buddy", - "Offgoing Buddy" - }, - {"Messeging", - "Invalid", - "Error", - "Add ICBM Parameter", - "Remove ICBM Parameter", - "Request Parameter Information", - "Parameter Information", - "Outgoing Message", - "Incoming Message", - "Evil Request", - "Evil Reply", - "Missed Calls", - "Message Error", - "Host Ack" - }, - {"Advertisements", - "Invalid", - "Error", - "Request Ad", - "Ad Data (GIFs)" - }, - {"Invitation / Client-to-Client", - "Invalid", - "Error", - "Invite a Friend", - "Invitation Ack" - }, - {"Administrative", - "Invalid", - "Error", - "Information Request", - "Information Reply", - "Information Change Request", - "Information Chat Reply", - "Account Confirm Request", - "Account Confirm Reply", - "Account Delete Request", - "Account Delete Reply" - }, - {"Popups", - "Invalid", - "Error", - "Display Popup" - }, - {"BOS", - "Invalid", - "Error", - "Request Rights", - "Rights Response", - "Set group permission mask", - "Add permission list entries", - "Delete permission list entries", - "Add deny list entries", - "Delete deny list entries", - "Server Error" - }, - {"User Lookup", - "Invalid", - "Error", - "Search Request", - "Search Response" - }, - {"Stats", - "Invalid", - "Error", - "Set minimum report interval", - "Report Events" - }, - {"Translate", - "Invalid", - "Error", - "Translate Request", - "Translate Reply", - }, - {"Chat Navigation", - "Invalid", - "Error", - "Request rights", - "Request Exchange Information", - "Request Room Information", - "Request Occupant List", - "Search for Room", - "Outgoing Message", - "Incoming Message", - "Evil Request", - "Evil Reply", - "Chat Error", - } - }; - - maxf = sizeof(literals) / sizeof(literals[0]); - maxs = sizeof(literals[0]) / sizeof(literals[0][0]); - - if (frame->channel == 0x02) { - - family = byte_stream_get16(&frame->data); - subtype = byte_stream_get16(&frame->data); - - if ((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL)) - purple_debug_misc("oscar", "bleck: channel %s: null handler for %04x/%04x (%s)\n", channels[frame->channel], family, subtype, literals[family][subtype+1]); - else - purple_debug_misc("oscar", "bleck: channel %s: null handler for %04x/%04x (no literal)\n", channels[frame->channel], family, subtype); - } else { - - if (frame->channel <= maxchannels) - purple_debug_misc("oscar", "bleck: channel %s (0x%02x)\n", channels[frame->channel], frame->channel); - else - purple_debug_misc("oscar", "bleck: unknown channel 0x%02x\n", frame->channel); - - } - - return 1; -} -#endif diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/snac.c --- a/libpurple/protocols/oscar/snac.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/snac.c Fri Aug 20 08:35:27 2010 +0000 @@ -151,12 +151,12 @@ return; } -int aim_putsnac(ByteStream *bs, guint16 family, guint16 subtype, guint16 flags, aim_snacid_t snacid) +int aim_putsnac(ByteStream *bs, guint16 family, guint16 subtype, aim_snacid_t snacid) { byte_stream_put16(bs, family); byte_stream_put16(bs, subtype); - byte_stream_put16(bs, flags); + byte_stream_put16(bs, 0x0000); byte_stream_put32(bs, snacid); return 10; diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/tlv.c --- a/libpurple/protocols/oscar/tlv.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/tlv.c Fri Aug 20 08:35:27 2010 +0000 @@ -49,27 +49,7 @@ type = byte_stream_get16(bs); length = byte_stream_get16(bs); -#if 0 - /* - * This code hasn't been needed in years. It's been commented - * out since 2003, at the latest. It seems likely that it was - * just a bug in their server code that has since been fixed. - * In any case, here's the orignal comment, kept for historical - * purposes: - * - * Okay, so now AOL has decided that any TLV of - * type 0x0013 can only be two bytes, despite - * what the actual given length is. So here - * we dump any invalid TLVs of that sort. Hopefully - * there's no special cases to this special case. - * - mid (30jun2000) - */ - if ((type == 0x0013) && (length != 0x0002)) { - length = 0x0002; - return list; - } -#endif - if (length > byte_stream_empty(bs)) { + if (length > byte_stream_bytes_left(bs)) { aim_tlvlist_free(list); return NULL; } @@ -108,7 +88,7 @@ { GSList *list = NULL; - while (byte_stream_empty(bs) > 0) { + while (byte_stream_bytes_left(bs) > 0) { list = aim_tlv_read(list, bs); if (list == NULL) return NULL; @@ -142,7 +122,7 @@ { GSList *list = NULL; - while ((byte_stream_empty(bs) > 0) && (num != 0)) { + while ((byte_stream_bytes_left(bs) > 0) && (num != 0)) { list = aim_tlv_read(list, bs); if (list == NULL) return NULL; @@ -177,7 +157,7 @@ { GSList *list = NULL; - while ((byte_stream_empty(bs) > 0) && (len > 0)) { + while ((byte_stream_bytes_left(bs) > 0) && (len > 0)) { list = aim_tlv_read(list, bs); if (list == NULL) return NULL; @@ -391,6 +371,17 @@ return aim_tlvlist_add_raw(list, type, strlen(value), (guint8 *)value); } +static int +count_caps(guint64 caps) +{ + int set_bits = 0; + while (caps) { + set_bits += caps & 1; + caps >>= 1; + } + return set_bits; +} + /** * Adds a block of capability blocks to a TLV chain. The bitfield * passed in should be a bitwise %OR of any of the %AIM_CAPS constants: @@ -409,23 +400,24 @@ */ int aim_tlvlist_add_caps(GSList **list, const guint16 type, const guint64 caps, const char *mood) { - guint8 buf[256]; /* TODO: Don't use a fixed length buffer */ ByteStream bs; + guint32 bs_size; guint8 *data; if (caps == 0) return 0; /* nothing there anyway */ - byte_stream_init(&bs, buf, sizeof(buf)); + data = icq_get_custom_icon_data(mood); + bs_size = 16*(count_caps(caps) + (data != NULL ? 1 : 0)); + byte_stream_new(&bs, bs_size); byte_stream_putcaps(&bs, caps); - + /* adding of custom icon GUID */ - data = icq_get_custom_icon_data(mood); if (data != NULL) byte_stream_putraw(&bs, data, 16); - return aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), buf); + return aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), bs.data); } /** @@ -668,7 +660,7 @@ /* do an initial run to test total length */ goodbuflen = aim_tlvlist_size(*list); - if (goodbuflen > byte_stream_empty(bs)) + if (goodbuflen > byte_stream_bytes_left(bs)) return 0; /* not enough buffer */ /* do the real write-out */ diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/userinfo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/oscar/userinfo.c Fri Aug 20 08:35:27 2010 +0000 @@ -0,0 +1,553 @@ +/* + * Purple's oscar protocol plugin + * This file is the legal property of its developers. + * Please see the AUTHORS file distributed alongside this file. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA +*/ + +/* + * Displaying various information about buddies. + */ + +#include "encoding.h" +#include "oscar.h" + +static gchar * +oscar_caps_to_string(guint64 caps) +{ + GString *str; + const gchar *tmp; + guint64 bit = 1; + + str = g_string_new(""); + + if (!caps) { + return NULL; + } else while (bit <= OSCAR_CAPABILITY_LAST) { + if (bit & caps) { + switch (bit) { + case OSCAR_CAPABILITY_BUDDYICON: + tmp = _("Buddy Icon"); + break; + case OSCAR_CAPABILITY_TALK: + tmp = _("Voice"); + break; + case OSCAR_CAPABILITY_DIRECTIM: + tmp = _("AIM Direct IM"); + break; + case OSCAR_CAPABILITY_CHAT: + tmp = _("Chat"); + break; + case OSCAR_CAPABILITY_GETFILE: + tmp = _("Get File"); + break; + case OSCAR_CAPABILITY_SENDFILE: + tmp = _("Send File"); + break; + case OSCAR_CAPABILITY_GAMES: + case OSCAR_CAPABILITY_GAMES2: + tmp = _("Games"); + break; + case OSCAR_CAPABILITY_XTRAZ: + case OSCAR_CAPABILITY_NEWCAPS: + tmp = _("ICQ Xtraz"); + break; + case OSCAR_CAPABILITY_ADDINS: + tmp = _("Add-Ins"); + break; + case OSCAR_CAPABILITY_SENDBUDDYLIST: + tmp = _("Send Buddy List"); + break; + case OSCAR_CAPABILITY_ICQ_DIRECT: + tmp = _("ICQ Direct Connect"); + break; + case OSCAR_CAPABILITY_APINFO: + tmp = _("AP User"); + break; + case OSCAR_CAPABILITY_ICQRTF: + tmp = _("ICQ RTF"); + break; + case OSCAR_CAPABILITY_EMPTY: + tmp = _("Nihilist"); + break; + case OSCAR_CAPABILITY_ICQSERVERRELAY: + tmp = _("ICQ Server Relay"); + break; + case OSCAR_CAPABILITY_UNICODEOLD: + tmp = _("Old ICQ UTF8"); + break; + case OSCAR_CAPABILITY_TRILLIANCRYPT: + tmp = _("Trillian Encryption"); + break; + case OSCAR_CAPABILITY_UNICODE: + tmp = _("ICQ UTF8"); + break; + case OSCAR_CAPABILITY_HIPTOP: + tmp = _("Hiptop"); + break; + case OSCAR_CAPABILITY_SECUREIM: + tmp = _("Security Enabled"); + break; + case OSCAR_CAPABILITY_VIDEO: + tmp = _("Video Chat"); + break; + /* Not actually sure about this one... WinAIM doesn't show anything */ + case OSCAR_CAPABILITY_ICHATAV: + tmp = _("iChat AV"); + break; + case OSCAR_CAPABILITY_LIVEVIDEO: + tmp = _("Live Video"); + break; + case OSCAR_CAPABILITY_CAMERA: + tmp = _("Camera"); + break; + case OSCAR_CAPABILITY_ICHAT_SCREENSHARE: + tmp = _("Screen Sharing"); + break; + default: + tmp = NULL; + break; + } + if (tmp) + g_string_append_printf(str, "%s%s", (*(str->str) == '\0' ? "" : ", "), tmp); + } + bit <<= 1; + } + + return g_string_free(str, FALSE); +} + +static void +oscar_user_info_add_pair(PurpleNotifyUserInfo *user_info, const char *name, const char *value) +{ + if (value && value[0]) { + purple_notify_user_info_add_pair(user_info, name, value); + } +} + +static void +oscar_user_info_convert_and_add(PurpleAccount *account, OscarData *od, PurpleNotifyUserInfo *user_info, + const char *name, const char *value) +{ + gchar *utf8; + + if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, od, value))) { + purple_notify_user_info_add_pair(user_info, name, utf8); + g_free(utf8); + } +} + +static void +oscar_user_info_convert_and_add_hyperlink(PurpleAccount *account, OscarData *od, PurpleNotifyUserInfo *user_info, + const char *name, const char *value, const char *url_prefix) +{ + gchar *utf8; + + if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, od, value))) { + gchar *tmp = g_strdup_printf("%s", url_prefix, utf8, utf8); + purple_notify_user_info_add_pair(user_info, name, tmp); + g_free(utf8); + g_free(tmp); + } +} + +/** + * @brief Append the status information to a user_info struct + * + * The returned information is HTML-ready, appropriately escaped, as all information in a user_info struct should be HTML. + * + * @param gc The PurpleConnection + * @param user_info A PurpleNotifyUserInfo object to which status information will be added + * @param b The PurpleBuddy whose status is desired. This or the aim_userinfo_t (or both) must be passed to oscar_user_info_append_status(). + * @param userinfo The aim_userinfo_t of the buddy whose status is desired. This or the PurpleBuddy (or both) must be passed to oscar_user_info_append_status(). + * @param strip_html_tags If strip_html_tags is TRUE, tags embedded in the status message will be stripped, returning a non-formatted string. The string will still be HTML escaped. + */ +void +oscar_user_info_append_status(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo, gboolean strip_html_tags) +{ + PurpleAccount *account = purple_connection_get_account(gc); + OscarData *od; + PurplePresence *presence = NULL; + PurpleStatus *status = NULL; + gchar *message = NULL, *itmsurl = NULL, *tmp; + gboolean is_away; + + od = purple_connection_get_protocol_data(gc); + + if (b == NULL && userinfo == NULL) + return; + + if (b == NULL) + b = purple_find_buddy(purple_connection_get_account(gc), userinfo->bn); + else + userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b)); + + if (b) { + presence = purple_buddy_get_presence(b); + status = purple_presence_get_active_status(presence); + } + + /* If we have both b and userinfo we favor userinfo, because if we're + viewing someone's profile then we want the HTML away message, and + the "message" attribute of the status contains only the plaintext + message. */ + if (userinfo) { + if ((userinfo->flags & AIM_FLAG_AWAY) && userinfo->away_len > 0 && userinfo->away != NULL && userinfo->away_encoding != NULL) { + /* Away message */ + message = oscar_encoding_to_utf8(userinfo->away_encoding, userinfo->away, userinfo->away_len); + } else { + /* + * Available message or non-HTML away message (because that's + * all we have right now. + */ + if ((userinfo->status != NULL) && userinfo->status[0] != '\0') { + message = oscar_encoding_to_utf8(userinfo->status_encoding, userinfo->status, userinfo->status_len); + } +#if defined (_WIN32) || defined (__APPLE__) + if (userinfo->itmsurl && (userinfo->itmsurl[0] != '\0')) { + itmsurl = oscar_encoding_to_utf8(userinfo->itmsurl_encoding, userinfo->itmsurl, userinfo->itmsurl_len); + } +#endif + } + } else { + message = g_strdup(purple_status_get_attr_string(status, "message")); + itmsurl = g_strdup(purple_status_get_attr_string(status, "itmsurl")); + } + + is_away = ((status && !purple_status_is_available(status)) || + (userinfo && (userinfo->flags & AIM_FLAG_AWAY))); + + if (strip_html_tags) { + /* Away messages are HTML, but available messages were originally plain text. + * We therefore need to strip away messages but not available messages if we're asked to remove HTML tags. + */ + /* + * It seems like the above comment no longer applies. All messages need + * to be escaped. + */ + if (message) { + gchar *tmp2; + tmp = purple_markup_strip_html(message); + g_free(message); + tmp2 = g_markup_escape_text(tmp, -1); + g_free(tmp); + message = tmp2; + } + + } else { + if (itmsurl) { + tmp = g_strdup_printf("%s", + itmsurl, message); + g_free(message); + message = tmp; + } + } + g_free(itmsurl); + + if (message) { + tmp = oscar_util_format_string(message, purple_account_get_username(account)); + g_free(message); + message = tmp; + } + + if (b) { + if (purple_presence_is_online(presence)) { + if (oscar_util_valid_name_icq(purple_buddy_get_name(b)) || is_away || !message || !(*message)) { + /* Append the status name for online ICQ statuses, away AIM statuses, and for all buddies with no message. + * If the status name and the message are the same, only show one. */ + const char *status_name = purple_status_get_name(status); + if (status_name && message && !strcmp(status_name, message)) + status_name = NULL; + + tmp = g_strdup_printf("%s%s%s", + status_name ? status_name : "", + ((status_name && message) && *message) ? ": " : "", + (message && *message) ? message : ""); + g_free(message); + message = tmp; + } + + } else if (aim_ssi_waitingforauth(od->ssi.local, + aim_ssi_itemlist_findparentname(od->ssi.local, purple_buddy_get_name(b)), + purple_buddy_get_name(b))) + { + /* Note if an offline buddy is not authorized */ + tmp = g_strdup_printf("%s%s%s", + _("Not Authorized"), + (message && *message) ? ": " : "", + (message && *message) ? message : ""); + g_free(message); + message = tmp; + } else { + g_free(message); + message = g_strdup(_("Offline")); + } + } + + if (presence) { + const char *mood; + const char *description; + status = purple_presence_get_status(presence, "mood"); + mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME); + description = icq_get_custom_icon_description(mood); + if (description && *description) + purple_notify_user_info_add_pair(user_info, _("Mood"), _(description)); + } + + purple_notify_user_info_add_pair(user_info, _("Status"), message); + g_free(message); +} + +void +oscar_user_info_append_extra_info(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo) +{ + OscarData *od; + PurpleAccount *account; + PurplePresence *presence = NULL; + PurpleStatus *status = NULL; + PurpleGroup *g = NULL; + struct buddyinfo *bi = NULL; + char *tmp; + const char *bname = NULL, *gname = NULL; + + od = purple_connection_get_protocol_data(gc); + account = purple_connection_get_account(gc); + + if ((user_info == NULL) || ((b == NULL) && (userinfo == NULL))) + return; + + if (userinfo == NULL) + userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b)); + + if (b == NULL) + b = purple_find_buddy(account, userinfo->bn); + + if (b != NULL) { + bname = purple_buddy_get_name(b); + g = purple_buddy_get_group(b); + gname = purple_group_get_name(g); + presence = purple_buddy_get_presence(b); + status = purple_presence_get_active_status(presence); + } + + if (userinfo != NULL) + bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, userinfo->bn)); + + if ((bi != NULL) && (bi->ipaddr != 0)) { + tmp = g_strdup_printf("%hhu.%hhu.%hhu.%hhu", + (bi->ipaddr & 0xff000000) >> 24, + (bi->ipaddr & 0x00ff0000) >> 16, + (bi->ipaddr & 0x0000ff00) >> 8, + (bi->ipaddr & 0x000000ff)); + oscar_user_info_add_pair(user_info, _("IP Address"), tmp); + g_free(tmp); + } + + if ((userinfo != NULL) && (userinfo->warnlevel != 0)) { + tmp = g_strdup_printf("%d", (int)(userinfo->warnlevel/10.0 + .5)); + oscar_user_info_add_pair(user_info, _("Warning Level"), tmp); + g_free(tmp); + } + + if ((b != NULL) && (bname != NULL) && (g != NULL) && (gname != NULL)) { + tmp = aim_ssi_getcomment(od->ssi.local, gname, bname); + if (tmp != NULL) { + char *tmp2 = g_markup_escape_text(tmp, strlen(tmp)); + g_free(tmp); + + oscar_user_info_convert_and_add(account, od, user_info, _("Buddy Comment"), tmp2); + g_free(tmp2); + } + } +} + +void +oscar_user_info_display_error(OscarData *od, guint16 error_reason, gchar *buddy) +{ + PurpleNotifyUserInfo *user_info = purple_notify_user_info_new(); + gchar *buf = g_strdup_printf(_("User information not available: %s"), oscar_get_msgerr_reason(error_reason)); + purple_notify_user_info_add_pair(user_info, NULL, buf); + purple_notify_userinfo(od->gc, buddy, user_info, NULL, NULL); + purple_notify_user_info_destroy(user_info); + purple_conv_present_error(buddy, purple_connection_get_account(od->gc), buf); + g_free(buf); +} + +void +oscar_user_info_display_icq(OscarData *od, struct aim_icq_info *info) +{ + PurpleConnection *gc = od->gc; + PurpleAccount *account = purple_connection_get_account(gc); + PurpleBuddy *buddy; + struct buddyinfo *bi; + gchar who[16]; + PurpleNotifyUserInfo *user_info; + const gchar *alias; + + if (!info->uin) + return; + + user_info = purple_notify_user_info_new(); + + g_snprintf(who, sizeof(who), "%u", info->uin); + buddy = purple_find_buddy(account, who); + if (buddy != NULL) + bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, purple_buddy_get_name(buddy))); + else + bi = NULL; + + purple_notify_user_info_add_pair(user_info, _("UIN"), who); + oscar_user_info_convert_and_add(account, od, user_info, _("Nick"), info->nick); + if ((bi != NULL) && (bi->ipaddr != 0)) { + char *tstr = g_strdup_printf("%hhu.%hhu.%hhu.%hhu", + (bi->ipaddr & 0xff000000) >> 24, + (bi->ipaddr & 0x00ff0000) >> 16, + (bi->ipaddr & 0x0000ff00) >> 8, + (bi->ipaddr & 0x000000ff)); + purple_notify_user_info_add_pair(user_info, _("IP Address"), tstr); + g_free(tstr); + } + oscar_user_info_convert_and_add(account, od, user_info, _("First Name"), info->first); + oscar_user_info_convert_and_add(account, od, user_info, _("Last Name"), info->last); + oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Email Address"), info->email, "mailto:"); + if (info->numaddresses && info->email2) { + int i; + for (i = 0; i < info->numaddresses; i++) { + oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Email Address"), info->email2[i], "mailto:"); + } + } + oscar_user_info_convert_and_add(account, od, user_info, _("Mobile Phone"), info->mobile); + + if (info->gender != 0) + purple_notify_user_info_add_pair(user_info, _("Gender"), (info->gender == 1 ? _("Female") : _("Male"))); + + if ((info->birthyear > 1900) && (info->birthmonth > 0) && (info->birthday > 0)) { + /* Initialize the struct properly or strftime() will crash + * under some conditions (e.g. Debian sarge w/ LANG=en_HK). */ + time_t t = time(NULL); + struct tm *tm = localtime(&t); + + tm->tm_mday = (int)info->birthday; + tm->tm_mon = (int)info->birthmonth - 1; + tm->tm_year = (int)info->birthyear - 1900; + + /* To be 100% sure that the fields are re-normalized. + * If you're sure strftime() ALWAYS does this EVERYWHERE, + * feel free to remove it. --rlaager */ + mktime(tm); + + oscar_user_info_convert_and_add(account, od, user_info, _("Birthday"), purple_date_format_short(tm)); + } + if ((info->age > 0) && (info->age < 255)) { + char age[5]; + snprintf(age, sizeof(age), "%hhd", info->age); + purple_notify_user_info_add_pair(user_info, _("Age"), age); + } + oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Personal Web Page"), info->email, ""); + if (buddy != NULL) + oscar_user_info_append_status(gc, user_info, buddy, /* aim_userinfo_t */ NULL, /* strip_html_tags */ FALSE); + + oscar_user_info_convert_and_add(account, od, user_info, _("Additional Information"), info->info); + purple_notify_user_info_add_section_break(user_info); + + if ((info->homeaddr && (info->homeaddr[0])) || (info->homecity && info->homecity[0]) || (info->homestate && info->homestate[0]) || (info->homezip && info->homezip[0])) { + purple_notify_user_info_add_section_header(user_info, _("Home Address")); + + oscar_user_info_convert_and_add(account, od, user_info, _("Address"), info->homeaddr); + oscar_user_info_convert_and_add(account, od, user_info, _("City"), info->homecity); + oscar_user_info_convert_and_add(account, od, user_info, _("State"), info->homestate); + oscar_user_info_convert_and_add(account, od, user_info, _("Zip Code"), info->homezip); + } + if ((info->workaddr && info->workaddr[0]) || (info->workcity && info->workcity[0]) || (info->workstate && info->workstate[0]) || (info->workzip && info->workzip[0])) { + purple_notify_user_info_add_section_header(user_info, _("Work Address")); + + oscar_user_info_convert_and_add(account, od, user_info, _("Address"), info->workaddr); + oscar_user_info_convert_and_add(account, od, user_info, _("City"), info->workcity); + oscar_user_info_convert_and_add(account, od, user_info, _("State"), info->workstate); + oscar_user_info_convert_and_add(account, od, user_info, _("Zip Code"), info->workzip); + } + if ((info->workcompany && info->workcompany[0]) || (info->workdivision && info->workdivision[0]) || (info->workposition && info->workposition[0]) || (info->workwebpage && info->workwebpage[0])) { + purple_notify_user_info_add_section_header(user_info, _("Work Information")); + + oscar_user_info_convert_and_add(account, od, user_info, _("Company"), info->workcompany); + oscar_user_info_convert_and_add(account, od, user_info, _("Division"), info->workdivision); + oscar_user_info_convert_and_add(account, od, user_info, _("Position"), info->workposition); + oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Web Page"), info->email, ""); + } + + if (buddy != NULL) + alias = purple_buddy_get_alias(buddy); + else + alias = who; + purple_notify_userinfo(gc, who, user_info, NULL, NULL); + purple_notify_user_info_destroy(user_info); +} + +void +oscar_user_info_display_aim(OscarData *od, aim_userinfo_t *userinfo) +{ + PurpleConnection *gc = od->gc; + PurpleAccount *account = purple_connection_get_account(gc); + PurpleNotifyUserInfo *user_info = purple_notify_user_info_new(); + gchar *tmp = NULL, *info_utf8 = NULL, *base_profile_url = NULL; + + oscar_user_info_append_status(gc, user_info, /* PurpleBuddy */ NULL, userinfo, /* strip_html_tags */ FALSE); + + if ((userinfo->present & AIM_USERINFO_PRESENT_IDLE) && userinfo->idletime != 0) { + tmp = purple_str_seconds_to_string(userinfo->idletime*60); + oscar_user_info_add_pair(user_info, _("Idle"), tmp); + g_free(tmp); + } + + oscar_user_info_append_extra_info(gc, user_info, NULL, userinfo); + + if ((userinfo->present & AIM_USERINFO_PRESENT_ONLINESINCE) && !oscar_util_valid_name_sms(userinfo->bn)) { + /* An SMS contact is always online; its Online Since value is not useful */ + time_t t = userinfo->onlinesince; + oscar_user_info_add_pair(user_info, _("Online Since"), purple_date_format_full(localtime(&t))); + } + + if (userinfo->present & AIM_USERINFO_PRESENT_MEMBERSINCE) { + time_t t = userinfo->membersince; + oscar_user_info_add_pair(user_info, _("Member Since"), purple_date_format_full(localtime(&t))); + } + + if (userinfo->capabilities != 0) { + tmp = oscar_caps_to_string(userinfo->capabilities); + oscar_user_info_add_pair(user_info, _("Capabilities"), tmp); + g_free(tmp); + } + + /* Info */ + if ((userinfo->info_len > 0) && (userinfo->info != NULL) && (userinfo->info_encoding != NULL)) { + info_utf8 = oscar_encoding_to_utf8(userinfo->info_encoding, userinfo->info, userinfo->info_len); + tmp = oscar_util_format_string(info_utf8, purple_account_get_username(account)); + purple_notify_user_info_add_section_break(user_info); + oscar_user_info_add_pair(user_info, _("Profile"), tmp); + g_free(tmp); + g_free(info_utf8); + } + + purple_notify_user_info_add_section_break(user_info); + base_profile_url = oscar_util_valid_name_icq(userinfo->bn) ? "http://www.icq.com/people" : "http://profiles.aim.com"; + tmp = g_strdup_printf("%s", + base_profile_url, purple_normalize(account, userinfo->bn), _("View web profile")); + purple_notify_user_info_add_pair(user_info, NULL, tmp); + g_free(tmp); + + purple_notify_userinfo(gc, userinfo->bn, user_info, NULL, NULL); + purple_notify_user_info_destroy(user_info); +} \ No newline at end of file diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/util.c --- a/libpurple/protocols/oscar/util.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/oscar/util.c Fri Aug 20 08:35:27 2010 +0000 @@ -107,91 +107,6 @@ return g_strdup_printf("%s/%s", name, version);; } -/* - * Tokenizing functions. Used to portably replace strtok/sep. - * -- DMP. - * - */ -/* TODO: Get rid of this and use glib functions */ -int -aimutil_tokslen(char *toSearch, int theindex, char dl) -{ - int curCount = 1; - char *next; - char *last; - int toReturn; - - last = toSearch; - next = strchr(toSearch, dl); - - while(curCount < theindex && next != NULL) { - curCount++; - last = next + 1; - next = strchr(last, dl); - } - - if ((curCount < theindex) || (next == NULL)) - toReturn = strlen(toSearch) - (curCount - 1); - else - toReturn = next - toSearch - (curCount - 1); - - return toReturn; -} - -int -aimutil_itemcnt(char *toSearch, char dl) -{ - int curCount; - char *next; - - curCount = 1; - - next = strchr(toSearch, dl); - - while(next != NULL) { - curCount++; - next = strchr(next + 1, dl); - } - - return curCount; -} - -char * -aimutil_itemindex(char *toSearch, int theindex, char dl) -{ - int curCount; - char *next; - char *last; - char *toReturn; - - curCount = 0; - - last = toSearch; - next = strchr(toSearch, dl); - - while (curCount < theindex && next != NULL) { - curCount++; - last = next + 1; - next = strchr(last, dl); - } - next = strchr(last, dl); - - if (curCount < theindex) { - toReturn = g_malloc(sizeof(char)); - *toReturn = '\0'; - } else { - if (next == NULL) { - toReturn = g_malloc((strlen(last) + 1) * sizeof(char)); - strcpy(toReturn, last); - } else { - toReturn = g_malloc((next - last + 1) * sizeof(char)); - memcpy(toReturn, last, (next - last)); - toReturn[next - last] = '\0'; - } - } - return toReturn; -} - /** * Calculate the checksum of a given icon. */ @@ -323,3 +238,89 @@ return 0; } + +/** + * Looks for %n, %d, or %t in a string, and replaces them with the + * specified name, date, and time, respectively. + * + * @param str The string that may contain the special variables. + * @param name The sender name. + * + * @return A newly allocated string where the special variables are + * expanded. This should be g_free'd by the caller. + */ +gchar * +oscar_util_format_string(const char *str, const char *name) +{ + char *c; + GString *cpy; + time_t t; + struct tm *tme; + + g_return_val_if_fail(str != NULL, NULL); + g_return_val_if_fail(name != NULL, NULL); + + /* Create an empty GString that is hopefully big enough for most messages */ + cpy = g_string_sized_new(1024); + + t = time(NULL); + tme = localtime(&t); + + c = (char *)str; + while (*c) { + switch (*c) { + case '%': + if (*(c + 1)) { + switch (*(c + 1)) { + case 'n': + /* append name */ + g_string_append(cpy, name); + c++; + break; + case 'd': + /* append date */ + g_string_append(cpy, purple_date_format_short(tme)); + c++; + break; + case 't': + /* append time */ + g_string_append(cpy, purple_time_format(tme)); + c++; + break; + default: + g_string_append_c(cpy, *c); + } + } else { + g_string_append_c(cpy, *c); + } + break; + default: + g_string_append_c(cpy, *c); + } + c++; + } + + return g_string_free(cpy, FALSE); +} + +gchar * +oscar_format_buddies(GSList *buddies, const gchar *no_buddies_message) +{ + GSList *cur; + GString *result; + if (!buddies) { + return g_strdup_printf("%s", no_buddies_message); + } + result = g_string_new(""); + for (cur = buddies; cur != NULL; cur = cur->next) { + PurpleBuddy *buddy = cur->data; + const gchar *bname = purple_buddy_get_name(buddy); + const gchar *alias = purple_buddy_get_alias_only(buddy); + g_string_append(result, bname); + if (alias) { + g_string_append_printf(result, " (%s)", alias); + } + g_string_append(result, "
"); + } + return g_string_free(result, FALSE); +} diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/visibility.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/oscar/visibility.c Fri Aug 20 08:35:27 2010 +0000 @@ -0,0 +1,199 @@ +/* + * Purple's oscar protocol plugin + * This file is the legal property of its developers. + * Please see the AUTHORS file distributed alongside this file. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "visibility.h" +#include "request.h" + +/* 4 separate strings are needed in order to ease translators' job */ +#define APPEAR_ONLINE N_("Appear Online") +#define DONT_APPEAR_ONLINE N_("Don't Appear Online") +#define APPEAR_OFFLINE N_("Appear Offline") +#define DONT_APPEAR_OFFLINE N_("Don't Appear Offline") + +static guint16 +get_buddy_list_type(OscarData *od) +{ + PurpleAccount *account = purple_connection_get_account(od->gc); + return purple_account_is_status_active(account, OSCAR_STATUS_ID_INVISIBLE) ? AIM_SSI_TYPE_PERMIT : AIM_SSI_TYPE_DENY; +} + +static gboolean +is_buddy_on_list(OscarData *od, const char *bname) +{ + return aim_ssi_itemlist_finditem(od->ssi.local, NULL, bname, get_buddy_list_type(od)) != NULL; +} + +static void +visibility_cb(PurpleBlistNode *node, gpointer whatever) +{ + PurpleBuddy *buddy = PURPLE_BUDDY(node); + const char* bname = purple_buddy_get_name(buddy); + OscarData *od = purple_connection_get_protocol_data(purple_account_get_connection(purple_buddy_get_account(buddy))); + guint16 list_type = get_buddy_list_type(od); + + if (!is_buddy_on_list(od, bname)) { + aim_ssi_add_to_private_list(od, bname, list_type); + } else { + aim_ssi_del_from_private_list(od, bname, list_type); + } +} + +PurpleMenuAction * +create_visibility_menu_item(OscarData *od, const char *bname) +{ + PurpleAccount *account = purple_connection_get_account(od->gc); + gboolean invisible = purple_account_is_status_active(account, OSCAR_STATUS_ID_INVISIBLE); + gboolean on_list = is_buddy_on_list(od, bname); + const gchar *label; + + if (invisible) { + label = on_list ? _(DONT_APPEAR_ONLINE) : _(APPEAR_ONLINE); + } else { + label = on_list ? _(DONT_APPEAR_OFFLINE) : _(APPEAR_OFFLINE); + } + return purple_menu_action_new(label, PURPLE_CALLBACK(visibility_cb), NULL, NULL); +} + +typedef void (*ShowDialog)(PurplePluginAction *); + +struct list_remove_data +{ + PurplePluginAction *action; + ShowDialog show_dialog_again; + OscarData *od; + guint16 list_type; + const gchar *list_name; +}; + +static void +list_remove_cb(struct list_remove_data *data, PurpleRequestFields *fields) +{ + ShowDialog show_dialog_again = data->show_dialog_again; + PurplePluginAction *action = data->action; + PurpleRequestField *field = purple_request_fields_get_field(fields, "list-items"); + GList *sels = purple_request_field_list_get_selected(field); + for (; sels; sels = sels->next) { + const gchar *name = sels->data; + const gchar *bname = purple_request_field_list_get_data(field, name); + + purple_debug_info("oscar", "Removing %s from %s\n", bname, data->list_name); + + aim_ssi_del_from_private_list(data->od, bname, data->list_type); + } + + g_free(data); + show_dialog_again(action); +} + +static void +list_close_cb(struct list_remove_data *data, gpointer ignored) +{ + g_free(data); +} + +static void +show_private_list(PurplePluginAction *action, + guint16 list_type, + const gchar *list_name, + const gchar *list_description, + const gchar *menu_action_name, + ShowDialog caller) +{ + PurpleConnection *gc = (PurpleConnection *) action->context; + OscarData *od = purple_connection_get_protocol_data(gc); + PurpleAccount *account = purple_connection_get_account(gc); + GSList *buddies, *cur; + gchar *desc; + struct list_remove_data *data; + + PurpleRequestField *field; + PurpleRequestFields *fields = purple_request_fields_new(); + PurpleRequestFieldGroup *group = purple_request_field_group_new(NULL); + + purple_request_fields_add_group(fields, group); + + desc = g_strdup_printf(_("You can add a buddy to this list " + "by right-clicking on them and " + "selecting \"%s\""), menu_action_name); + + field = purple_request_field_list_new("list-items", desc); + g_free(desc); + + purple_request_field_group_add_field(group, field); + + purple_request_field_list_set_multi_select(field, TRUE); + purple_request_field_set_required(field, TRUE); + + buddies = purple_find_buddies(account, NULL); + for (cur = buddies; cur != NULL; cur = cur->next) { + PurpleBuddy *buddy; + const gchar *bname; + + buddy = cur->data; + bname = purple_buddy_get_name(buddy); + if (aim_ssi_itemlist_finditem(od->ssi.local, NULL, bname, list_type)) { + const gchar *alias = purple_buddy_get_alias_only(buddy); + char *dname = alias ? g_strdup_printf("%s (%s)", bname, alias) : NULL; + purple_request_field_list_add(field, dname ? dname : bname, (void *)bname); + g_free(dname); + } + } + + g_slist_free(buddies); + + data = g_new0(struct list_remove_data, 1); + data->action = action; + data->show_dialog_again = caller; + data->od = od; + data->list_type = list_type; + data->list_name = list_name; + + purple_request_fields(gc, list_name, list_description, NULL, + fields, + _("Close"), G_CALLBACK(list_close_cb), + _("Remove"), G_CALLBACK(list_remove_cb), + account, NULL, NULL, + data); +} + +void +oscar_show_visible_list(PurplePluginAction *action) +{ + show_private_list(action, + AIM_SSI_TYPE_PERMIT, + _("Visible List"), + _("These buddies will see " + "your status when you switch " + "to \"Invisible\""), + _(APPEAR_ONLINE), + oscar_show_visible_list); +} + +void +oscar_show_invisible_list(PurplePluginAction *action) +{ + show_private_list(action, + AIM_SSI_TYPE_DENY, + _("Invisible List"), + _("These buddies will always see you as offline"), + _(APPEAR_OFFLINE), + oscar_show_invisible_list); +} + diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/oscar/visibility.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/oscar/visibility.h Fri Aug 20 08:35:27 2010 +0000 @@ -0,0 +1,32 @@ +/* + * Purple's oscar protocol plugin + * This file is the legal property of its developers. + * Please see the AUTHORS file distributed alongside this file. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA +*/ + +#ifndef _VISIBILITY_H_ +#define _VISIBILITY_H_ + +#include "oscar.h" +#include "plugin.h" +#include "util.h" + +PurpleMenuAction * create_visibility_menu_item(OscarData *od, const char *bname); +void oscar_show_visible_list(PurplePluginAction *action); +void oscar_show_invisible_list(PurplePluginAction *action); + +#endif \ No newline at end of file diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/qq/char_conv.c --- a/libpurple/protocols/qq/char_conv.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/qq/char_conv.c Fri Aug 20 08:35:27 2010 +0000 @@ -37,7 +37,7 @@ /* convert a string from from_charset to to_charset, using g_convert */ /* Warning: do not return NULL */ -static gchar *do_convert(const gchar *str, gssize len, const gchar *to_charset, const gchar *from_charset) +static gchar *do_convert(const gchar *str, gssize len, guint8 *out_len, const gchar *to_charset, const gchar *from_charset) { GError *error = NULL; gchar *ret; @@ -48,6 +48,8 @@ ret = g_convert(str, len, to_charset, from_charset, &byte_read, &byte_write, &error); if (error == NULL) { + if (out_len) + *out_len = byte_write; return ret; /* convert is OK */ } @@ -67,7 +69,8 @@ */ gint qq_get_vstr(gchar **ret, const gchar *from_charset, guint8 *data) { - guint8 len; + gssize len; + guint8 out_len; g_return_val_if_fail(data != NULL && from_charset != NULL, -1); @@ -76,9 +79,9 @@ *ret = g_strdup(""); return 1; } - *ret = do_convert((gchar *) (data + 1), (gssize) len, UTF8, from_charset); + *ret = do_convert((gchar *) (data + 1), len, &out_len, UTF8, from_charset); - return len + 1; + return out_len + 1; } gint qq_put_vstr(guint8 *buf, const gchar *str_utf8, const gchar *to_charset) @@ -86,12 +89,11 @@ gchar *str; guint8 len; - if (str_utf8 == NULL || (len = strlen(str_utf8)) == 0) { + if (str_utf8 == NULL || str_utf8[0] == '\0') { buf[0] = 0; return 1; } - str = do_convert(str_utf8, -1, to_charset, UTF8); - len = strlen(str_utf8); + str = do_convert(str_utf8, -1, &len, to_charset, UTF8); buf[0] = len; if (len > 0) { memcpy(buf + 1, str, len); @@ -102,12 +104,12 @@ /* Warning: do not return NULL */ gchar *utf8_to_qq(const gchar *str, const gchar *to_charset) { - return do_convert(str, -1, to_charset, UTF8); + return do_convert(str, -1, NULL, to_charset, UTF8); } /* Warning: do not return NULL */ gchar *qq_to_utf8(const gchar *str, const gchar *from_charset) { - return do_convert(str, -1, UTF8, from_charset); + return do_convert(str, -1, NULL, UTF8, from_charset); } diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/qq/qq.c --- a/libpurple/protocols/qq/qq.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/qq/qq.c Fri Aug 20 08:35:27 2010 +0000 @@ -382,12 +382,10 @@ { PurpleAccount *account; PurpleConnection *gc; - qq_data *qd; qq_buddy_data *buddy; if (!b || !(account = purple_buddy_get_account(b)) || - !(gc = purple_account_get_connection(account)) || - !(qd = purple_connection_get_protocol_data(gc))) + !(gc = purple_account_get_connection(account))) return NULL; buddy = purple_buddy_get_protocol_data(b); diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/qq/qq_trans.c --- a/libpurple/protocols/qq/qq_trans.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/qq/qq_trans.c Fri Aug 20 08:35:27 2010 +0000 @@ -138,10 +138,11 @@ /* Remove a packet with seq from send trans */ static void trans_remove(PurpleConnection *gc, qq_transaction *trans) { - qq_data *qd = (qq_data *)gc->proto_data; + qq_data *qd; - g_return_if_fail(gc != NULL && gc->proto_data != NULL); + g_return_if_fail(gc != NULL); qd = (qq_data *) gc->proto_data; + g_return_if_fail(qd != NULL); g_return_if_fail(trans != NULL); #if 0 diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/yahoo/libymsg.c --- a/libpurple/protocols/yahoo/libymsg.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/yahoo/libymsg.c Fri Aug 20 08:35:27 2010 +0000 @@ -502,8 +502,6 @@ char *temp = NULL; YahooFriend *f = NULL; /* It's your friends. They're going to want you to share your StarBursts. */ /* But what if you had no friends? */ - PurpleBuddy *b; - PurpleGroup *g; YahooFederation fed = YAHOO_FEDERATION_NONE; int stealth = 0; @@ -549,7 +547,9 @@ if (yd->current_list15_grp) { /* This buddy is in a group */ f = yahoo_friend_find_or_new(gc, norm_bud); - if (!(b = purple_find_buddy(account, norm_bud))) { + if (!purple_find_buddy(account, norm_bud)) { + PurpleBuddy *b; + PurpleGroup *g; if (!(g = purple_find_group(yd->current_list15_grp))) { g = purple_group_new(yd->current_list15_grp); purple_blist_add_group(g, NULL); @@ -636,8 +636,6 @@ GSList *l = pkt->hash; gboolean export = FALSE; gboolean got_serv_list = FALSE; - PurpleBuddy *b; - PurpleGroup *g; YahooFriend *f = NULL; PurpleAccount *account = purple_connection_get_account(gc); YahooData *yd = gc->proto_data; @@ -705,7 +703,9 @@ norm_bud = g_strdup(purple_normalize(account, *bud)); f = yahoo_friend_find_or_new(gc, norm_bud); - if (!(b = purple_find_buddy(account, norm_bud))) { + if (!purple_find_buddy(account, norm_bud)) { + PurpleBuddy *b; + PurpleGroup *g; if (!(g = purple_find_group(grp))) { g = purple_group_new(grp); purple_blist_add_group(g, NULL); @@ -3806,13 +3806,12 @@ { PurpleAccount *account; PurpleConnection *gc; - YahooData *yd; YahooFriend *f; PurplePresence *presence; if (!b || !(account = purple_buddy_get_account(b)) || !(gc = purple_account_get_connection(account)) || - !(yd = gc->proto_data)) + !gc->proto_data) return NULL; f = yahoo_friend_find(gc, purple_buddy_get_name(b)); diff -r 69760676c50c -r 581a070c3737 libpurple/protocols/yahoo/yahoochat.c --- a/libpurple/protocols/yahoo/yahoochat.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/protocols/yahoo/yahoochat.c Fri Aug 20 08:35:27 2010 +0000 @@ -121,7 +121,6 @@ char *msg = NULL; GString *members = NULL; GHashTable *components; - PurpleConversation *c = NULL; if ( (pkt->status == 2) || (pkt->status == 11) ) return; /* Status is 11 when we are being notified about invitation being sent to someone else */ @@ -133,7 +132,7 @@ if (pair->key == 57) { room = yahoo_string_decode(gc, pair->value, FALSE); - if((c = yahoo_find_conference(gc, room))) + if (yahoo_find_conference(gc, room) != NULL) { /* Looks like we got invited to an already open conference. */ /* Laters: Should we accept this conference rather than ignoring the invitation ? */ @@ -880,7 +879,6 @@ { YahooData *yd = gc->proto_data; struct yahoo_packet *pkt; - PurpleConversation *c; char *eroom; gboolean utf8 = 1; @@ -905,7 +903,7 @@ yd->chat_name = NULL; } - if ((c = purple_find_chat(gc, YAHOO_CHAT_ID))) + if (purple_find_chat(gc, YAHOO_CHAT_ID) != NULL) serv_got_chat_left(gc, YAHOO_CHAT_ID); if (!logout) diff -r 69760676c50c -r 581a070c3737 libpurple/proxy.c --- a/libpurple/proxy.c Fri Aug 20 08:34:12 2010 +0000 +++ b/libpurple/proxy.c Fri Aug 20 08:35:27 2010 +0000 @@ -1023,7 +1023,7 @@ g_free(response); - } else if((header = g_strrstr((const char *)connect_data->read_buffer, "Proxy-Authenticate: Basic"))) { + } else if (g_strrstr((const char *)connect_data->read_buffer, "Proxy-Authenticate: Basic") != NULL) { gchar *t1, *t2; const char *username, *password; diff -r 69760676c50c -r 581a070c3737 pidgin/gtkaccount.c --- a/pidgin/gtkaccount.c Fri Aug 20 08:34:12 2010 +0000 +++ b/pidgin/gtkaccount.c Fri Aug 20 08:35:27 2010 +0000 @@ -2418,35 +2418,38 @@ g_free(buffer); } -struct auth_and_add { +struct auth_request +{ PurpleAccountRequestAuthorizationCb auth_cb; PurpleAccountRequestAuthorizationCb deny_cb; void *data; char *username; char *alias; PurpleAccount *account; + gboolean add_buddy_after_auth; }; static void -free_auth_and_add(struct auth_and_add *aa) +free_auth_request(struct auth_request *ar) { - g_free(aa->username); - g_free(aa->alias); - g_free(aa); + g_free(ar->username); + g_free(ar->alias); + g_free(ar); } static void -authorize_and_add_cb(struct auth_and_add *aa) +authorize_and_add_cb(struct auth_request *ar) { - aa->auth_cb(aa->data); - purple_blist_request_add_buddy(aa->account, aa->username, - NULL, aa->alias); + ar->auth_cb(ar->data); + if (ar->add_buddy_after_auth) { + purple_blist_request_add_buddy(ar->account, ar->username, NULL, ar->alias); + } } static void -deny_no_add_cb(struct auth_and_add *aa) +deny_no_add_cb(struct auth_request *ar) { - aa->deny_cb(aa->data); + ar->deny_cb(ar->data); } static void * @@ -2463,49 +2466,48 @@ char *buffer; PurpleConnection *gc; GtkWidget *alert; + GdkPixbuf *prpl_icon; + struct auth_request *aa; gc = purple_account_get_connection(account); if (message != NULL && *message == '\0') message = NULL; - buffer = g_strdup_printf(_("%s%s%s%s wants to add %s to his or her buddy list%s%s"), + buffer = g_strdup_printf(_("%s%s%s%s wants to add you (%s) to his or her buddy list%s%s"), remote_user, - (alias != NULL ? " (" : ""), - (alias != NULL ? alias : ""), - (alias != NULL ? ")" : ""), - (id != NULL - ? id - : (purple_connection_get_display_name(gc) != NULL - ? purple_connection_get_display_name(gc) - : purple_account_get_username(account))), - (message != NULL ? ": " : "."), - (message != NULL ? message : "")); - - - if (!on_list) { - struct auth_and_add *aa = g_new0(struct auth_and_add, 1); - aa->auth_cb = auth_cb; - aa->deny_cb = deny_cb; - aa->data = user_data; - aa->username = g_strdup(remote_user); - aa->alias = g_strdup(alias); - aa->account = account; - alert = pidgin_make_mini_dialog(gc, PIDGIN_STOCK_DIALOG_QUESTION, - _("Authorize buddy?"), buffer, aa, - _("Authorize"), authorize_and_add_cb, - _("Deny"), deny_no_add_cb, - NULL); - g_signal_connect_swapped(G_OBJECT(alert), "destroy", G_CALLBACK(free_auth_and_add), aa); - } else { - alert = pidgin_make_mini_dialog(gc, PIDGIN_STOCK_DIALOG_QUESTION, - _("Authorize buddy?"), buffer, user_data, - _("Authorize"), auth_cb, - _("Deny"), deny_cb, - NULL); - } + (alias != NULL ? " (" : ""), + (alias != NULL ? alias : ""), + (alias != NULL ? ")" : ""), + (id != NULL + ? id + : (purple_connection_get_display_name(gc) != NULL + ? purple_connection_get_display_name(gc) + : purple_account_get_username(account))), + (message != NULL ? ": " : "."), + (message != NULL ? message : "")); + + + prpl_icon = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL); + + aa = g_new0(struct auth_request, 1); + aa->auth_cb = auth_cb; + aa->deny_cb = deny_cb; + aa->data = user_data; + aa->username = g_strdup(remote_user); + aa->alias = g_strdup(alias); + aa->account = account; + aa->add_buddy_after_auth = !on_list; + + alert = pidgin_make_mini_dialog_with_custom_icon( + gc, prpl_icon, + _("Authorize buddy?"), buffer, aa, + _("Authorize"), authorize_and_add_cb, + _("Deny"), deny_no_add_cb, + NULL); + + g_signal_connect_swapped(G_OBJECT(alert), "destroy", G_CALLBACK(free_auth_request), aa); + g_signal_connect(G_OBJECT(alert), "destroy", G_CALLBACK(purple_account_request_close), NULL); pidgin_blist_add_alert(alert); - g_signal_connect(G_OBJECT(alert), "destroy", - G_CALLBACK(purple_account_request_close), NULL); g_free(buffer); diff -r 69760676c50c -r 581a070c3737 pidgin/gtkblist.c --- a/pidgin/gtkblist.c Fri Aug 20 08:34:12 2010 +0000 +++ b/pidgin/gtkblist.c Fri Aug 20 08:35:27 2010 +0000 @@ -3168,7 +3168,6 @@ } else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) { PurpleBlistNode *child; PurpleBuddy *b = purple_contact_get_priority_buddy((PurpleContact *)node); - width = height = 0; for(child = node->child; child; child = child->next) { diff -r 69760676c50c -r 581a070c3737 pidgin/gtksourceundomanager.c --- a/pidgin/gtksourceundomanager.c Fri Aug 20 08:34:12 2010 +0000 +++ b/pidgin/gtksourceundomanager.c Fri Aug 20 08:35:27 2010 +0000 @@ -963,7 +963,7 @@ * the stack with a new undo action. So when we undo for example * typing, we can undo the whole word and not each letter by itself. * - * Return Value: %TRUE is merge was successful, %FALSE otherwise.˛ + * Return Value: %TRUE is merge was successful, %FALSE otherwise. **/ static gboolean gtk_source_undo_manager_merge_action (GtkSourceUndoManager *um, diff -r 69760676c50c -r 581a070c3737 pidgin/gtkutils.c --- a/pidgin/gtkutils.c Fri Aug 20 08:34:12 2010 +0000 +++ b/pidgin/gtkutils.c Fri Aug 20 08:35:27 2010 +0000 @@ -1036,7 +1036,7 @@ char *username = NULL; char *alias = NULL; char *str; - char *c, *s; + char *s; gboolean valid; g_return_val_if_fail(msg != NULL, FALSE); @@ -1078,7 +1078,7 @@ if (*s == '\r') *s++ = '\0'; if (*s == '\n') *s++ = '\0'; - if ((c = strchr(key, ':')) != NULL) + if (strchr(key, ':') != NULL) { if (!g_ascii_strcasecmp(key, "X-IM-Username:")) username = g_strdup(value); @@ -2611,18 +2611,11 @@ } } -GtkWidget * -pidgin_make_mini_dialog(PurpleConnection *gc, - const char *icon_name, - const char *primary, - const char *secondary, - void *user_data, - ...) +static void +mini_dialog_init(PidginMiniDialog *mini_dialog, PurpleConnection *gc, void *user_data, va_list args) { - PidginMiniDialog *mini_dialog; const char *button_text; GList *cb_datas = NULL; - va_list args; static gboolean first_call = TRUE; if (first_call) { @@ -2632,12 +2625,10 @@ PURPLE_CALLBACK(connection_signed_off_cb), NULL); } - mini_dialog = pidgin_mini_dialog_new(primary, secondary, icon_name); g_object_set_data(G_OBJECT(mini_dialog), "gc" ,gc); g_signal_connect(G_OBJECT(mini_dialog), "destroy", G_CALLBACK(alert_killed_cb), NULL); - va_start(args, user_data); while ((button_text = va_arg(args, char*))) { struct _old_button_clicked_cb_data *data = NULL; PidginMiniDialogCallback wrapper_cb = NULL; @@ -2654,12 +2645,40 @@ wrapper_cb, data); cb_datas = g_list_append(cb_datas, data); } - va_end(args); g_signal_connect(G_OBJECT(mini_dialog), "destroy", G_CALLBACK(old_mini_dialog_destroy_cb), cb_datas); - +} + +#define INIT_AND_RETURN_MINI_DIALOG(mini_dialog) \ + va_list args; \ + va_start(args, user_data); \ + mini_dialog_init(mini_dialog, gc, user_data, args); \ + va_end(args); \ return GTK_WIDGET(mini_dialog); + +GtkWidget * +pidgin_make_mini_dialog(PurpleConnection *gc, + const char *icon_name, + const char *primary, + const char *secondary, + void *user_data, + ...) +{ + PidginMiniDialog *mini_dialog = pidgin_mini_dialog_new(primary, secondary, icon_name); + INIT_AND_RETURN_MINI_DIALOG(mini_dialog); +} + +GtkWidget * +pidgin_make_mini_dialog_with_custom_icon(PurpleConnection *gc, + GdkPixbuf *custom_icon, + const char *primary, + const char *secondary, + void *user_data, + ...) +{ + PidginMiniDialog *mini_dialog = pidgin_mini_dialog_new_with_custom_icon(primary, secondary, custom_icon); + INIT_AND_RETURN_MINI_DIALOG(mini_dialog); } /* diff -r 69760676c50c -r 581a070c3737 pidgin/gtkutils.h --- a/pidgin/gtkutils.h Fri Aug 20 08:34:12 2010 +0000 +++ b/pidgin/gtkutils.h Fri Aug 20 08:35:27 2010 +0000 @@ -718,6 +718,17 @@ void *user_data, ...) G_GNUC_NULL_TERMINATED; /** + * Does exactly what pidgin_make_mini_dialog() does, except you can specify + * a custom icon for the dialog. + */ +GtkWidget *pidgin_make_mini_dialog_with_custom_icon(PurpleConnection *gc, + GdkPixbuf *custom_icon, + const char *primary, + const char *secondary, + void *user_data, + ...) G_GNUC_NULL_TERMINATED; + +/** * This is a callback function to be used for Ctrl+F searching in treeviews. * Sample Use: * gtk_tree_view_set_search_equal_func(treeview, diff -r 69760676c50c -r 581a070c3737 pidgin/minidialog.c --- a/pidgin/minidialog.c Fri Aug 20 08:34:12 2010 +0000 +++ b/pidgin/minidialog.c Fri Aug 20 08:35:27 2010 +0000 @@ -75,6 +75,7 @@ PROP_TITLE = 1, PROP_DESCRIPTION, PROP_ICON_NAME, + PROP_CUSTOM_ICON, LAST_PROPERTY } HazeConnectionProperties; @@ -93,17 +94,32 @@ #define PIDGIN_MINI_DIALOG_GET_PRIVATE(dialog) \ ((PidginMiniDialogPrivate *) ((dialog)->priv)) +static PidginMiniDialog * +mini_dialog_new(const gchar *title, const gchar *description) +{ + return g_object_new(PIDGIN_TYPE_MINI_DIALOG, + "title", title, + "description", description, + NULL); +} + PidginMiniDialog * pidgin_mini_dialog_new(const gchar *title, const gchar *description, const gchar *icon_name) { - PidginMiniDialog *mini_dialog = g_object_new(PIDGIN_TYPE_MINI_DIALOG, - "title", title, - "description", description, - "icon-name", icon_name, - NULL); + PidginMiniDialog *mini_dialog = mini_dialog_new(title, description); + pidgin_mini_dialog_set_icon_name(mini_dialog, icon_name); + return mini_dialog; +} +PidginMiniDialog * +pidgin_mini_dialog_new_with_custom_icon(const gchar *title, + const gchar *description, + GdkPixbuf *custom_icon) +{ + PidginMiniDialog *mini_dialog = mini_dialog_new(title, description); + pidgin_mini_dialog_set_custom_icon(mini_dialog, custom_icon); return mini_dialog; } @@ -125,7 +141,13 @@ pidgin_mini_dialog_set_icon_name(PidginMiniDialog *mini_dialog, const char *icon_name) { - g_object_set(G_OBJECT(mini_dialog), "icon_name", icon_name, NULL); + g_object_set(G_OBJECT(mini_dialog), "icon-name", icon_name, NULL); +} + +void +pidgin_mini_dialog_set_custom_icon(PidginMiniDialog *mini_dialog, GdkPixbuf *custom_icon) +{ + g_object_set(G_OBJECT(mini_dialog), "custom-icon", custom_icon, NULL); } struct _mini_dialog_button_clicked_cb_data @@ -233,6 +255,9 @@ g_value_set_string(value, icon_name); break; } + case PROP_CUSTOM_ICON: + g_value_set_object(value, gtk_image_get_pixbuf(priv->icon)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } @@ -305,6 +330,8 @@ gtk_image_set_from_stock(priv->icon, g_value_get_string(value), gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL)); break; + case PROP_CUSTOM_ICON: + gtk_image_set_from_pixbuf(priv->icon, g_value_get_object(value)); default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } @@ -355,6 +382,13 @@ G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READWRITE); g_object_class_install_property (object_class, PROP_ICON_NAME, param_spec); + + param_spec = g_param_spec_object("custom-icon", "custom-icon", + "Pixbuf to use as the dialog's icon", + GDK_TYPE_PIXBUF, + G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | + G_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_CUSTOM_ICON, param_spec); } /* 16 is the width of the icon, due to PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL */ diff -r 69760676c50c -r 581a070c3737 pidgin/minidialog.h --- a/pidgin/minidialog.h Fri Aug 20 08:34:12 2010 +0000 +++ b/pidgin/minidialog.h Fri Aug 20 08:35:27 2010 +0000 @@ -73,6 +73,8 @@ *
The Gtk stock id of an icon for the dialog, or @c NULL for no icon. * @see pidginstock.h *
+ *
"custom-icon" (GdkPixbuf *)
+ *
The custom icon to use instead of a stock one (overrides the "icon-name" property).
* */ typedef struct { @@ -108,13 +110,20 @@ /** Get the GType of #PidginMiniDialog. */ GType pidgin_mini_dialog_get_type (void); -/** Creates a new #PidginMiniDialog. This is a shortcut for creating the dialog +/** Creates a new #PidginMiniDialog with a stock icon. This is a shortcut for creating the dialog * with @c g_object_new() then setting each property yourself. * @return a new #PidginMiniDialog. */ PidginMiniDialog *pidgin_mini_dialog_new(const gchar *title, const gchar *description, const gchar *icon_name); +/** Creates a new #PidginMiniDialog with a custom icon. This is a shortcut for creating the dialog + * with @c g_object_new() then setting each property yourself. + * @return a new #PidginMiniDialog. + */ +PidginMiniDialog *pidgin_mini_dialog_new_with_custom_icon(const gchar *title, + const gchar *description, GdkPixbuf *custom_icon); + /** Shortcut for setting a mini-dialog's title via GObject properties. * @param mini_dialog a mini-dialog * @param title the new title for @a mini_dialog @@ -137,6 +146,13 @@ void pidgin_mini_dialog_set_icon_name(PidginMiniDialog *mini_dialog, const char *icon_name); +/** Shortcut for setting a mini-dialog's custom icon via GObject properties. + * @param mini_dialog a mini-dialog + * @param icon_name the pixbuf to use as a custom icon + */ +void pidgin_mini_dialog_set_custom_icon(PidginMiniDialog *mini_dialog, + GdkPixbuf *custom_icon); + /** Adds a new button to a mini-dialog, and attaches the supplied callback to * its clicked signal. After a button is clicked, the dialog is * destroyed. diff -r 69760676c50c -r 581a070c3737 pidgin/plugins/xmppconsole.c --- a/pidgin/plugins/xmppconsole.c Fri Aug 20 08:34:12 2010 +0000 +++ b/pidgin/plugins/xmppconsole.c Fri Aug 20 08:35:27 2010 +0000 @@ -183,7 +183,7 @@ { GtkTextIter start, end; PurplePluginProtocolInfo *prpl_info = NULL; - PurpleConnection *gc = console->gc; + PurpleConnection *gc; GtkTextBuffer *buffer; char *text; diff -r 69760676c50c -r 581a070c3737 po/hu.po --- a/po/hu.po Fri Aug 20 08:34:12 2010 +0000 +++ b/po/hu.po Fri Aug 20 08:35:27 2010 +0000 @@ -9,14 +9,14 @@ msgstr "" "Project-Id-Version: pidgin 2.7\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-07-27 01:17-0400\n" -"PO-Revision-Date: 2010-05-29 02:36+0200\n" +"POT-Creation-Date: 2010-08-15 21:49+0200\n" +"PO-Revision-Date: 2010-08-15 21:48+0200\n" "Last-Translator: Gabor Kelemen \n" "Language-Team: Hungarian \n" -"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: \n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: KBabel 1.11.4\n" @@ -64,9 +64,8 @@ msgid "Error" msgstr "Hiba" -#, fuzzy msgid "Account was not modified" -msgstr "A fiók nem lett felvéve" +msgstr "A fiók nem lett módosítva" msgid "Account was not added" msgstr "A fiók nem lett felvéve" @@ -77,10 +76,13 @@ msgid "" "The account's protocol cannot be changed while it is connected to the server." msgstr "" +"A fiók protokollja nem módosítható, ha épp csatlakozva van a kiszolgálóhoz." msgid "" "The account's username cannot be changed while it is connected to the server." msgstr "" +"A fiók felhasználóneve nem módosítható, ha épp csatlakozva van a " +"kiszolgálóhoz." msgid "New mail notifications" msgstr "Értesítések új levélre" @@ -691,7 +693,7 @@ msgid "me <action>: Send an IRC style action to a buddy or chat." msgstr "" -"me <művelet>: IRC stílusú művelet küldése egy partnernak vagy " +"me <művelet>: IRC stílusú művelet küldése egy partnernek vagy " "csevegésnek." msgid "" @@ -1689,6 +1691,8 @@ "The certificate is not valid yet. Check that your computer's date and time " "are accurate." msgstr "" +"A tanúsítvány még nem érvényes. Ellenőrizze a számítógép dátumának és " +"idejének pontosságát." msgid "The certificate has expired and should not be considered valid." msgstr "A tanúsítvány lejárt és nem tekinthető érvényesnek." @@ -3834,7 +3838,7 @@ "this and continue authentication?" msgstr "" "%s szöveges hitelesítést követel meg egy nem titkosított csatornán. " -"Engedélyezi ezt és folytatja a hitelesítést?" +"Engedélyezi ezt, és folytatja a hitelesítést?" msgid "Plaintext Authentication" msgstr "Egyszerű szöveges hitelesítés" @@ -3848,18 +3852,18 @@ msgid "Server thinks authentication is complete, but client does not" msgstr "A kiszolgáló szerint a hitelesítés kész, a kliens szerint nem" -#, fuzzy msgid "Server may require plaintext authentication over an unencrypted stream" msgstr "" -"A kiszolgáló szöveges hitelesítést követel meg egy nem titkosított csatornán" - -#, fuzzy, c-format +"A kiszolgáló egyszerű szöveges hitelesítést követel meg egy nem titkosított " +"csatornán" + +#, c-format msgid "" "%s may require plaintext authentication over an unencrypted connection. " "Allow this and continue authentication?" msgstr "" -"%s szöveges hitelesítést követel meg egy nem titkosított csatornán. " -"Engedélyezi ezt és folytatja a hitelesítést?" +"%s egyszerű szöveges hitelesítést követelhet meg egy nem titkosított " +"kapcsolaton. Engedélyezi ezt, és folytatja a hitelesítést?" msgid "SASL authentication failed" msgstr "A SASL hitelesítés meghiúsult" @@ -5939,8 +5943,8 @@ msgid "The two PINs you entered do not match." msgstr "A megadott két PIN nem egyezik." -msgid "The name you entered is invalid." -msgstr "A megadott név érvénytelen." +msgid "The Display Name you entered is invalid." +msgstr "A megadott megjelenő név érvénytelen." msgid "" "The birthday you entered is invalid. The correct format is: 'YYYY-MM-DD'." @@ -5958,9 +5962,8 @@ msgid "Your profile information is not yet retrieved. Please try again later." msgstr "A profilinformációi még nincsenek lekérve. Próbálja újra később." -#, fuzzy msgid "Your UID" -msgstr "Az Ön MXitId-ja" +msgstr "Az Ön UID-ja" #. pin #. pin (required) @@ -6032,16 +6035,12 @@ msgid "Connecting..." msgstr "Kapcsolódás…" -#, fuzzy -msgid "The Display Name you entered is invalid." -msgstr "A megadott név érvénytelen." - msgid "The PIN you entered has an invalid length [7-10]." msgstr "A megadott PIN érvénytelen hosszúságú [7-10]." #. mxit login name msgid "MXit ID" -msgstr "" +msgstr "MXit azonosító" #. show the form to the user to complete msgid "Register New MXit Account" @@ -6069,14 +6068,13 @@ msgid "Invalid country selected. Please try again." msgstr "Érvénytelen országot választott. Próbálja újra később." -#, fuzzy msgid "The MXit ID you entered is not registered. Please register first." -msgstr "A felhasználónév nincs regisztrálva. Először regisztráljon." - -#, fuzzy +msgstr "A megadott MXit azonosító nincs regisztrálva. Először regisztráljon." + msgid "The MXit ID you entered is already registered. Please choose another." msgstr "" -"A felhasználónév már használatban van. Válasszon másik felhasználónevet." +"A megadott MXit azonosító már használatban van. Válasszon másik " +"felhasználónevet." msgid "Internal error. Please try again later." msgstr "Belső hiba. Próbálja újra később." @@ -6120,9 +6118,8 @@ msgid "Hidden Number" msgstr "Rejtett szám" -#, fuzzy msgid "Your MXit ID..." -msgstr "Az Ön MXitId-ja" +msgstr "Az Ön MXit ID-ja…" #. Configuration options #. WAP server (reference: "libpurple/accountopt.h") @@ -6136,26 +6133,21 @@ msgstr "Felugró indítókép engedélyezése" #. you were kicked -#, fuzzy msgid "You have been kicked from this MultiMX." -msgstr "Kirúgták Önt: (%s)" - -#, fuzzy +msgstr "Kirúgták ebből a MultiMX-ből." + msgid "was kicked" -msgstr "Rossz jegy" - -#, fuzzy +msgstr "kirúgva" + msgid "_Room Name:" -msgstr "Sz_oba:" +msgstr "Sz_obanév:" #. Display system message in chat window -#, fuzzy msgid "You have invited" -msgstr "Levele érkezett!" - -#, fuzzy +msgstr "Meghívták" + msgid "Last Online" -msgstr "Elérhető" +msgstr "Utoljára elérhető" #. we must have lost the connection, so terminate it so that we can reconnect msgid "We have lost the connection to MXit. Please reconnect." @@ -6727,8 +6719,8 @@ #, c-format msgid "Unable to send message. Could not get details for user (%s)." msgstr "" -"Az üzenetet nem lehet elküldeni. A felhasználó részletei nem kérhetőek le " -"(%s)." +"Az üzenetet nem lehet elküldeni. A felhasználó részletei nem kérhetőek le (%" +"s)." #, c-format msgid "Unable to add %s to your buddy list (%s)." @@ -7128,102 +7120,13 @@ "%s tried to send you a %s file, but we only allow files up to %s over Direct " "IM. Try using file transfer instead.\n" msgstr "" -"%s egy %s fájlt próbált küldeni, de közvetlen kapcsolatban legfeljebb csak " -"%s méretű fájl küldhető. Próbálkozzon inkább a fájlátvitellel.\n" +"%s egy %s fájlt próbált küldeni, de közvetlen kapcsolatban legfeljebb csak %" +"s méretű fájl küldhető. Próbálkozzon inkább a fájlátvitellel.\n" #, c-format msgid "File %s is %s, which is larger than the maximum size of %s." msgstr "A(z) %s fájl %s, amely nagyobb, mint a legnagyobb méret (%s)." -msgid "" -"(There was an error receiving this message. The buddy you are speaking with " -"is probably using a different encoding than expected. If you know what " -"encoding he is using, you can specify it in the advanced account options for " -"your AIM/ICQ account.)" -msgstr "" -"(Hiba történt az üzenet fogadása során. A partner, akivel cseveg " -"valószínűleg a várttól eltérő kódolást használ. Ha tudja, hogy a partner " -"milyen kódolást használ, akkor megadhatja azt az AIM/ICQ fiók haladó " -"fiókbeállításainál.)" - -#, c-format -msgid "" -"(There was an error receiving this message. Either you and %s have " -"different encodings selected, or %s has a buggy client.)" -msgstr "" -"(Hiba az üzenet fogadása közben. Lehetséges, hogy Ön és %s különböző " -"kódolást használnak, vagy %s hibás klienst használ.)" - -#. Label -msgid "Buddy Icon" -msgstr "Partnerikon" - -msgid "Voice" -msgstr "Hang" - -msgid "AIM Direct IM" -msgstr "AIM közvetlen azonnali üzenetek" - -msgid "Get File" -msgstr "Fájl letöltése" - -msgid "Games" -msgstr "Játékok" - -msgid "ICQ Xtraz" -msgstr "ICQ Xtraz" - -msgid "Add-Ins" -msgstr "Kiegészítők" - -msgid "Send Buddy List" -msgstr "Partnerlista küldése" - -msgid "ICQ Direct Connect" -msgstr "ICQ közvetlen kapcsolat" - -msgid "AP User" -msgstr "AP felhasználó" - -msgid "ICQ RTF" -msgstr "ICQ RTF" - -msgid "Nihilist" -msgstr "Nihilista" - -msgid "ICQ Server Relay" -msgstr "ICQ közvetítő kiszolgáló" - -msgid "Old ICQ UTF8" -msgstr "Régi ICQ UTF8" - -msgid "Trillian Encryption" -msgstr "Trillian titkosítás" - -msgid "ICQ UTF8" -msgstr "ICQ UTF8" - -msgid "Hiptop" -msgstr "Hiptop" - -msgid "Security Enabled" -msgstr "Biztonság engedélyezve" - -msgid "Video Chat" -msgstr "Videócsevegés" - -msgid "iChat AV" -msgstr "iChat AV" - -msgid "Live Video" -msgstr "Élő videó" - -msgid "Camera" -msgstr "Fényképezőgép" - -msgid "Screen Sharing" -msgstr "Képernyőmegosztás" - msgid "Free For Chat" msgstr "Ráérek csevegni" @@ -7254,15 +7157,6 @@ msgid "At lunch" msgstr "Ebédel" -msgid "IP Address" -msgstr "IP cím" - -msgid "Warning Level" -msgstr "Figyelmeztetési szint" - -msgid "Buddy Comment" -msgstr "Partnermegjegyzés" - #, c-format msgid "Unable to connect to authentication server: %s" msgstr "Nem lehet kapcsolódni a hitelesítési kiszolgálóhoz: %s" @@ -7361,15 +7255,6 @@ msgid "Unable to initialize connection" msgstr "A kapcsolat nem inicializálható" -msgid "Please authorize me so I can add you to my buddy list." -msgstr "Kérem engedélyezze, hogy felvehessem a partnereim közé." - -msgid "No reason given." -msgstr "Nincs ok megadva." - -msgid "Authorization Denied Message:" -msgstr "Engedélyezést elutasító üzenet:" - #, c-format msgid "" "The user %u has denied your request to add them to your buddy list for the " @@ -7380,6 +7265,9 @@ "következő indoklással:\n" "%s" +msgid "No reason given." +msgstr "Nincs ok megadva." + msgid "ICQ authorization denied." msgstr "ICQ engedélyezés elutasítva." @@ -7498,60 +7386,13 @@ msgstr[0] "Nem kapott meg %hu üzenetet a következőtől: %s, ismeretlen okból." msgstr[1] "Nem kapott meg %hu üzenetet a következőtől: %s, ismeretlen okból." -#, c-format -msgid "User information not available: %s" -msgstr "A felhasználó információi nem érhetőek el: %s" - -msgid "Online Since" -msgstr "Kapcsolódva ezóta" - -msgid "Member Since" -msgstr "Tagság kezdete" - -msgid "Capabilities" -msgstr "Képességek" - msgid "Your AIM connection may be lost." msgstr "Az AIM kapcsolata megszakadhatott." -#. The conversion failed! -msgid "" -"[Unable to display a message from this user because it contained invalid " -"characters.]" -msgstr "" -"[Nem lehet megjeleníteni az üzenetet ettől a felhasználótól, mert az " -"érvénytelen karaktereket tartalmazott.]" - #, c-format msgid "You have been disconnected from chat room %s." msgstr "Kilépett a(z) %s csevegőszobából." -msgid "Mobile Phone" -msgstr "Mobiltelefon" - -msgid "Personal Web Page" -msgstr "Saját weboldal" - -#. aim_userinfo_t -#. strip_html_tags -msgid "Additional Information" -msgstr "További információ" - -msgid "Zip Code" -msgstr "Irányítószám" - -msgid "Work Information" -msgstr "Munkahelyi adatok" - -msgid "Division" -msgstr "Részleg" - -msgid "Position" -msgstr "Pozíció" - -msgid "Web Page" -msgstr "Weboldal" - msgid "Pop-Up Message" msgstr "Felbukkanó üzenet" @@ -7831,8 +7672,8 @@ msgid "Change Address To:" msgstr "Cím módosítása a következőre:" -msgid "you are not waiting for authorization" -msgstr "Ön nem vár engedélyezésre" +msgid "you are not waiting for authorization" +msgstr "Ön nem vár engedélyezésre" msgid "You are awaiting authorization from the following buddies" msgstr "A következő partnerektől vár engedélyezésre" @@ -7886,9 +7727,6 @@ msgid "Search for Buddy by Email Address..." msgstr "Partner keresése e-mail cím szerint…" -msgid "Search for Buddy by Information" -msgstr "Partner keresése információ alapján" - msgid "Use clientLogin" msgstr "Kliensbejelentkezés használata" @@ -7929,85 +7767,74 @@ "képekhez. Ezzel láthatóvá válik az IP címe, ami veszélyeztetheti a " "magánszférája biztonságát." -#, fuzzy msgid "Invalid SNAC" -msgstr "Érvénytelen azonosító" +msgstr "Érvénytelen SNAC" msgid "Server rate limit exceeded" -msgstr "" +msgstr "A kiszolgáló sebességkorlátja túllépve" msgid "Client rate limit exceeded" -msgstr "" - -#, fuzzy +msgstr "A kliens sebességkorlátja túllépve" + msgid "Service unavailable" msgstr "A szolgáltatás nem érhető el" -#, fuzzy msgid "Service not defined" -msgstr "A konferencia nem található" +msgstr "A szolgáltatás nincs meghatározva" msgid "Obsolete SNAC" -msgstr "" - -#, fuzzy +msgstr "Elavult SNAC" + msgid "Not supported by host" -msgstr "Nem támogatott" - -#, fuzzy +msgstr "A kiszolgáló nem támogatja" + msgid "Not supported by client" -msgstr "Nem támogatott" +msgstr "A kliens nem támogatja" msgid "Refused by client" -msgstr "" +msgstr "A kliens visszautasította" msgid "Reply too big" -msgstr "" - -#, fuzzy +msgstr "A válasz túl nagy" + msgid "Responses lost" -msgstr "Válasz valószínűsége:" - -#, fuzzy +msgstr "A válaszok elvesztek" + msgid "Request denied" -msgstr "Kérés" +msgstr "A kérés elutasítva" msgid "Busted SNAC payload" -msgstr "" +msgstr "Sérült SNAC tartalom" msgid "Insufficient rights" -msgstr "" +msgstr "Elégtelen jogosultságok" msgid "In local permit/deny" -msgstr "" +msgstr "A helyi engedélyezésben/tiltásban" msgid "Warning level too high (sender)" -msgstr "" +msgstr "A figyelmeztetési szint túl magas (küldő)" msgid "Warning level too high (receiver)" -msgstr "" - -#, fuzzy +msgstr "A figyelmeztetési szint túl magas (fogadó)" + msgid "User temporarily unavailable" -msgstr "A szolgáltatás átmenetileg nem érhető el" - -#, fuzzy +msgstr "A felhasználó átmenetileg nem érhető el" + msgid "No match" msgstr "Nincs találat" -#, fuzzy msgid "List overflow" -msgstr "A lista megtelt" - -#, fuzzy +msgstr "A lista túlcsordult" + msgid "Request ambiguous" -msgstr "Kérés" +msgstr "A kérés kétértelmű" msgid "Queue full" -msgstr "" +msgstr "A sor tele" msgid "Not while on AOL" -msgstr "" +msgstr "Nem az AOL-on" msgid "Aquarius" msgstr "Vízöntő" @@ -10064,6 +9891,9 @@ msgid "Computer" msgstr "Számítógép" +msgid "Mobile Phone" +msgstr "Mobiltelefon" + msgid "PDA" msgstr "PDA" @@ -10232,9 +10062,8 @@ msgid "Ignore conference and chatroom invitations" msgstr "Konferencia- és csevegőszoba-meghívások figyelmen kívül hagyása" -#, fuzzy msgid "Use account proxy for HTTP and HTTPS connections" -msgstr "Fiókproxy használata SSL kapcsolatokhoz" +msgstr "Fiókproxy használata HTTP és HTTPS kapcsolatokhoz" msgid "Chat room list URL" msgstr "Csevegőszobák listájának URL címe" @@ -10493,6 +10322,9 @@ msgid "Write Error" msgstr "Írási hiba" +msgid "IP Address" +msgstr "IP cím" + msgid "Yahoo! Japan Profile" msgstr "Yahoo! Japán profil" @@ -10534,6 +10366,9 @@ msgid "Cool Link 3" msgstr "Érdekes link 3" +msgid "Member Since" +msgstr "Tagság kezdete" + msgid "Last Update" msgstr "Utolsó frissítés" @@ -10762,8 +10597,8 @@ #, c-format msgid "Access denied: HTTP proxy server forbids port %d tunneling" msgstr "" -"Hozzáférés megtagadva: a HTTP proxy kiszolgáló tiltja az alagutazást a(z) " -"%d. porton" +"Hozzáférés megtagadva: a HTTP proxy kiszolgáló tiltja az alagutazást a(z) %" +"d. porton" #, c-format msgid "Error resolving %s" @@ -11016,8 +10851,8 @@ "An error was encountered reading your %s. The file has not been loaded, and " "the old file has been renamed to %s~." msgstr "" -"Hiba történt a(z) %s olvasásakor. Ez a fájl nem lett betöltve, a régi fájl " -"%s~ néven lett elmentve." +"Hiba történt a(z) %s olvasásakor. Ez a fájl nem lett betöltve, a régi fájl %" +"s~ néven lett elmentve." msgid "" "Chat over IM. Supports AIM, Google Talk, Jabber/XMPP, MSN, Yahoo and more" @@ -11154,6 +10989,10 @@ "segítségével visszatérhet ehhez az ablakhoz fiókok hozzáadásához, " "szerkesztéséhez vagy eltávolításához." +#, c-format +msgid "%s%s%s%s wants to add you (%s) to his or her buddy list%s%s" +msgstr "%s%s%s%s felhasználó szeretné Önt (%s) felvenni a partnerlistájára%s%s" + #. Buddy List msgid "Background Color" msgstr "Háttérszín" @@ -12437,8 +12276,8 @@ "to multiple messaging services at once. %s is written in C using GTK+. %s " "is released, and may be modified and redistributed, under the terms of the " "GPL version 2 (or later). A copy of the GPL is distributed with %s. %s is " -"copyrighted by its contributors, a list of whom is also distributed with " -"%s. There is no warranty for %s.

" +"copyrighted by its contributors, a list of whom is also distributed with %" +"s. There is no warranty for %s.

" msgstr "" "A %s egy libpurple alapú moduláris üzenetküldő kliens, amely egyszerre több " "üzenetküldő szolgáltatáshoz is képes csatlakozni. A %s GTK+ használatával, C " @@ -12988,16 +12827,16 @@ #, c-format msgid "" -"Are you sure you want to permanently delete the log of the conversation in " -"%s which started at %s?" +"Are you sure you want to permanently delete the log of the conversation in %" +"s which started at %s?" msgstr "" "Biztos, hogy törölni akarja a(z) %s csatornán folytatott, %s időpontban " "kezdődött beszélgetés naplóját?" #, c-format msgid "" -"Are you sure you want to permanently delete the system log which started at " -"%s?" +"Are you sure you want to permanently delete the system log which started at %" +"s?" msgstr "" "Biztos, hogy törölni akarja a(z) %s időpontban kezdődött rendszernaplót?" @@ -13103,13 +12942,11 @@ msgid "Exiting because another libpurple client is already running.\n" msgstr "Kilépés, mert már fut egy másik libpurple kliens.\n" -#, fuzzy msgid "_Media" -msgstr "/_Média" - -#, fuzzy +msgstr "Méd_ia" + msgid "_Hangup" -msgstr "Lerakás" +msgstr "_Lerakás" #, c-format msgid "%s wishes to start an audio/video session with you." @@ -14016,6 +13853,10 @@ "Fájlméret: %s\n" "Képméret: %dx%d" +#. Label +msgid "Buddy Icon" +msgstr "Partnerikon" + #, c-format msgid "The file '%s' is too large for %s. Please try a smaller image.\n" msgstr "" @@ -14948,6 +14789,9 @@ msgid "Half Operator" msgstr "Féloperátor" +msgid "Voice" +msgstr "Hang" + msgid "Authorization dialog" msgstr "Hitelesítési ablak" @@ -15266,7 +15110,7 @@ "Ez a bővítmény XMPP kiszolgálókban vagy kliensekben végzett hibakereséshez " "hasznos." -#. $(^Name) is the current Version name (e.g. Pidgin 2.7.0). $_CLICK will become a translated version of "Click Next to continue." +#. $(^Name) is the current Version name (e.g. Pidgin 2.7.0). $_CLICK will become a translated version of "Click Next to continue." DO NOT translate the CLICK in $_CLICK. It will break the installer. msgid "" "$(^Name) is released under the GNU General Public License (GPL). The license " "is provided here for information purposes only. $_CLICK" @@ -15328,8 +15172,8 @@ #, no-c-format msgid "" "Error Installing Spellchecking ($R3).$\\rIf retrying fails, manual " -"installation instructions are at: http://developer.pidgin.im/wiki/Installing" -"%20Pidgin#manual_win32_spellcheck_installation" +"installation instructions are at: http://developer.pidgin.im/wiki/Installing%" +"20Pidgin#manual_win32_spellcheck_installation" msgstr "" "Hiba a helyesírás-ellenőrző telepítésekor. ($R3).$\\rHa az újrapróbálkozás " "meghiúsul, akkor saját kezűleg is telepítheti a http://developer.pidgin.im/" @@ -15411,29 +15255,3 @@ msgid "You do not have permission to uninstall this application." msgstr "Nincs jogosultsága az alkalmazás eltávolításához." - -#~ msgid "The certificate is not valid yet." -#~ msgstr "A tanúsítvány még nem érvényes." - -#~ msgid "The nick name you entered is invalid." -#~ msgstr "A megadott becenév érvénytelen." - -#~ msgid "MXit Login Name" -#~ msgstr "MXit bejelentkezési név" - -#~ msgid "Nick Name" -#~ msgstr "Becenév" - -#~ msgid "Your Mobile Number..." -#~ msgstr "Az Ön mobiltelefonszáma…" - -#, fuzzy -#~ msgid "Rate to host" -#~ msgstr "Meghívás csevegésre" - -#, fuzzy -#~ msgid "Rate to client" -#~ msgstr "Utolsó ismert kliens" - -#~ msgid "/Media/_Hangup" -#~ msgstr "/Média/_Lerakás"