Mercurial > pidgin.yaz
changeset 31007:c5ba7dd399fa
merged from im.pidgin.pidgin:
- oscar.c needs to be revised
- changes in google.c may need to be salvaged
line wrap: on
line diff
--- a/COPYRIGHT Tue Aug 17 17:23:13 2010 +0900 +++ b/COPYRIGHT Wed Sep 22 14:17:09 2010 +0900 @@ -18,6 +18,7 @@ Copyright (C) 1998-2009 by the following: Saleem Abdulrasool +Jakub Adam Dave Ahlswede Manuel Amador Matt Amato @@ -74,6 +75,7 @@ Jeffery Brown Philip Brown Dan Bruce +Guillaume Brunerie Norbert Buchmuller Johannes Buchner Sean Burke @@ -82,6 +84,7 @@ Andrea Canciani Damien Carbery Michael Carlson +Rodrigo Tobar Carrizo Keegan Carruthers-Smith Ludovico Cavedon Steve Cavilia @@ -330,6 +333,7 @@ John Moody Tim Mooney Sergio Moretto +Keith Moyer Andrei Mozzhuhin Christian Muise MXit Lifestyle (Pty) Ltd.
--- a/ChangeLog Tue Aug 17 17:23:13 2010 +0900 +++ b/ChangeLog Wed Sep 22 14:17:09 2010 +0900 @@ -3,6 +3,63 @@ version 2.7.4 (MM/DD/YYYY): General: * Fix search path for Tk when compiling on Debian Squeeze. (#12465) + * purple-remote now expects and produces UTF-8. (Guillaume Brunerie) + (#12049) + + libpurple: + * Fall back to an ordinary request if a UI does not support showing a + request with an icon. Fixes receiving MSN file transfer requests + including a thumbnail in Finch. + * Fix an invalid memory access when removing UPnP mappings that could + cause sporadic crashes, most notably when MSN Direct Connections are + enabled. (#12387) + * Add a sentence to the certificate warning for expired certificates + suggesting the user check their computer's date and time. (#12654) + + Pidgin: + * Add support for the Gadu-Gadu protocol in the gevolution plugin to + provide Evolution integration with contacts with GG IDs. (#10709) + * Remap the "Set User Mood" shortcut to Control-D, which does not + conflict with the previous shortcut for Get Buddy Info on the + selected buddy. + * Add a plugin action menu (under Tools) for the Voice and Video + Settings plugin. + * Use GRegex for the debug window where available. This brings regex + filtering to the debug window on Windows. (Eion Robb) (#12601) + * Add Google Chrome to the list of possible browsers on non-Windows + systems. + * Add Chromium to the list of possible browsers on non-Windows systems. + * The "Manual" browser option is now stored as a string. It is no + longer necessary to specify a full path to the browser command. + (Rodrigo Tobar Carrizo) (#12024) + * The Send To menu can now be used if the active account in the + conversation becomes disabled or inactive. (Keith Moyer) (#12471) + + Finch: + * Add support for drop-down account options (like the SILC cipher + and HMAC options or the QQ protocol version). + + XMPP: + * Unify the connection security-related settings into one dropdown. + * Fix a crash when multiple accounts are simultaneously performing + SASL authentication when built with Cyrus SASL support. (thanks + to Jan Kaluza) (#11560) + * Restore the ability to connect to XMPP servers that do not offer + Stream ID. (#12331) + * Added support for using Google's relay servers when making voice and + video calls to Google clients. + * Fix detecting file transfer proxies advertised by the server. + * Advertise support for Google Talk's JID Domain Discovery extension + in all cases again (changed in 2.7.0), not just when the domain + is "gmail.com" or "googlemail.com" (it's also needed for Google + Talk used for accounts on arbitrary domains not using Google Apps + for Your Domain). (#a14153) + + Yahoo/Yahoo JAPAN: + * Stop doing unnecessary lookups of certain alias information. This + solves deadlocks when a given Yahoo account has a ridiculously large + (>500 buddies) list and may improve login speed for those on slow + connections. (#12532) version 2.7.3 (08/10/2010): General:
--- a/ChangeLog.API Tue Aug 17 17:23:13 2010 +0900 +++ b/ChangeLog.API Wed Sep 22 14:17:09 2010 +0900 @@ -1,6 +1,14 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul version 2.7.4 (MM/DD/YYYY): + Perl: + Added: + * Purple::BuddyList::Chat::get_components + + Changed: + * Purple::BuddyList::Chat::new now works properly. Thanks + to Rafael in devel@conference.pidgin.im for reporting and + testing. version 2.7.3 (08/10/2010): libpurple:
--- a/finch/gntaccount.c Tue Aug 17 17:23:13 2010 +0900 +++ b/finch/gntaccount.c Wed Sep 22 14:17:09 2010 +0900 @@ -236,7 +236,8 @@ } else if (type == PURPLE_PREF_STRING_LIST) { - /* TODO: */ + gchar *value = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(entry)); + purple_account_set_string(account, setting, value); } else { @@ -430,8 +431,26 @@ if (type == PURPLE_PREF_STRING_LIST) { - /* TODO: Use a combobox */ - /* Don't forget to append the widget to prpl_entries */ + GntWidget *combo = gnt_combo_box_new(); + GList *opt_iter = purple_account_option_get_list(option); + const char *dv = purple_account_option_get_default_list_value(option); + const char *active = dv; + + if (account) + active = purple_account_get_string(account, + purple_account_option_get_setting(option), dv); + + gnt_box_add_widget(GNT_BOX(box), combo); + dialog->prpl_entries = g_list_append(dialog->prpl_entries, combo); + + for ( ; opt_iter; opt_iter = opt_iter->next) + { + PurpleKeyValuePair *kvp = opt_iter->data; + gnt_combo_box_add_data(GNT_COMBO_BOX(combo), kvp->value, kvp->key); + + if (g_str_equal(kvp->value, active)) + gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), kvp->value); + } } else {
--- a/finch/gntft.c Tue Aug 17 17:23:13 2010 +0900 +++ b/finch/gntft.c Wed Sep 22 14:17:09 2010 +0900 @@ -383,12 +383,10 @@ return; } - data = FINCHXFER(xfer); - update_title_progress(); if (purple_xfer_is_canceled(xfer)) - status = _("Canceled"); + status = _("Cancelled"); else status = _("Failed"); @@ -402,7 +400,7 @@ char *size_str, *remaining_str; time_t current_time; char prog_str[5]; - double kb_sent, kb_rem; + double kb_sent; double kbps = 0.0; time_t elapsed, now; char *kbsec; @@ -412,7 +410,6 @@ now = time(NULL); kb_sent = purple_xfer_get_bytes_sent(xfer) / 1024.0; - kb_rem = purple_xfer_get_bytes_remaining(xfer) / 1024.0; elapsed = (purple_xfer_get_start_time(xfer) > 0 ? now - purple_xfer_get_start_time(xfer) : 0); kbps = (elapsed > 0 ? (kb_sent / elapsed) : 0);
--- a/finch/gntft.h Tue Aug 17 17:23:13 2010 +0900 +++ b/finch/gntft.h Wed Sep 22 14:17:09 2010 +0900 @@ -72,9 +72,9 @@ void finch_xfer_dialog_remove_xfer(PurpleXfer *xfer); /** - * Indicate in a file transfer dialog that a transfer was canceled. + * Indicate in a file transfer dialog that a transfer was cancelled. * - * @param xfer The file transfer that was canceled. + * @param xfer The file transfer that was cancelled. */ void finch_xfer_dialog_cancel_xfer(PurpleXfer *xfer);
--- a/finch/libgnt/gntentry.c Tue Aug 17 17:23:13 2010 +0900 +++ b/finch/libgnt/gntentry.c Wed Sep 22 14:17:09 2010 +0900 @@ -480,8 +480,7 @@ { GntEntry *entry = GNT_ENTRY(bind); GList *iter; - const char *current , *pos; - int len; + const char *current; if (entry->history->prev && entry->search->needle) current = entry->search->needle; @@ -491,13 +490,11 @@ if (!entry->histlength || !entry->history->next || !*current) return FALSE; - len = g_utf8_strlen(current, -1); - for (iter = entry->history->next; iter; iter = iter->next) { 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; }
--- a/finch/libgnt/gnttextview.c Tue Aug 17 17:23:13 2010 +0900 +++ b/finch/libgnt/gnttextview.c Wed Sep 22 14:17:09 2010 +0900 @@ -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;
--- a/libpurple/account.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/account.c Wed Sep 22 14:17:09 2010 +0900 @@ -513,6 +513,25 @@ } static void +migrate_xmpp_encryption(PurpleAccount *account) +{ + /* When this is removed, nuke the "old_ssl" and "require_tls" settings */ + if (g_str_equal(purple_account_get_protocol_id(account), "prpl-jabber")) { + const char *sec = purple_account_get_string(account, "connection_security", ""); + + if (g_str_equal("", sec)) { + const char *val = "require_tls"; + if (purple_account_get_bool(account, "old_ssl", FALSE)) + val = "old_ssl"; + else if (!purple_account_get_bool(account, "require_tls", TRUE)) + val = "opportunistic_tls"; + + purple_account_set_string(account, "connection_security", val); + } + } +} + +static void parse_settings(xmlnode *node, PurpleAccount *account) { const char *ui; @@ -579,6 +598,9 @@ /* we do this here because we need access to account settings to determine * if we can/should migrate an old Yahoo! JAPAN account */ migrate_yahoo_japan(account); + /* we do this here because we need to do it before the user views the + * Edit Account dialog. */ + migrate_xmpp_encryption(account); } static GList * @@ -1129,7 +1151,7 @@ static void request_password_cancel_cb(PurpleAccount *account, PurpleRequestFields *fields) { - /* Disable the account as the user has canceled connecting */ + /* Disable the account as the user has cancelled connecting */ purple_account_set_enabled(account, purple_core_get_ui(), FALSE); }
--- a/libpurple/certificate.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/certificate.c Wed Sep 22 14:17:09 2010 +0900 @@ -104,7 +104,8 @@ break; case PURPLE_CERTIFICATE_EXPIRED: return _("The certificate has expired and should not be " - "considered valid."); + "considered valid. Check that your computer's date " + "and time are accurate."); break; case PURPLE_CERTIFICATE_NAME_MISMATCH: /* Translators: "domain" refers to a DNS domain (e.g. talk.google.com) */
--- a/libpurple/conversation.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/conversation.c Wed Sep 22 14:17:09 2010 +0900 @@ -1128,7 +1128,6 @@ purple_conv_im_start_typing_timeout(PurpleConvIm *im, int timeout) { PurpleConversation *conv; - const char *name; g_return_if_fail(im != NULL); @@ -1136,7 +1135,6 @@ purple_conv_im_stop_typing_timeout(im); conv = purple_conv_im_get_conversation(im); - name = purple_conversation_get_name(conv); im->typing_timeout = purple_timeout_add_seconds(timeout, reset_typing_cb, conv); } @@ -1534,7 +1532,6 @@ PurpleAccount *account; PurpleConversation *conv; PurpleConnection *gc; - PurplePluginProtocolInfo *prpl_info; g_return_if_fail(chat != NULL); g_return_if_fail(who != NULL); @@ -1543,7 +1540,6 @@ conv = purple_conv_chat_get_conversation(chat); gc = purple_conversation_get_gc(conv); account = purple_connection_get_account(gc); - prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc)); /* Don't display this if the person who wrote it is ignored. */ if (purple_conv_chat_is_user_ignored(chat, who))
--- a/libpurple/desktopitem.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/desktopitem.c Wed Sep 22 14:17:09 2010 +0900 @@ -330,7 +330,7 @@ if (c == EOF && pos == 0) return NULL; - buf[pos++] = '\0'; + buf[pos] = '\0'; return buf; }
--- a/libpurple/dnssrv.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/dnssrv.c Wed Sep 22 14:17:09 2010 +0900 @@ -534,7 +534,7 @@ PurpleSrvResponse *srvres = NULL; PurpleSrvQueryData *query_data = data; if(query_data->error_message != NULL) { - purple_debug_error("dnssrv", query_data->error_message); + purple_debug_error("dnssrv", "%s", query_data->error_message); if (query_data->type == DNS_TYPE_SRV) { if (query_data->cb.srv) query_data->cb.srv(srvres, 0, query_data->extradata);
--- a/libpurple/ft.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/ft.c Wed Sep 22 14:17:09 2010 +0900 @@ -752,6 +752,7 @@ return xfer->status; } +/* FIXME: Rename with cancelled for 3.0.0. */ gboolean purple_xfer_is_canceled(const PurpleXfer *xfer) {
--- a/libpurple/ft.h Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/ft.h Wed Sep 22 14:17:09 2010 +0900 @@ -58,8 +58,8 @@ PURPLE_XFER_STATUS_ACCEPTED, /**< Receive accepted, but destination file not selected yet */ PURPLE_XFER_STATUS_STARTED, /**< purple_xfer_start has been called. */ PURPLE_XFER_STATUS_DONE, /**< The xfer completed successfully. */ - PURPLE_XFER_STATUS_CANCEL_LOCAL, /**< The xfer was canceled by us. */ - PURPLE_XFER_STATUS_CANCEL_REMOTE /**< The xfer was canceled by the other end, or we couldn't connect. */ + PURPLE_XFER_STATUS_CANCEL_LOCAL, /**< The xfer was cancelled by us. */ + PURPLE_XFER_STATUS_CANCEL_REMOTE /**< The xfer was cancelled by the other end, or we couldn't connect. */ } PurpleXferStatusType; /** @@ -304,11 +304,12 @@ PurpleXferStatusType purple_xfer_get_status(const PurpleXfer *xfer); /** - * Returns true if the file transfer was canceled. + * Returns true if the file transfer was cancelled. * * @param xfer The file transfer. * - * @return Whether or not the transfer was canceled. + * @return Whether or not the transfer was cancelled. + * FIXME: This should be renamed using cancelled for 3.0.0. */ gboolean purple_xfer_is_canceled(const PurpleXfer *xfer);
--- a/libpurple/log.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/log.c Wed Sep 22 14:17:09 2010 +0900 @@ -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];
--- a/libpurple/media.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/media.c Wed Sep 22 14:17:09 2010 +0900 @@ -515,7 +515,8 @@ if (!media->priv->sessions) { purple_debug_info("media", "Creating hash table for sessions\n"); - media->priv->sessions = g_hash_table_new(g_str_hash, g_str_equal); + media->priv->sessions = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, NULL); } g_hash_table_insert(media->priv->sessions, g_strdup(session->id), session); }
--- a/libpurple/media/backend-fs2.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/media/backend-fs2.c Wed Sep 22 14:17:09 2010 +0900 @@ -208,11 +208,7 @@ } if (priv->participants) { - GList *participants = - g_hash_table_get_values(priv->participants); - for (; participants; participants = g_list_delete_link( - participants, participants)) - g_object_unref(participants->data); + g_hash_table_destroy(priv->participants); priv->participants = NULL; } @@ -1425,7 +1421,8 @@ if (!priv->sessions) { purple_debug_info("backend-fs2", "Creating hash table for sessions\n"); - priv->sessions = g_hash_table_new(g_str_hash, g_str_equal); + priv->sessions = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, NULL); } g_hash_table_insert(priv->sessions, g_strdup(session->id), session); @@ -1461,7 +1458,7 @@ purple_debug_info("backend-fs2", "Creating hash table for participants\n"); priv->participants = g_hash_table_new_full(g_str_hash, - g_str_equal, g_free, NULL); + g_str_equal, g_free, g_object_unref); } g_hash_table_insert(priv->participants, g_strdup(name), participant); @@ -1564,6 +1561,30 @@ (GSourceFunc)src_pad_added_cb_cb, stream); } +static GValueArray * +append_relay_info(GValueArray *relay_info, const gchar *ip, gint port, + const gchar *username, const gchar *password, const gchar *type) +{ + GValue value; + GstStructure *turn_setup = gst_structure_new("relay-info", + "ip", G_TYPE_STRING, ip, + "port", G_TYPE_UINT, port, + "username", G_TYPE_STRING, username, + "password", G_TYPE_STRING, password, + "relay-type", G_TYPE_STRING, type, + NULL); + + if (turn_setup) { + memset(&value, 0, sizeof(GValue)); + g_value_init(&value, GST_TYPE_STRUCTURE); + gst_value_set_structure(&value, turn_setup); + relay_info = g_value_array_append(relay_info, &value); + gst_structure_free(turn_setup); + } + + return relay_info; +} + static gboolean create_stream(PurpleMediaBackendFs2 *self, const gchar *sess_id, const gchar *who, @@ -1584,6 +1605,18 @@ PurpleMediaBackendFs2Session *session; PurpleMediaBackendFs2Stream *stream; FsParticipant *participant; + /* check if the prpl has already specified a relay-info + we need to do this to allow them to override when using non-standard + TURN modes, like Google f.ex. */ + gboolean got_turn_from_prpl = FALSE; + int i; + + for (i = 0 ; i < num_params ; i++) { + if (purple_strequal(params[i].name, "relay-info")) { + got_turn_from_prpl = TRUE; + break; + } + } memcpy(_params, params, sizeof(GParameter) * num_params); @@ -1603,34 +1636,24 @@ ++_num_params; } - if (turn_ip && !strcmp("nice", transmitter)) { + if (turn_ip && !strcmp("nice", transmitter) && !got_turn_from_prpl) { GValueArray *relay_info = g_value_array_new(0); - GValue value; - gint turn_port = purple_prefs_get_int( - "/purple/network/turn_port"); + gint port; const gchar *username = purple_prefs_get_string( "/purple/network/turn_username"); const gchar *password = purple_prefs_get_string( "/purple/network/turn_password"); - GstStructure *turn_setup = gst_structure_new("relay-info", - "ip", G_TYPE_STRING, turn_ip, - "port", G_TYPE_UINT, turn_port, - "username", G_TYPE_STRING, username, - "password", G_TYPE_STRING, password, - NULL); - if (!turn_setup) { - purple_debug_error("backend-fs2", - "Error creating relay info structure"); - return FALSE; + /* UDP */ + port = purple_prefs_get_int("/purple/network/turn_port"); + if (port > 0) { + relay_info = append_relay_info(relay_info, turn_ip, port, username, + password, "udp"); } - memset(&value, 0, sizeof(GValue)); - g_value_init(&value, GST_TYPE_STRUCTURE); - gst_value_set_structure(&value, turn_setup); - relay_info = g_value_array_append(relay_info, &value); - gst_structure_free(turn_setup); - + /* should add TCP and perhaps TLS relaying options when these are + supported by libnice using non-google mode */ + purple_debug_info("backend-fs2", "Setting relay-info on new stream\n"); _params[_num_params].name = "relay-info"; @@ -1791,7 +1814,7 @@ const gchar *sess_id) { PurpleMediaBackendFs2Private *priv; - gboolean ret; + gboolean ret = FALSE; g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), FALSE); @@ -1837,15 +1860,12 @@ purple_media_backend_fs2_get_codecs(PurpleMediaBackend *self, const gchar *sess_id) { - PurpleMediaBackendFs2Private *priv; PurpleMediaBackendFs2Session *session; GList *fscodecs; GList *codecs; g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), NULL); - priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self); - session = get_session(PURPLE_MEDIA_BACKEND_FS2(self), sess_id); if (session == NULL) @@ -2014,13 +2034,10 @@ const gchar *sess_id, const gchar *who, double level) { #ifdef USE_VV - PurpleMediaBackendFs2Private *priv; GList *streams; g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self)); - priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self); - purple_prefs_set_int("/purple/media/audio/volume/output", level); streams = get_streams(self, sess_id, who);
--- a/libpurple/media/codec.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/media/codec.c Wed Sep 22 14:17:09 2010 +0900 @@ -83,9 +83,11 @@ PURPLE_MEDIA_CODEC_GET_PRIVATE(info); g_free(priv->encoding_name); for (; priv->optional_params; priv->optional_params = - g_list_delete_link(priv->optional_params, - priv->optional_params)) { - g_free(priv->optional_params->data); + g_list_delete_link(priv->optional_params, priv->optional_params)) { + PurpleKeyValuePair *param = priv->optional_params->data; + g_free(param->key); + g_free(param->value); + g_free(param); } } @@ -302,10 +304,10 @@ g_free(param->key); g_free(param->value); - g_free(param); priv->optional_params = g_list_remove(priv->optional_params, param); + g_free(param); } PurpleKeyValuePair *
--- a/libpurple/media/codec.h Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/media/codec.h Wed Sep 22 14:17:09 2010 +0900 @@ -121,7 +121,8 @@ * * @param The codec to get the optional parameters from. * - * @return The list of optional parameters. + * @return The list of optional parameters. The list is owned by the codec and + * should not be freed. * * @since 2.6.0 */
--- a/libpurple/network.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/network.c Wed Sep 22 14:17:09 2010 +0900 @@ -693,7 +693,7 @@ static gboolean _print_debug_msg(gpointer data) { gchar *msg = data; - purple_debug_warning("network", msg); + purple_debug_warning("network", "%s", msg); g_free(msg); return FALSE; } @@ -1077,12 +1077,10 @@ if (protocol) { purple_network_upnp_mapping_remove(&port, protocol, NULL); - g_hash_table_remove(upnp_port_mappings, protocol); } else { protocol = g_hash_table_lookup(nat_pmp_port_mappings, &port); if (protocol) { purple_network_nat_pmp_mapping_remove(&port, protocol, NULL); - g_hash_table_remove(nat_pmp_port_mappings, protocol); } } }
--- a/libpurple/network.h Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/network.h Wed Sep 22 14:17:09 2010 +0900 @@ -239,7 +239,7 @@ * by passing in the return value from either purple_network_listen() * or purple_network_listen_range(). * - * @param listen_data This listener attempt will be canceled and + * @param listen_data This listener attempt will be cancelled and * the struct will be freed. */ void purple_network_listen_cancel(PurpleNetworkListenData *listen_data);
--- a/libpurple/plugins/idle.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/plugins/idle.c Wed Sep 22 14:17:09 2010 +0900 @@ -110,9 +110,6 @@ for(iter = list; iter; iter = iter->next) { acct = (PurpleAccount *)(iter->data); - if(acct) - prpl_id = purple_account_get_protocol_id(acct); - if(acct && idleable_filter(acct)) { purple_debug_misc("idle", "Idling %s.\n", purple_account_get_username(acct));
--- a/libpurple/plugins/perl/common/BuddyList.xs Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/plugins/perl/common/BuddyList.xs Wed Sep 22 14:17:09 2010 +0900 @@ -2,6 +2,13 @@ #include "module.h" #include "../perl-handlers.h" +static void +chat_components_foreach(gpointer key, gpointer value, gpointer user_data) +{ + HV *hv = user_data; + hv_store(hv, key, strlen(key), newSVpv(value, 0), 0); +} + MODULE = Purple::BuddyList PACKAGE = Purple PREFIX = purple_ PROTOTYPES: ENABLE @@ -331,6 +338,19 @@ purple_chat_get_name(chat) Purple::BuddyList::Chat chat +HV * +purple_chat_get_components(chat) + Purple::BuddyList::Chat chat +INIT: + HV * t_HV; + GHashTable * t_GHash; +CODE: + t_GHash = purple_chat_get_components(chat); + RETVAL = t_HV = newHV(); + g_hash_table_foreach(t_GHash, chat_components_foreach, t_HV); +OUTPUT: + RETVAL + Purple::BuddyList::Chat purple_chat_new(account, alias, components) Purple::Account account @@ -345,14 +365,14 @@ char *t_key, *t_value; CODE: t_HV = (HV *)SvRV(components); - t_GHash = g_hash_table_new(g_str_hash, g_str_equal); + t_GHash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); for (t_HE = hv_iternext(t_HV); t_HE != NULL; t_HE = hv_iternext(t_HV) ) { t_key = hv_iterkey(t_HE, &len); t_SV = *hv_fetch(t_HV, t_key, len, 0); t_value = SvPVutf8_nolen(t_SV); - g_hash_table_insert(t_GHash, t_key, t_value); + g_hash_table_insert(t_GHash, g_strdup(t_key), g_strdup(t_value)); } RETVAL = purple_chat_new(account, alias, t_GHash);
--- a/libpurple/plugins/perl/common/Server.xs Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/plugins/perl/common/Server.xs Wed Sep 22 14:17:09 2010 +0900 @@ -144,6 +144,7 @@ g_hash_table_insert(t_GHash, t_key, t_value); } serv_join_chat(conn, t_GHash); + g_hash_table_destroy(t_GHash); void serv_move_buddy(buddy, group1, group2)
--- a/libpurple/plugins/signals-test.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/plugins/signals-test.c Wed Sep 22 14:17:09 2010 +0900 @@ -592,12 +592,12 @@ static void ft_recv_cancel_cb(PurpleXfer *xfer, gpointer data) { - purple_debug_misc("signals test", "file receive canceled\n"); + purple_debug_misc("signals test", "file receive cancelled\n"); } static void ft_send_cancel_cb(PurpleXfer *xfer, gpointer data) { - purple_debug_misc("signals test", "file send canceled\n"); + purple_debug_misc("signals test", "file send cancelled\n"); } static void
--- a/libpurple/plugins/tcl/tcl_cmd.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/plugins/tcl/tcl_cmd.c Wed Sep 22 14:17:09 2010 +0900 @@ -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",
--- a/libpurple/plugins/tcl/tcl_signals.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/plugins/tcl/tcl_signals.c Wed Sep 22 14:17:09 2010 +0900 @@ -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;
--- a/libpurple/prefs.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/prefs.c Wed Sep 22 14:17:09 2010 +0900 @@ -506,7 +506,6 @@ return g_strdup("/"); name = g_string_new(pref->name); - parent = pref->parent; for(parent = pref->parent; parent && parent->name; parent = parent->parent) { name = g_string_prepend_c(name, '/');
--- a/libpurple/protocols/bonjour/bonjour.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/bonjour/bonjour.c Wed Sep 22 14:17:09 2010 +0900 @@ -206,18 +206,12 @@ { PurpleConnection *gc; BonjourData *bd; - gboolean disconnected; - PurpleStatusType *type; - int primitive; PurplePresence *presence; const char *message, *bonjour_status; gchar *stripped; gc = purple_account_get_connection(account); bd = gc->proto_data; - disconnected = purple_account_is_disconnected(account); - type = purple_status_get_type(status); - primitive = purple_status_type_get_primitive(type); presence = purple_account_get_presence(account); message = purple_status_get_attr_string(status, "message");
--- a/libpurple/protocols/bonjour/jabber.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/bonjour/jabber.c Wed Sep 22 14:17:09 2010 +0900 @@ -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);
--- a/libpurple/protocols/bonjour/mdns_avahi.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/bonjour/mdns_avahi.c Wed Sep 22 14:17:09 2010 +0900 @@ -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; @@ -189,12 +188,14 @@ bb->ips = g_slist_remove(bb->ips, rd->ip); g_free((gchar *) rd->ip); } - rd->ip = g_strdup(ip); /* IPv6 goes at the front of the list and IPv4 at the end so that we "prefer" IPv6, if present */ - if (protocol == AVAHI_PROTO_INET6) + if (protocol == AVAHI_PROTO_INET6) { + rd->ip = g_strdup_printf("%s%%%d", ip, interface); bb->ips = g_slist_prepend(bb->ips, (gchar *) rd->ip); - else + } else { + rd->ip = g_strdup(ip); bb->ips = g_slist_append(bb->ips, (gchar *) rd->ip); + } } bb->port_p2pj = port; @@ -202,7 +203,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
--- a/libpurple/protocols/jabber/Makefile.am Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/Makefile.am Wed Sep 22 14:17:09 2010 +0900 @@ -26,8 +26,20 @@ data.h \ disco.c \ disco.h \ - google.c \ - google.h \ + google/gmail.c \ + google/gmail.h \ + google/google.c \ + google/google.h \ + google/google_presence.c \ + google/google_presence.h \ + google/google_roster.c \ + google/google_roster.h \ + google/google_session.c \ + google/google_session.h \ + google/jingleinfo.c \ + google/jingleinfo.h \ + google/relay.c \ + google/relay.h \ ibb.c \ ibb.h \ iq.c \ @@ -98,7 +110,10 @@ st = pkg_LTLIBRARIES = libjabber.la libxmpp.la libjabber_la_SOURCES = $(JABBERSOURCES) -libjabber_la_LIBADD = $(GLIB_LIBS) $(SASL_LIBS) $(LIBXML_LIBS) $(IDN_LIBS) +libjabber_la_LIBADD = $(GLIB_LIBS) $(SASL_LIBS) $(LIBXML_LIBS) $(IDN_LIBS)\ + $(FARSIGHT_LIBS) \ + $(GSTREAMER_LIBS) \ + $(GSTINTERFACES_LIBS) libxmpp_la_SOURCES = libxmpp.c libxmpp_la_LIBADD = libjabber.la @@ -111,4 +126,7 @@ $(DEBUG_CFLAGS) \ $(GLIB_CFLAGS) \ $(IDN_CFLAGS) \ - $(LIBXML_CFLAGS) + $(LIBXML_CFLAGS) \ + $(FARSIGHT_CFLAGS) \ + $(GSTREAMER_CFLAGS) \ + $(GSTINTERFACES_CFLAGS)
--- a/libpurple/protocols/jabber/Makefile.mingw Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/Makefile.mingw Wed Sep 22 14:17:09 2010 +0900 @@ -55,7 +55,13 @@ chat.c \ data.c \ disco.c \ - google.c \ + google/gmail.c \ + google/google.c \ + google/google_presence.c \ + google/google_roster.c \ + google/google_session.c \ + google/jingleinfo.c \ + google/relay.c \ ibb.c \ iq.c \ jabber.c \
--- a/libpurple/protocols/jabber/auth.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/auth.c Wed Sep 22 14:17:09 2010 +0900 @@ -123,7 +123,7 @@ if (!PURPLE_CONNECTION_IS_VALID(gc)) return; - /* Disable the account as the user has canceled connecting */ + /* Disable the account as the user has cancelled connecting */ purple_account_set_enabled(purple_connection_get_account(gc), purple_core_get_ui(), FALSE); } #endif @@ -251,7 +251,8 @@ g_free(msg); } else if (type == JABBER_IQ_RESULT) { query = xmlnode_get_child(packet, "query"); - if(js->stream_id && xmlnode_get_child(query, "digest")) { + if (js->stream_id && *js->stream_id && + xmlnode_get_child(query, "digest")) { char *s, *hash; iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth"); @@ -269,8 +270,10 @@ g_free(s); jabber_iq_set_callback(iq, auth_old_result_cb, NULL); jabber_iq_send(iq); - - } else if(js->stream_id && (x = xmlnode_get_child(query, "crammd5"))) { + } else if ((x = xmlnode_get_child(query, "crammd5"))) { + /* For future reference, this appears to be a custom OS X extension + * to non-SASL authentication. + */ const char *challenge; gchar digest[33]; PurpleCipherContext *hmac; @@ -340,7 +343,8 @@ * is requiring SSL/TLS, we need to enforce it. */ if (!jabber_stream_is_ssl(js) && - purple_account_get_bool(account, "require_tls", JABBER_DEFAULT_REQUIRE_TLS)) { + g_str_equal("require_tls", + purple_account_get_string(account, "connection_security", JABBER_DEFAULT_REQUIRE_TLS))) { purple_connection_error_reason(js->gc, PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR, _("You require encryption, but it is not available on this server."));
--- a/libpurple/protocols/jabber/auth_cyrus.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/auth_cyrus.c Wed Sep 22 14:17:09 2010 +0900 @@ -94,7 +94,6 @@ PurpleAccount *account; const char *pw; size_t len; - static sasl_secret_t *x = NULL; account = purple_connection_get_account(js->gc); pw = purple_account_get_password(account); @@ -103,15 +102,16 @@ return SASL_BADPARAM; len = strlen(pw); - x = (sasl_secret_t *) realloc(x, sizeof(sasl_secret_t) + len); - - if (!x) + /* Not an off-by-one because sasl_secret_t defines char data[1] */ + /* TODO: This can probably be moved to glib's allocator */ + js->sasl_secret = malloc(sizeof(sasl_secret_t) + len); + if (!js->sasl_secret) return SASL_NOMEM; - x->len = len; - strcpy((char*)x->data, pw); + js->sasl_secret->len = len; + strcpy((char*)js->sasl_secret->data, pw); - *secret = x; + *secret = js->sasl_secret; return SASL_OK; } @@ -176,7 +176,7 @@ account = purple_connection_get_account(gc); js = purple_connection_get_protocol_data(gc); - /* Disable the account as the user has canceled connecting */ + /* Disable the account as the user has cancelled connecting */ purple_account_set_enabled(account, purple_core_get_ui(), FALSE); } @@ -321,11 +321,8 @@ xmlnode_set_namespace(auth, NS_XMPP_SASL); xmlnode_set_attrib(auth, "mechanism", js->current_mech); - if (g_str_equal(js->user->domain, "gmail.com") || - g_str_equal(js->user->domain, "googlemail.com")) { - xmlnode_set_attrib(auth, "xmlns:ga", "http://www.google.com/talk/protocol/auth"); - xmlnode_set_attrib(auth, "ga:client-uses-full-bind-result", "true"); - } + xmlnode_set_attrib(auth, "xmlns:ga", "http://www.google.com/talk/protocol/auth"); + xmlnode_set_attrib(auth, "ga:client-uses-full-bind-result", "true"); if (clientout) { if (coutlen == 0) {
--- a/libpurple/protocols/jabber/auth_plain.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/auth_plain.c Wed Sep 22 14:17:09 2010 +0900 @@ -40,11 +40,8 @@ auth = xmlnode_new("auth"); xmlnode_set_namespace(auth, NS_XMPP_SASL); - if (g_str_equal(js->user->domain, "gmail.com") || - g_str_equal(js->user->domain, "googlemail.com")) { - xmlnode_set_attrib(auth, "xmlns:ga", "http://www.google.com/talk/protocol/auth"); - xmlnode_set_attrib(auth, "ga:client-uses-full-bind-result", "true"); - } + xmlnode_set_attrib(auth, "xmlns:ga", "http://www.google.com/talk/protocol/auth"); + xmlnode_set_attrib(auth, "ga:client-uses-full-bind-result", "true"); response = g_string_new(""); response = g_string_append_c(response, '\0');
--- a/libpurple/protocols/jabber/bosh.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/bosh.c Wed Sep 22 14:17:09 2010 +0900 @@ -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.
--- a/libpurple/protocols/jabber/buddy.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/buddy.c Wed Sep 22 14:17:09 2010 +0900 @@ -38,7 +38,7 @@ #include "xdata.h" #include "pep.h" #include "adhoccommands.h" -#include "google.h" +#include "google/google.h" typedef struct { long idle_seconds;
--- a/libpurple/protocols/jabber/disco.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/disco.c Wed Sep 22 14:17:09 2010 +0900 @@ -30,7 +30,9 @@ #include "adhoccommands.h" #include "buddy.h" #include "disco.h" -#include "google.h" +#include "google/google.h" +#include "google/gmail.h" +#include "google/jingleinfo.h" #include "iq.h" #include "jabber.h" #include "jingle/jingle.h" @@ -256,7 +258,7 @@ } else if(!strcmp(category, "directory") && !strcmp(type, "user")) { /* we found a JUD */ js->user_directories = g_list_prepend(js->user_directories, g_strdup(from)); - } else if(!strcmp(category, "proxy") && !strcmp(type, NS_BYTESTREAMS)) { + } else if(!strcmp(category, "proxy") && !strcmp(type, "bytestreams")) { /* This is a bytestream proxy */ JabberIq *iq; JabberBytestreamsStreamhost *sh; @@ -597,14 +599,14 @@ for(child = xmlnode_get_child(query, "item"); child; child = xmlnode_get_next_twin(child)) { JabberIq *iq; - const char *jid, *node; + const char *jid; if(!(jid = xmlnode_get_attrib(child, "jid"))) continue; /* 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);
--- a/libpurple/protocols/jabber/google.c Tue Aug 17 17:23:13 2010 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1433 +0,0 @@ -/* -*- coding: utf-8 -*- */ -/** - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "debug.h" -#include "mediamanager.h" -#include "util.h" -#include "privacy.h" -#include "dnsquery.h" -#include "network.h" - -#include "buddy.h" -#include "google.h" -#include "jabber.h" -#include "presence.h" -#include "roster.h" -#include "iq.h" -#include "chat.h" - -#include "jingle/jingle.h" - -#ifdef USE_VV - -typedef struct { - char *id; - char *initiator; -} GoogleSessionId; - -typedef enum { - UNINIT, - SENT_INITIATE, - RECEIVED_INITIATE, - IN_PRORESS, - TERMINATED -} GoogleSessionState; - -typedef struct { - GoogleSessionId id; - GoogleSessionState state; - PurpleMedia *media; - JabberStream *js; - char *remote_jid; - gboolean video; -} GoogleSession; - -static gboolean -google_session_id_equal(gconstpointer a, gconstpointer b) -{ - GoogleSessionId *c = (GoogleSessionId*)a; - GoogleSessionId *d = (GoogleSessionId*)b; - - return !strcmp(c->id, d->id) && !strcmp(c->initiator, d->initiator); -} - -static void -google_session_destroy(GoogleSession *session) -{ - g_free(session->id.id); - g_free(session->id.initiator); - g_free(session->remote_jid); - g_free(session); -} - -static xmlnode * -google_session_create_xmlnode(GoogleSession *session, const char *type) -{ - xmlnode *node = xmlnode_new("session"); - xmlnode_set_namespace(node, NS_GOOGLE_SESSION); - xmlnode_set_attrib(node, "id", session->id.id); - xmlnode_set_attrib(node, "initiator", session->id.initiator); - xmlnode_set_attrib(node, "type", type); - return node; -} - -static void -google_session_send_candidates(PurpleMedia *media, gchar *session_id, - gchar *participant, GoogleSession *session) -{ - GList *candidates = purple_media_get_local_candidates( - session->media, session_id, session->remote_jid), *iter; - PurpleMediaCandidate *transport; - gboolean video = FALSE; - - if (!strcmp(session_id, "google-video")) - video = TRUE; - - for (iter = candidates; iter; iter = iter->next) { - JabberIq *iq; - gchar *ip, *port, *username, *password; - gchar pref[16]; - PurpleMediaCandidateType type; - xmlnode *sess; - xmlnode *candidate; - guint component_id; - transport = PURPLE_MEDIA_CANDIDATE(iter->data); - component_id = purple_media_candidate_get_component_id( - transport); - - iq = jabber_iq_new(session->js, JABBER_IQ_SET); - sess = google_session_create_xmlnode(session, "candidates"); - xmlnode_insert_child(iq->node, sess); - xmlnode_set_attrib(iq->node, "to", session->remote_jid); - - candidate = xmlnode_new("candidate"); - - ip = purple_media_candidate_get_ip(transport); - port = g_strdup_printf("%d", - purple_media_candidate_get_port(transport)); - g_ascii_dtostr(pref, 16, - purple_media_candidate_get_priority(transport) / 1000.0); - username = purple_media_candidate_get_username(transport); - password = purple_media_candidate_get_password(transport); - type = purple_media_candidate_get_candidate_type(transport); - - xmlnode_set_attrib(candidate, "address", ip); - xmlnode_set_attrib(candidate, "port", port); - xmlnode_set_attrib(candidate, "name", - component_id == PURPLE_MEDIA_COMPONENT_RTP ? - video ? "video_rtp" : "rtp" : - component_id == PURPLE_MEDIA_COMPONENT_RTCP ? - video ? "video_rtcp" : "rtcp" : "none"); - xmlnode_set_attrib(candidate, "username", username); - /* - * As of this writing, Farsight 2 in Google compatibility - * mode doesn't provide a password. The Gmail client - * requires this to be set. - */ - xmlnode_set_attrib(candidate, "password", - password != NULL ? password : ""); - xmlnode_set_attrib(candidate, "preference", pref); - xmlnode_set_attrib(candidate, "protocol", - purple_media_candidate_get_protocol(transport) - == PURPLE_MEDIA_NETWORK_PROTOCOL_UDP ? - "udp" : "tcp"); - xmlnode_set_attrib(candidate, "type", type == - PURPLE_MEDIA_CANDIDATE_TYPE_HOST ? "local" : - type == - PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX ? "stun" : - type == - PURPLE_MEDIA_CANDIDATE_TYPE_RELAY ? "relay" : - NULL); - xmlnode_set_attrib(candidate, "generation", "0"); - xmlnode_set_attrib(candidate, "network", "0"); - xmlnode_insert_child(sess, candidate); - - g_free(ip); - g_free(port); - g_free(username); - g_free(password); - - jabber_iq_send(iq); - } - purple_media_candidate_list_free(candidates); -} - -static void -google_session_ready(GoogleSession *session) -{ - PurpleMedia *media = session->media; - if (purple_media_codecs_ready(media, NULL) && - purple_media_candidates_prepared(media, NULL, NULL)) { - gchar *me = g_strdup_printf("%s@%s/%s", - session->js->user->node, - session->js->user->domain, - session->js->user->resource); - JabberIq *iq; - xmlnode *sess, *desc, *payload; - GList *codecs, *iter; - gboolean is_initiator = !strcmp(session->id.initiator, me); - - if (!is_initiator && - !purple_media_accepted(media, NULL, NULL)) { - g_free(me); - return; - } - - iq = jabber_iq_new(session->js, JABBER_IQ_SET); - - if (is_initiator) { - xmlnode_set_attrib(iq->node, "to", session->remote_jid); - xmlnode_set_attrib(iq->node, "from", session->id.initiator); - sess = google_session_create_xmlnode(session, "initiate"); - } else { - google_session_send_candidates(session->media, - "google-voice", session->remote_jid, - session); - google_session_send_candidates(session->media, - "google-video", session->remote_jid, - session); - xmlnode_set_attrib(iq->node, "to", session->remote_jid); - xmlnode_set_attrib(iq->node, "from", me); - sess = google_session_create_xmlnode(session, "accept"); - } - xmlnode_insert_child(iq->node, sess); - desc = xmlnode_new_child(sess, "description"); - if (session->video) - xmlnode_set_namespace(desc, NS_GOOGLE_SESSION_VIDEO); - else - xmlnode_set_namespace(desc, NS_GOOGLE_SESSION_PHONE); - - codecs = purple_media_get_codecs(media, "google-video"); - - for (iter = codecs; iter; iter = g_list_next(iter)) { - PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data; - gchar *id = g_strdup_printf("%d", - purple_media_codec_get_id(codec)); - gchar *encoding_name = - purple_media_codec_get_encoding_name(codec); - payload = xmlnode_new_child(desc, "payload-type"); - xmlnode_set_attrib(payload, "id", id); - xmlnode_set_attrib(payload, "name", encoding_name); - xmlnode_set_attrib(payload, "width", "320"); - xmlnode_set_attrib(payload, "height", "200"); - xmlnode_set_attrib(payload, "framerate", "30"); - g_free(encoding_name); - g_free(id); - } - purple_media_codec_list_free(codecs); - - codecs = purple_media_get_codecs(media, "google-voice"); - - for (iter = codecs; iter; iter = g_list_next(iter)) { - PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data; - gchar *id = g_strdup_printf("%d", - purple_media_codec_get_id(codec)); - gchar *encoding_name = - purple_media_codec_get_encoding_name(codec); - gchar *clock_rate = g_strdup_printf("%d", - purple_media_codec_get_clock_rate(codec)); - payload = xmlnode_new_child(desc, "payload-type"); - if (session->video) - xmlnode_set_namespace(payload, NS_GOOGLE_SESSION_PHONE); - xmlnode_set_attrib(payload, "id", id); - /* - * Hack to make Gmail accept speex as the codec. - * It shouldn't have to be case sensitive. - */ - if (purple_strequal(encoding_name, "SPEEX")) - xmlnode_set_attrib(payload, "name", "speex"); - else - xmlnode_set_attrib(payload, "name", encoding_name); - xmlnode_set_attrib(payload, "clockrate", clock_rate); - g_free(clock_rate); - g_free(encoding_name); - g_free(id); - } - purple_media_codec_list_free(codecs); - - jabber_iq_send(iq); - - if (is_initiator) { - google_session_send_candidates(session->media, - "google-voice", session->remote_jid, - session); - google_session_send_candidates(session->media, - "google-video", session->remote_jid, - session); - } - - g_signal_handlers_disconnect_by_func(G_OBJECT(session->media), - G_CALLBACK(google_session_ready), session); - } -} - -static void -google_session_state_changed_cb(PurpleMedia *media, PurpleMediaState state, - gchar *sid, gchar *name, GoogleSession *session) -{ - if (sid == NULL && name == NULL) { - if (state == PURPLE_MEDIA_STATE_END) { - google_session_destroy(session); - } - } -} - -static void -google_session_stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type, - gchar *sid, gchar *name, gboolean local, - GoogleSession *session) -{ - if (sid != NULL || name != NULL) - return; - - if (type == PURPLE_MEDIA_INFO_HANGUP) { - xmlnode *sess; - JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); - - xmlnode_set_attrib(iq->node, "to", session->remote_jid); - sess = google_session_create_xmlnode(session, "terminate"); - xmlnode_insert_child(iq->node, sess); - - jabber_iq_send(iq); - } else if (type == PURPLE_MEDIA_INFO_REJECT) { - xmlnode *sess; - JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); - - xmlnode_set_attrib(iq->node, "to", session->remote_jid); - sess = google_session_create_xmlnode(session, "reject"); - xmlnode_insert_child(iq->node, sess); - - jabber_iq_send(iq); - } else if (type == PURPLE_MEDIA_INFO_ACCEPT && local == TRUE) { - google_session_ready(session); - } -} - -static GParameter * -jabber_google_session_get_params(JabberStream *js, guint *num) -{ - guint num_params; - GParameter *params = jingle_get_params(js, &num_params); - GParameter *new_params = g_new0(GParameter, num_params + 1); - - memcpy(new_params, params, sizeof(GParameter) * num_params); - - purple_debug_info("jabber", "setting Google jingle compatibility param\n"); - new_params[num_params].name = "compatibility-mode"; - g_value_init(&new_params[num_params].value, G_TYPE_UINT); - g_value_set_uint(&new_params[num_params].value, 1); /* NICE_COMPATIBILITY_GOOGLE */ - - g_free(params); - *num = num_params + 1; - return new_params; -} - - -gboolean -jabber_google_session_initiate(JabberStream *js, const gchar *who, PurpleMediaSessionType type) -{ - GoogleSession *session; - JabberBuddy *jb; - JabberBuddyResource *jbr; - gchar *jid; - GParameter *params; - guint num_params; - - /* construct JID to send to */ - jb = jabber_buddy_find(js, who, FALSE); - if (!jb) { - purple_debug_error("jingle-rtp", - "Could not find Jabber buddy\n"); - return FALSE; - } - jbr = jabber_buddy_find_resource(jb, NULL); - if (!jbr) { - purple_debug_error("jingle-rtp", - "Could not find buddy's resource\n"); - } - - if ((strchr(who, '/') == NULL) && jbr && (jbr->name != NULL)) { - jid = g_strdup_printf("%s/%s", who, jbr->name); - } else { - jid = g_strdup(who); - } - - session = g_new0(GoogleSession, 1); - session->id.id = jabber_get_next_id(js); - session->id.initiator = g_strdup_printf("%s@%s/%s", js->user->node, - js->user->domain, js->user->resource); - session->state = SENT_INITIATE; - session->js = js; - session->remote_jid = jid; - - if (type & PURPLE_MEDIA_VIDEO) - session->video = TRUE; - - session->media = purple_media_manager_create_media( - purple_media_manager_get(), - purple_connection_get_account(js->gc), - "fsrtpconference", session->remote_jid, TRUE); - - purple_media_set_prpl_data(session->media, session); - - g_signal_connect_swapped(G_OBJECT(session->media), - "candidates-prepared", - G_CALLBACK(google_session_ready), session); - g_signal_connect_swapped(G_OBJECT(session->media), "codecs-changed", - G_CALLBACK(google_session_ready), session); - g_signal_connect(G_OBJECT(session->media), "state-changed", - G_CALLBACK(google_session_state_changed_cb), session); - g_signal_connect(G_OBJECT(session->media), "stream-info", - G_CALLBACK(google_session_stream_info_cb), session); - - params = jabber_google_session_get_params(js, &num_params); - - if (purple_media_add_stream(session->media, "google-voice", - session->remote_jid, PURPLE_MEDIA_AUDIO, - TRUE, "nice", num_params, params) == FALSE || - (session->video && purple_media_add_stream( - session->media, "google-video", - session->remote_jid, PURPLE_MEDIA_VIDEO, - TRUE, "nice", num_params, params) == FALSE)) { - purple_media_error(session->media, "Error adding stream."); - purple_media_end(session->media, NULL, NULL); - g_free(params); - return FALSE; - } - - g_free(params); - - return (session->media != NULL) ? TRUE : FALSE; -} - -static gboolean -google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id) -{ - JabberIq *result; - GList *codecs = NULL, *video_codecs = NULL; - xmlnode *desc_element, *codec_element; - PurpleMediaCodec *codec; - const char *xmlns; - GParameter *params; - guint num_params; - - if (session->state != UNINIT) { - purple_debug_error("jabber", "Received initiate for active session.\n"); - return FALSE; - } - - desc_element = xmlnode_get_child(sess, "description"); - xmlns = xmlnode_get_namespace(desc_element); - - if (purple_strequal(xmlns, NS_GOOGLE_SESSION_PHONE)) - session->video = FALSE; - else if (purple_strequal(xmlns, NS_GOOGLE_SESSION_VIDEO)) - session->video = TRUE; - else { - purple_debug_error("jabber", "Received initiate with " - "invalid namespace %s.\n", xmlns); - return FALSE; - } - - session->media = purple_media_manager_create_media( - purple_media_manager_get(), - purple_connection_get_account(js->gc), - "fsrtpconference", session->remote_jid, FALSE); - - purple_media_set_prpl_data(session->media, session); - - g_signal_connect_swapped(G_OBJECT(session->media), - "candidates-prepared", - G_CALLBACK(google_session_ready), session); - g_signal_connect_swapped(G_OBJECT(session->media), "codecs-changed", - G_CALLBACK(google_session_ready), session); - g_signal_connect(G_OBJECT(session->media), "state-changed", - G_CALLBACK(google_session_state_changed_cb), session); - g_signal_connect(G_OBJECT(session->media), "stream-info", - G_CALLBACK(google_session_stream_info_cb), session); - - params = jabber_google_session_get_params(js, &num_params); - - if (purple_media_add_stream(session->media, "google-voice", - session->remote_jid, PURPLE_MEDIA_AUDIO, FALSE, - "nice", num_params, params) == FALSE || - (session->video && purple_media_add_stream( - session->media, "google-video", - session->remote_jid, PURPLE_MEDIA_VIDEO, - FALSE, "nice", num_params, params) == FALSE)) { - purple_media_error(session->media, "Error adding stream."); - purple_media_stream_info(session->media, - PURPLE_MEDIA_INFO_REJECT, NULL, NULL, TRUE); - g_free(params); - return FALSE; - } - - g_free(params); - - for (codec_element = xmlnode_get_child(desc_element, "payload-type"); - codec_element; codec_element = codec_element->next) { - const char *id, *encoding_name, *clock_rate, - *width, *height, *framerate; - gboolean video; - if (codec_element->name && - strcmp(codec_element->name, "payload-type")) - continue; - - xmlns = xmlnode_get_namespace(codec_element); - encoding_name = xmlnode_get_attrib(codec_element, "name"); - id = xmlnode_get_attrib(codec_element, "id"); - - if (!session->video || - (xmlns && !strcmp(xmlns, NS_GOOGLE_SESSION_PHONE))) { - clock_rate = xmlnode_get_attrib( - codec_element, "clockrate"); - video = FALSE; - } else { - width = xmlnode_get_attrib(codec_element, "width"); - height = xmlnode_get_attrib(codec_element, "height"); - framerate = xmlnode_get_attrib( - codec_element, "framerate"); - clock_rate = "90000"; - video = TRUE; - } - - if (id) { - codec = purple_media_codec_new(atoi(id), encoding_name, - video ? PURPLE_MEDIA_VIDEO : - PURPLE_MEDIA_AUDIO, - clock_rate ? atoi(clock_rate) : 0); - if (video) - video_codecs = g_list_append( - video_codecs, codec); - else - codecs = g_list_append(codecs, codec); - } - } - - if (codecs) - purple_media_set_remote_codecs(session->media, "google-voice", - session->remote_jid, codecs); - if (video_codecs) - purple_media_set_remote_codecs(session->media, "google-video", - session->remote_jid, video_codecs); - - purple_media_codec_list_free(codecs); - purple_media_codec_list_free(video_codecs); - - result = jabber_iq_new(js, JABBER_IQ_RESULT); - jabber_iq_set_id(result, iq_id); - xmlnode_set_attrib(result->node, "to", session->remote_jid); - jabber_iq_send(result); - - return TRUE; -} - -static void -google_session_handle_candidates(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id) -{ - JabberIq *result; - GList *list = NULL, *video_list = NULL; - xmlnode *cand; - static int name = 0; - char n[4]; - - for (cand = xmlnode_get_child(sess, "candidate"); cand; - cand = xmlnode_get_next_twin(cand)) { - PurpleMediaCandidate *info; - const gchar *cname = xmlnode_get_attrib(cand, "name"); - const gchar *type = xmlnode_get_attrib(cand, "type"); - const gchar *protocol = xmlnode_get_attrib(cand, "protocol"); - const gchar *address = xmlnode_get_attrib(cand, "address"); - const gchar *port = xmlnode_get_attrib(cand, "port"); - guint component_id; - - if (cname && type && address && port) { - PurpleMediaCandidateType candidate_type; - - g_snprintf(n, sizeof(n), "S%d", name++); - - if (g_str_equal(type, "local")) - candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST; - else if (g_str_equal(type, "stun")) - candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX; - else if (g_str_equal(type, "relay")) - candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_RELAY; - else - candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST; - - if (purple_strequal(cname, "rtcp") || - purple_strequal(cname, "video_rtcp")) - component_id = PURPLE_MEDIA_COMPONENT_RTCP; - else - component_id = PURPLE_MEDIA_COMPONENT_RTP; - - info = purple_media_candidate_new(n, component_id, - candidate_type, - purple_strequal(protocol, "udp") ? - PURPLE_MEDIA_NETWORK_PROTOCOL_UDP : - PURPLE_MEDIA_NETWORK_PROTOCOL_TCP, - address, - atoi(port)); - g_object_set(info, "username", xmlnode_get_attrib(cand, "username"), - "password", xmlnode_get_attrib(cand, "password"), NULL); - if (!strncmp(cname, "video_", 6)) - video_list = g_list_append(video_list, info); - else - list = g_list_append(list, info); - } - } - - if (list) - purple_media_add_remote_candidates( - session->media, "google-voice", - session->remote_jid, list); - if (video_list) - purple_media_add_remote_candidates( - session->media, "google-video", - session->remote_jid, video_list); - purple_media_candidate_list_free(list); - purple_media_candidate_list_free(video_list); - - result = jabber_iq_new(js, JABBER_IQ_RESULT); - jabber_iq_set_id(result, iq_id); - xmlnode_set_attrib(result->node, "to", session->remote_jid); - jabber_iq_send(result); -} - -static void -google_session_handle_accept(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id) -{ - xmlnode *desc_element = xmlnode_get_child(sess, "description"); - xmlnode *codec_element = xmlnode_get_child( - desc_element, "payload-type"); - GList *codecs = NULL, *video_codecs = NULL; - JabberIq *result = NULL; - const gchar *xmlns = xmlnode_get_namespace(desc_element); - gboolean video = (xmlns && !strcmp(xmlns, NS_GOOGLE_SESSION_VIDEO)); - - for (; codec_element; codec_element = codec_element->next) { - const gchar *xmlns, *encoding_name, *id, - *clock_rate, *width, *height, *framerate; - gboolean video_codec = FALSE; - - if (!purple_strequal(codec_element->name, "payload-type")) - continue; - - xmlns = xmlnode_get_namespace(codec_element); - encoding_name = xmlnode_get_attrib(codec_element, "name"); - id = xmlnode_get_attrib(codec_element, "id"); - - if (!video || purple_strequal(xmlns, NS_GOOGLE_SESSION_PHONE)) - clock_rate = xmlnode_get_attrib( - codec_element, "clockrate"); - else { - clock_rate = "90000"; - width = xmlnode_get_attrib(codec_element, "width"); - height = xmlnode_get_attrib(codec_element, "height"); - framerate = xmlnode_get_attrib( - codec_element, "framerate"); - video_codec = TRUE; - } - - if (id && encoding_name) { - PurpleMediaCodec *codec = purple_media_codec_new( - atoi(id), encoding_name, - video_codec ? PURPLE_MEDIA_VIDEO : - PURPLE_MEDIA_AUDIO, - clock_rate ? atoi(clock_rate) : 0); - if (video_codec) - video_codecs = g_list_append( - video_codecs, codec); - else - codecs = g_list_append(codecs, codec); - } - } - - if (codecs) - purple_media_set_remote_codecs(session->media, "google-voice", - session->remote_jid, codecs); - if (video_codecs) - purple_media_set_remote_codecs(session->media, "google-video", - session->remote_jid, video_codecs); - - purple_media_stream_info(session->media, PURPLE_MEDIA_INFO_ACCEPT, - NULL, NULL, FALSE); - - result = jabber_iq_new(js, JABBER_IQ_RESULT); - jabber_iq_set_id(result, iq_id); - xmlnode_set_attrib(result->node, "to", session->remote_jid); - jabber_iq_send(result); -} - -static void -google_session_handle_reject(JabberStream *js, GoogleSession *session, xmlnode *sess) -{ - purple_media_end(session->media, NULL, NULL); -} - -static void -google_session_handle_terminate(JabberStream *js, GoogleSession *session, xmlnode *sess) -{ - purple_media_end(session->media, NULL, NULL); -} - -static void -google_session_parse_iq(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id) -{ - const char *type = xmlnode_get_attrib(sess, "type"); - - if (!strcmp(type, "initiate")) { - google_session_handle_initiate(js, session, sess, iq_id); - } else if (!strcmp(type, "accept")) { - google_session_handle_accept(js, session, sess, iq_id); - } else if (!strcmp(type, "reject")) { - google_session_handle_reject(js, session, sess); - } else if (!strcmp(type, "terminate")) { - google_session_handle_terminate(js, session, sess); - } else if (!strcmp(type, "candidates")) { - google_session_handle_candidates(js, session, sess, iq_id); - } -} - -void -jabber_google_session_parse(JabberStream *js, const char *from, - JabberIqType type, const char *iq_id, - xmlnode *session_node) -{ - GoogleSession *session = NULL; - GoogleSessionId id; - - xmlnode *desc_node; - - GList *iter = NULL; - - if (type != JABBER_IQ_SET) - return; - - id.id = (gchar*)xmlnode_get_attrib(session_node, "id"); - if (!id.id) - return; - - id.initiator = (gchar*)xmlnode_get_attrib(session_node, "initiator"); - if (!id.initiator) - return; - - iter = purple_media_manager_get_media_by_account( - purple_media_manager_get(), - purple_connection_get_account(js->gc)); - for (; iter; iter = g_list_delete_link(iter, iter)) { - GoogleSession *gsession = - purple_media_get_prpl_data(iter->data); - if (google_session_id_equal(&(gsession->id), &id)) { - session = gsession; - break; - } - } - if (iter != NULL) { - g_list_free(iter); - } - - if (session) { - google_session_parse_iq(js, session, session_node, iq_id); - return; - } - - /* If the session doesn't exist, this has to be an initiate message */ - if (strcmp(xmlnode_get_attrib(session_node, "type"), "initiate")) - return; - desc_node = xmlnode_get_child(session_node, "description"); - if (!desc_node) - return; - session = g_new0(GoogleSession, 1); - session->id.id = g_strdup(id.id); - session->id.initiator = g_strdup(id.initiator); - session->state = UNINIT; - session->js = js; - session->remote_jid = g_strdup(session->id.initiator); - - google_session_handle_initiate(js, session, session_node, iq_id); -} -#endif /* USE_VV */ - -static void -jabber_gmail_parse(JabberStream *js, const char *from, - JabberIqType type, const char *id, - xmlnode *packet, gpointer nul) -{ - xmlnode *child; - xmlnode *message; - const char *to, *url; - const char *in_str; - char *to_name; - - int i, count = 1, returned_count; - - const char **tos, **froms, **urls; - char **subjects; - - if (type == JABBER_IQ_ERROR) - return; - - child = xmlnode_get_child(packet, "mailbox"); - if (!child) - return; - - in_str = xmlnode_get_attrib(child, "total-matched"); - if (in_str && *in_str) - count = atoi(in_str); - - /* If Gmail doesn't tell us who the mail is to, let's use our JID */ - to = xmlnode_get_attrib(packet, "to"); - - message = xmlnode_get_child(child, "mail-thread-info"); - - if (count == 0 || !message) { - if (count > 0) { - char *bare_jid = jabber_get_bare_jid(to); - const char *default_tos[2] = { bare_jid }; - - purple_notify_emails(js->gc, count, FALSE, NULL, NULL, default_tos, NULL, NULL, NULL); - g_free(bare_jid); - } else { - purple_notify_emails(js->gc, count, FALSE, NULL, NULL, NULL, NULL, NULL, NULL); - } - - return; - } - - /* Loop once to see how many messages were returned so we can allocate arrays - * accordingly */ - for (returned_count = 0; message; returned_count++, message=xmlnode_get_next_twin(message)); - - froms = g_new0(const char* , returned_count + 1); - tos = g_new0(const char* , returned_count + 1); - subjects = g_new0(char* , returned_count + 1); - urls = g_new0(const char* , returned_count + 1); - - to = xmlnode_get_attrib(packet, "to"); - to_name = jabber_get_bare_jid(to); - url = xmlnode_get_attrib(child, "url"); - if (!url || !*url) - url = "http://www.gmail.com"; - - message= xmlnode_get_child(child, "mail-thread-info"); - for (i=0; message; message = xmlnode_get_next_twin(message), i++) { - xmlnode *sender_node, *subject_node; - const char *from, *tid; - char *subject; - - subject_node = xmlnode_get_child(message, "subject"); - sender_node = xmlnode_get_child(message, "senders"); - sender_node = xmlnode_get_child(sender_node, "sender"); - - while (sender_node && (!xmlnode_get_attrib(sender_node, "unread") || - !strcmp(xmlnode_get_attrib(sender_node, "unread"),"0"))) - sender_node = xmlnode_get_next_twin(sender_node); - - if (!sender_node) { - i--; - continue; - } - - from = xmlnode_get_attrib(sender_node, "name"); - if (!from || !*from) - from = xmlnode_get_attrib(sender_node, "address"); - subject = xmlnode_get_data(subject_node); - /* - * url = xmlnode_get_attrib(message, "url"); - */ - tos[i] = (to_name != NULL ? to_name : ""); - froms[i] = (from != NULL ? from : ""); - subjects[i] = (subject != NULL ? subject : g_strdup("")); - urls[i] = url; - - tid = xmlnode_get_attrib(message, "tid"); - if (tid && - (js->gmail_last_tid == NULL || strcmp(tid, js->gmail_last_tid) > 0)) { - g_free(js->gmail_last_tid); - js->gmail_last_tid = g_strdup(tid); - } - } - - if (i>0) - purple_notify_emails(js->gc, count, count == i, (const char**) subjects, froms, tos, - urls, NULL, NULL); - - g_free(to_name); - g_free(tos); - g_free(froms); - for (i = 0; i < returned_count; i++) - g_free(subjects[i]); - g_free(subjects); - g_free(urls); - - in_str = xmlnode_get_attrib(child, "result-time"); - if (in_str && *in_str) { - g_free(js->gmail_last_time); - js->gmail_last_time = g_strdup(in_str); - } -} - -void -jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type, - const char *id, xmlnode *new_mail) -{ - xmlnode *query; - JabberIq *iq; - - /* bail if the user isn't interested */ - if (!purple_account_get_check_mail(js->gc->account)) - return; - - /* Is this an initial incoming mail notification? If so, send a request for more info */ - if (type != JABBER_IQ_SET) - return; - - /* Acknowledge the notification */ - iq = jabber_iq_new(js, JABBER_IQ_RESULT); - if (from) - xmlnode_set_attrib(iq->node, "to", from); - xmlnode_set_attrib(iq->node, "id", id); - jabber_iq_send(iq); - - purple_debug_misc("jabber", - "Got new mail notification. Sending request for more info\n"); - - iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_MAIL_NOTIFY); - jabber_iq_set_callback(iq, jabber_gmail_parse, NULL); - query = xmlnode_get_child(iq->node, "query"); - - if (js->gmail_last_time) - xmlnode_set_attrib(query, "newer-than-time", js->gmail_last_time); - if (js->gmail_last_tid) - xmlnode_set_attrib(query, "newer-than-tid", js->gmail_last_tid); - - jabber_iq_send(iq); - return; -} - -void jabber_gmail_init(JabberStream *js) { - JabberIq *iq; - xmlnode *usersetting, *mailnotifications; - - if (!purple_account_get_check_mail(purple_connection_get_account(js->gc))) - return; - - /* - * Quoting http://code.google.com/apis/talk/jep_extensions/usersettings.html: - * To ensure better compatibility with other clients, rather than - * setting this value to "false" to turn off notifications, it is - * recommended that a client set this to "true" and filter incoming - * email notifications itself. - */ - iq = jabber_iq_new(js, JABBER_IQ_SET); - usersetting = xmlnode_new_child(iq->node, "usersetting"); - xmlnode_set_namespace(usersetting, "google:setting"); - mailnotifications = xmlnode_new_child(usersetting, "mailnotifications"); - xmlnode_set_attrib(mailnotifications, "value", "true"); - jabber_iq_send(iq); - - iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_MAIL_NOTIFY); - jabber_iq_set_callback(iq, jabber_gmail_parse, NULL); - jabber_iq_send(iq); -} - -void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item) -{ - PurpleAccount *account = purple_connection_get_account(js->gc); - GSList *list = account->deny; - const char *jid = xmlnode_get_attrib(item, "jid"); - char *jid_norm = (char *)jabber_normalize(account, jid); - - while (list) { - if (!strcmp(jid_norm, (char*)list->data)) { - xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER); - xmlnode_set_attrib(query, "gr:ext", "2"); - xmlnode_set_attrib(item, "gr:t", "B"); - return; - } - list = list->next; - } -} - -gboolean jabber_google_roster_incoming(JabberStream *js, xmlnode *item) -{ - PurpleAccount *account = purple_connection_get_account(js->gc); - const char *jid = xmlnode_get_attrib(item, "jid"); - gboolean on_block_list = FALSE; - - char *jid_norm; - - const char *grt = xmlnode_get_attrib_with_namespace(item, "t", NS_GOOGLE_ROSTER); - const char *subscription = xmlnode_get_attrib(item, "subscription"); - const char *ask = xmlnode_get_attrib(item, "ask"); - - if ((!subscription || !strcmp(subscription, "none")) && !ask) { - /* The Google Talk servers will automatically add people from your Gmail address book - * with subscription=none. If we see someone with subscription=none, ignore them. - */ - return FALSE; - } - - jid_norm = g_strdup(jabber_normalize(account, jid)); - - on_block_list = NULL != g_slist_find_custom(account->deny, jid_norm, - (GCompareFunc)strcmp); - - if (grt && (*grt == 'H' || *grt == 'h')) { - /* Hidden; don't show this buddy. */ - GSList *buddies = purple_find_buddies(account, jid_norm); - if (buddies) - purple_debug_info("jabber", "Removing %s from local buddy list\n", - jid_norm); - - for ( ; buddies; buddies = g_slist_delete_link(buddies, buddies)) { - purple_blist_remove_buddy(buddies->data); - } - - g_free(jid_norm); - return FALSE; - } - - if (!on_block_list && (grt && (*grt == 'B' || *grt == 'b'))) { - purple_debug_info("jabber", "Blocking %s\n", jid_norm); - purple_privacy_deny_add(account, jid_norm, TRUE); - } else if (on_block_list && (!grt || (*grt != 'B' && *grt != 'b' ))){ - purple_debug_info("jabber", "Unblocking %s\n", jid_norm); - purple_privacy_deny_remove(account, jid_norm, TRUE); - } - - g_free(jid_norm); - return TRUE; -} - -void jabber_google_roster_add_deny(JabberStream *js, const char *who) -{ - PurpleAccount *account; - GSList *buddies; - JabberIq *iq; - xmlnode *query; - xmlnode *item; - xmlnode *group; - PurpleBuddy *b; - JabberBuddy *jb; - const char *balias; - - jb = jabber_buddy_find(js, who, TRUE); - - account = purple_connection_get_account(js->gc); - buddies = purple_find_buddies(account, who); - if(!buddies) - return; - - b = buddies->data; - - iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster"); - - query = xmlnode_get_child(iq->node, "query"); - item = xmlnode_new_child(query, "item"); - - while(buddies) { - PurpleGroup *g; - - b = buddies->data; - g = purple_buddy_get_group(b); - - group = xmlnode_new_child(item, "group"); - xmlnode_insert_data(group, purple_group_get_name(g), -1); - - buddies = buddies->next; - } - - balias = purple_buddy_get_local_buddy_alias(b); - xmlnode_set_attrib(item, "jid", who); - xmlnode_set_attrib(item, "name", balias ? balias : ""); - xmlnode_set_attrib(item, "gr:t", "B"); - xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER); - xmlnode_set_attrib(query, "gr:ext", "2"); - - jabber_iq_send(iq); - - /* Synthesize a sign-off */ - if (jb) { - JabberBuddyResource *jbr; - GList *l = jb->resources; - while (l) { - jbr = l->data; - if (jbr && jbr->name) - { - purple_debug_misc("jabber", "Removing resource %s\n", jbr->name); - jabber_buddy_remove_resource(jb, jbr->name); - } - l = l->next; - } - } - - purple_prpl_got_user_status(account, who, "offline", NULL); -} - -void jabber_google_roster_rem_deny(JabberStream *js, const char *who) -{ - GSList *buddies; - JabberIq *iq; - xmlnode *query; - xmlnode *item; - xmlnode *group; - PurpleBuddy *b; - const char *balias; - - buddies = purple_find_buddies(purple_connection_get_account(js->gc), who); - if(!buddies) - return; - - b = buddies->data; - - iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster"); - - query = xmlnode_get_child(iq->node, "query"); - item = xmlnode_new_child(query, "item"); - - while(buddies) { - PurpleGroup *g; - - b = buddies->data; - g = purple_buddy_get_group(b); - - group = xmlnode_new_child(item, "group"); - xmlnode_insert_data(group, purple_group_get_name(g), -1); - - buddies = buddies->next; - } - - balias = purple_buddy_get_local_buddy_alias(b); - xmlnode_set_attrib(item, "jid", who); - xmlnode_set_attrib(item, "name", balias ? balias : ""); - xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER); - xmlnode_set_attrib(query, "gr:ext", "2"); - - jabber_iq_send(iq); - - /* See if he's online */ - jabber_presence_subscription_set(js, who, "probe"); -} - -/* This does two passes on the string. The first pass goes through - * and determine if all the structured text is properly balanced, and - * how many instances of each there is. The second pass goes and converts - * everything to HTML, depending on what's figured out by the first pass. - * It will short circuit once it knows it has no more replacements to make - */ -char *jabber_google_format_to_html(const char *text) -{ - const char *p; - - /* The start of the screen may be consdiered a space for this purpose */ - gboolean preceding_space = TRUE; - - gboolean in_bold = FALSE, in_italic = FALSE; - gboolean in_tag = FALSE; - - gint bold_count = 0, italic_count = 0; - - GString *str; - - for (p = text; *p != '\0'; p = g_utf8_next_char(p)) { - gunichar c = g_utf8_get_char(p); - if (c == '*' && !in_tag) { - if (in_bold && (g_unichar_isspace(*(p+1)) || - *(p+1) == '\0' || - *(p+1) == '<')) { - bold_count++; - in_bold = FALSE; - } else if (preceding_space && !in_bold && !g_unichar_isspace(*(p+1))) { - bold_count++; - in_bold = TRUE; - } - preceding_space = TRUE; - } else if (c == '_' && !in_tag) { - if (in_italic && (g_unichar_isspace(*(p+1)) || - *(p+1) == '\0' || - *(p+1) == '<')) { - italic_count++; - in_italic = FALSE; - } else if (preceding_space && !in_italic && !g_unichar_isspace(*(p+1))) { - italic_count++; - in_italic = TRUE; - } - preceding_space = TRUE; - } else if (c == '<' && !in_tag) { - in_tag = TRUE; - } else if (c == '>' && in_tag) { - in_tag = FALSE; - } else if (!in_tag) { - if (g_unichar_isspace(c)) - preceding_space = TRUE; - else - preceding_space = FALSE; - } - } - - str = g_string_new(NULL); - in_bold = in_italic = in_tag = FALSE; - preceding_space = TRUE; - - for (p = text; *p != '\0'; p = g_utf8_next_char(p)) { - gunichar c = g_utf8_get_char(p); - - if (bold_count < 2 && italic_count < 2 && !in_bold && !in_italic) { - g_string_append(str, p); - return g_string_free(str, FALSE); - } - - - if (c == '*' && !in_tag) { - if (in_bold && - (g_unichar_isspace(*(p+1))||*(p+1)=='<')) { /* This is safe in UTF-8 */ - str = g_string_append(str, "</b>"); - in_bold = FALSE; - bold_count--; - } else if (preceding_space && bold_count > 1 && !g_unichar_isspace(*(p+1))) { - str = g_string_append(str, "<b>"); - bold_count--; - in_bold = TRUE; - } else { - str = g_string_append_unichar(str, c); - } - preceding_space = TRUE; - } else if (c == '_' && !in_tag) { - if (in_italic && - (g_unichar_isspace(*(p+1))||*(p+1)=='<')) { - str = g_string_append(str, "</i>"); - italic_count--; - in_italic = FALSE; - } else if (preceding_space && italic_count > 1 && !g_unichar_isspace(*(p+1))) { - str = g_string_append(str, "<i>"); - italic_count--; - in_italic = TRUE; - } else { - str = g_string_append_unichar(str, c); - } - preceding_space = TRUE; - } else if (c == '<' && !in_tag) { - str = g_string_append_unichar(str, c); - in_tag = TRUE; - } else if (c == '>' && in_tag) { - str = g_string_append_unichar(str, c); - in_tag = FALSE; - } else if (!in_tag) { - str = g_string_append_unichar(str, c); - if (g_unichar_isspace(c)) - preceding_space = TRUE; - else - preceding_space = FALSE; - } else { - str = g_string_append_unichar(str, c); - } - } - return g_string_free(str, FALSE); -} - -void jabber_google_presence_incoming(JabberStream *js, const char *user, JabberBuddyResource *jbr) -{ - if (!js->googletalk) - return; - if (jbr->status && purple_str_has_prefix(jbr->status, "♫ ")) { - gchar *unescaped; - unescaped = purple_unescape_html(jbr->status + strlen("♫ ")); - purple_prpl_got_user_status(js->gc->account, user, "tune", - PURPLE_TUNE_TITLE, unescaped, NULL); - g_free(unescaped); - g_free(jbr->status); - jbr->status = NULL; - } else { - purple_prpl_got_user_status_deactive(js->gc->account, user, "tune"); - } -} - -char *jabber_google_presence_outgoing(PurpleStatus *tune) -{ - const char *attr = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE); - return attr ? g_strdup_printf("♫ %s", attr) : g_strdup(""); -} - -static void -jabber_google_stun_lookup_cb(GSList *hosts, gpointer data, - const char *error_message) -{ - JabberStream *js = (JabberStream *) data; - - if (error_message) { - purple_debug_error("jabber", "Google STUN lookup failed: %s\n", - error_message); - g_slist_free(hosts); - js->stun_query = NULL; - return; - } - - if (hosts && g_slist_next(hosts)) { - struct sockaddr *addr = g_slist_next(hosts)->data; - char dst[INET6_ADDRSTRLEN]; - int port; - - if (addr->sa_family == AF_INET6) { - inet_ntop(addr->sa_family, &((struct sockaddr_in6 *) addr)->sin6_addr, - dst, sizeof(dst)); - port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port); - } else { - inet_ntop(addr->sa_family, &((struct sockaddr_in *) addr)->sin_addr, - dst, sizeof(dst)); - port = ntohs(((struct sockaddr_in *) addr)->sin_port); - } - - if (js->stun_ip) - g_free(js->stun_ip); - js->stun_ip = g_strdup(dst); - js->stun_port = port; - - purple_debug_info("jabber", "set Google STUN IP/port address: " - "%s:%d\n", dst, port); - - /* unmark ongoing query */ - js->stun_query = NULL; - } - - while (hosts != NULL) { - hosts = g_slist_delete_link(hosts, hosts); - /* Free the address */ - g_free(hosts->data); - hosts = g_slist_delete_link(hosts, hosts); - } -} - -static void -jabber_google_jingle_info_common(JabberStream *js, const char *from, - JabberIqType type, xmlnode *query) -{ - const xmlnode *stun = xmlnode_get_child(query, "stun"); - gchar *my_bare_jid; - - /* - * Make sure that random people aren't sending us STUN servers. Per - * http://code.google.com/apis/talk/jep_extensions/jingleinfo.html, these - * stanzas are stamped from our bare JID. - */ - if (from) { - my_bare_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain); - if (!purple_strequal(from, my_bare_jid)) { - purple_debug_warning("jabber", "got google:jingleinfo with invalid from (%s)\n", - from); - g_free(my_bare_jid); - return; - } - - g_free(my_bare_jid); - } - - if (type == JABBER_IQ_ERROR || type == JABBER_IQ_GET) - return; - - purple_debug_info("jabber", "got google:jingleinfo\n"); - - if (stun) { - xmlnode *server = xmlnode_get_child(stun, "server"); - - if (server) { - const gchar *host = xmlnode_get_attrib(server, "host"); - const gchar *udp = xmlnode_get_attrib(server, "udp"); - - if (host && udp) { - int port = atoi(udp); - /* if there, would already be an ongoing query, - cancel it */ - if (js->stun_query) - purple_dnsquery_destroy(js->stun_query); - - js->stun_query = purple_dnsquery_a(host, port, - jabber_google_stun_lookup_cb, js); - } - } - } - /* should perhaps handle relays later on, or maybe wait until - Google supports a common standard... */ -} - -static void -jabber_google_jingle_info_cb(JabberStream *js, const char *from, - JabberIqType type, const char *id, - xmlnode *packet, gpointer data) -{ - xmlnode *query = xmlnode_get_child_with_namespace(packet, "query", - NS_GOOGLE_JINGLE_INFO); - - if (query) - jabber_google_jingle_info_common(js, from, type, query); - else - purple_debug_warning("jabber", "Got invalid google:jingleinfo\n"); -} - -void -jabber_google_handle_jingle_info(JabberStream *js, const char *from, - JabberIqType type, const char *id, - xmlnode *child) -{ - jabber_google_jingle_info_common(js, from, type, child); -} - -void -jabber_google_send_jingle_info(JabberStream *js) -{ - JabberIq *jingle_info = - jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_JINGLE_INFO); - - jabber_iq_set_callback(jingle_info, jabber_google_jingle_info_cb, - NULL); - purple_debug_info("jabber", "sending google:jingleinfo query\n"); - jabber_iq_send(jingle_info); -} - -void google_buddy_node_chat(PurpleBlistNode *node, gpointer data) -{ - PurpleBuddy *buddy; - PurpleConnection *gc; - JabberStream *js; - JabberChat *chat; - gchar *room; - gchar *uuid = purple_uuid_random(); - - g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); - - buddy = PURPLE_BUDDY(node); - gc = purple_account_get_connection(purple_buddy_get_account(buddy)); - g_return_if_fail(gc != NULL); - js = purple_connection_get_protocol_data(gc); - - room = g_strdup_printf("private-chat-%s", uuid); - chat = jabber_join_chat(js, room, GOOGLE_GROUPCHAT_SERVER, js->user->node, - NULL, NULL); - if (chat) { - chat->muc = TRUE; - jabber_chat_invite(gc, chat->id, "", purple_buddy_get_name(buddy)); - } - - g_free(room); - g_free(uuid); -}
--- a/libpurple/protocols/jabber/google.h Tue Aug 17 17:23:13 2010 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/** - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef PURPLE_JABBER_GOOGLE_H_ -#define PURPLE_JABBER_GOOGLE_H_ - -/* This is a place for Google Talk-specific XMPP extensions to live - * such that they don't intermingle with code for the XMPP RFCs and XEPs :) */ - -#include "jabber.h" - -#define GOOGLE_GROUPCHAT_SERVER "groupchat.google.com" - -void jabber_gmail_init(JabberStream *js); -void jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type, - const char *id, xmlnode *new_mail); - -void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item); - -/* Returns FALSE if this should short-circuit processing of this roster item, or TRUE - * if this roster item should continue to be processed - */ -gboolean jabber_google_roster_incoming(JabberStream *js, xmlnode *item); - -void jabber_google_presence_incoming(JabberStream *js, const char *who, JabberBuddyResource *jbr); -char *jabber_google_presence_outgoing(PurpleStatus *tune); - -void jabber_google_roster_add_deny(JabberStream *js, const char *who); -void jabber_google_roster_rem_deny(JabberStream *js, const char *who); - -char *jabber_google_format_to_html(const char *text); - -gboolean jabber_google_session_initiate(JabberStream *js, const gchar *who, PurpleMediaSessionType type); -void jabber_google_session_parse(JabberStream *js, const char *from, JabberIqType type, const char *iq, xmlnode *session); - -void jabber_google_handle_jingle_info(JabberStream *js, const char *from, - JabberIqType type, const char *id, - xmlnode *child); -void jabber_google_send_jingle_info(JabberStream *js); - -void google_buddy_node_chat(PurpleBlistNode *node, gpointer data); - -#endif /* PURPLE_JABBER_GOOGLE_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/google/gmail.c Wed Sep 22 14:17:09 2010 +0900 @@ -0,0 +1,207 @@ +/** + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "internal.h" +#include "debug.h" +#include "jabber.h" +#include "gmail.h" + +static void +jabber_gmail_parse(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer nul) +{ + xmlnode *child; + xmlnode *message; + const char *to, *url; + const char *in_str; + char *to_name; + + int i, count = 1, returned_count; + + const char **tos, **froms, **urls; + char **subjects; + + if (type == JABBER_IQ_ERROR) + return; + + child = xmlnode_get_child(packet, "mailbox"); + if (!child) + return; + + in_str = xmlnode_get_attrib(child, "total-matched"); + if (in_str && *in_str) + count = atoi(in_str); + + /* If Gmail doesn't tell us who the mail is to, let's use our JID */ + to = xmlnode_get_attrib(packet, "to"); + + message = xmlnode_get_child(child, "mail-thread-info"); + + if (count == 0 || !message) { + if (count > 0) { + char *bare_jid = jabber_get_bare_jid(to); + const char *default_tos[2] = { bare_jid }; + + purple_notify_emails(js->gc, count, FALSE, NULL, NULL, default_tos, NULL, NULL, NULL); + g_free(bare_jid); + } else { + purple_notify_emails(js->gc, count, FALSE, NULL, NULL, NULL, NULL, NULL, NULL); + } + + return; + } + + /* Loop once to see how many messages were returned so we can allocate arrays + * accordingly */ + for (returned_count = 0; message; returned_count++, message=xmlnode_get_next_twin(message)); + + froms = g_new0(const char* , returned_count + 1); + tos = g_new0(const char* , returned_count + 1); + subjects = g_new0(char* , returned_count + 1); + urls = g_new0(const char* , returned_count + 1); + + to = xmlnode_get_attrib(packet, "to"); + to_name = jabber_get_bare_jid(to); + url = xmlnode_get_attrib(child, "url"); + if (!url || !*url) + url = "http://www.gmail.com"; + + message= xmlnode_get_child(child, "mail-thread-info"); + for (i=0; message; message = xmlnode_get_next_twin(message), i++) { + xmlnode *sender_node, *subject_node; + const char *from, *tid; + char *subject; + + subject_node = xmlnode_get_child(message, "subject"); + sender_node = xmlnode_get_child(message, "senders"); + sender_node = xmlnode_get_child(sender_node, "sender"); + + while (sender_node && (!xmlnode_get_attrib(sender_node, "unread") || + !strcmp(xmlnode_get_attrib(sender_node, "unread"),"0"))) + sender_node = xmlnode_get_next_twin(sender_node); + + if (!sender_node) { + i--; + continue; + } + + from = xmlnode_get_attrib(sender_node, "name"); + if (!from || !*from) + from = xmlnode_get_attrib(sender_node, "address"); + subject = xmlnode_get_data(subject_node); + /* + * url = xmlnode_get_attrib(message, "url"); + */ + tos[i] = (to_name != NULL ? to_name : ""); + froms[i] = (from != NULL ? from : ""); + subjects[i] = (subject != NULL ? subject : g_strdup("")); + urls[i] = url; + + tid = xmlnode_get_attrib(message, "tid"); + if (tid && + (js->gmail_last_tid == NULL || strcmp(tid, js->gmail_last_tid) > 0)) { + g_free(js->gmail_last_tid); + js->gmail_last_tid = g_strdup(tid); + } + } + + if (i>0) + purple_notify_emails(js->gc, count, count == i, (const char**) subjects, froms, tos, + urls, NULL, NULL); + + g_free(to_name); + g_free(tos); + g_free(froms); + for (i = 0; i < returned_count; i++) + g_free(subjects[i]); + g_free(subjects); + g_free(urls); + + in_str = xmlnode_get_attrib(child, "result-time"); + if (in_str && *in_str) { + g_free(js->gmail_last_time); + js->gmail_last_time = g_strdup(in_str); + } +} + +void +jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type, + const char *id, xmlnode *new_mail) +{ + xmlnode *query; + JabberIq *iq; + + /* bail if the user isn't interested */ + if (!purple_account_get_check_mail(js->gc->account)) + return; + + /* Is this an initial incoming mail notification? If so, send a request for more info */ + if (type != JABBER_IQ_SET) + return; + + /* Acknowledge the notification */ + iq = jabber_iq_new(js, JABBER_IQ_RESULT); + if (from) + xmlnode_set_attrib(iq->node, "to", from); + xmlnode_set_attrib(iq->node, "id", id); + jabber_iq_send(iq); + + purple_debug_misc("jabber", + "Got new mail notification. Sending request for more info\n"); + + iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_MAIL_NOTIFY); + jabber_iq_set_callback(iq, jabber_gmail_parse, NULL); + query = xmlnode_get_child(iq->node, "query"); + + if (js->gmail_last_time) + xmlnode_set_attrib(query, "newer-than-time", js->gmail_last_time); + if (js->gmail_last_tid) + xmlnode_set_attrib(query, "newer-than-tid", js->gmail_last_tid); + + jabber_iq_send(iq); + return; +} + +void jabber_gmail_init(JabberStream *js) { + JabberIq *iq; + xmlnode *usersetting, *mailnotifications; + + if (!purple_account_get_check_mail(purple_connection_get_account(js->gc))) + return; + + /* + * Quoting http://code.google.com/apis/talk/jep_extensions/usersettings.html: + * To ensure better compatibility with other clients, rather than + * setting this value to "false" to turn off notifications, it is + * recommended that a client set this to "true" and filter incoming + * email notifications itself. + */ + iq = jabber_iq_new(js, JABBER_IQ_SET); + usersetting = xmlnode_new_child(iq->node, "usersetting"); + xmlnode_set_namespace(usersetting, "google:setting"); + mailnotifications = xmlnode_new_child(usersetting, "mailnotifications"); + xmlnode_set_attrib(mailnotifications, "value", "true"); + jabber_iq_send(iq); + + iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_MAIL_NOTIFY); + jabber_iq_set_callback(iq, jabber_gmail_parse, NULL); + jabber_iq_send(iq); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/google/gmail.h Wed Sep 22 14:17:09 2010 +0900 @@ -0,0 +1,30 @@ +/** + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#ifndef PURPLE_JABBER_GOOGLE_GMAIL_H_ +#define PURPLE_JABBER_GOOGLE_GMAIL_H_ + +#include "jabber.h" + +void jabber_gmail_init(JabberStream *js); +void jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type, + const char *id, xmlnode *new_mail); + +#endif /* PURPLE_JABBER_GOOGLE_GMAIL_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/google/google.c Wed Sep 22 14:17:09 2010 +0900 @@ -0,0 +1,172 @@ +/** + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "internal.h" +#include "debug.h" + +#include "google.h" +#include "jabber.h" +#include "chat.h" + +/* This does two passes on the string. The first pass goes through + * and determine if all the structured text is properly balanced, and + * how many instances of each there is. The second pass goes and converts + * everything to HTML, depending on what's figured out by the first pass. + * It will short circuit once it knows it has no more replacements to make + */ +char *jabber_google_format_to_html(const char *text) +{ + const char *p; + + /* The start of the screen may be consdiered a space for this purpose */ + gboolean preceding_space = TRUE; + + gboolean in_bold = FALSE, in_italic = FALSE; + gboolean in_tag = FALSE; + + gint bold_count = 0, italic_count = 0; + + GString *str; + + for (p = text; *p != '\0'; p = g_utf8_next_char(p)) { + gunichar c = g_utf8_get_char(p); + if (c == '*' && !in_tag) { + if (in_bold && (g_unichar_isspace(*(p+1)) || + *(p+1) == '\0' || + *(p+1) == '<')) { + bold_count++; + in_bold = FALSE; + } else if (preceding_space && !in_bold && !g_unichar_isspace(*(p+1))) { + bold_count++; + in_bold = TRUE; + } + preceding_space = TRUE; + } else if (c == '_' && !in_tag) { + if (in_italic && (g_unichar_isspace(*(p+1)) || + *(p+1) == '\0' || + *(p+1) == '<')) { + italic_count++; + in_italic = FALSE; + } else if (preceding_space && !in_italic && !g_unichar_isspace(*(p+1))) { + italic_count++; + in_italic = TRUE; + } + preceding_space = TRUE; + } else if (c == '<' && !in_tag) { + in_tag = TRUE; + } else if (c == '>' && in_tag) { + in_tag = FALSE; + } else if (!in_tag) { + if (g_unichar_isspace(c)) + preceding_space = TRUE; + else + preceding_space = FALSE; + } + } + + str = g_string_new(NULL); + in_bold = in_italic = in_tag = FALSE; + preceding_space = TRUE; + + for (p = text; *p != '\0'; p = g_utf8_next_char(p)) { + gunichar c = g_utf8_get_char(p); + + if (bold_count < 2 && italic_count < 2 && !in_bold && !in_italic) { + g_string_append(str, p); + return g_string_free(str, FALSE); + } + + + if (c == '*' && !in_tag) { + if (in_bold && + (g_unichar_isspace(*(p+1))||*(p+1)=='<')) { /* This is safe in UTF-8 */ + str = g_string_append(str, "</b>"); + in_bold = FALSE; + bold_count--; + } else if (preceding_space && bold_count > 1 && !g_unichar_isspace(*(p+1))) { + str = g_string_append(str, "<b>"); + bold_count--; + in_bold = TRUE; + } else { + str = g_string_append_unichar(str, c); + } + preceding_space = TRUE; + } else if (c == '_' && !in_tag) { + if (in_italic && + (g_unichar_isspace(*(p+1))||*(p+1)=='<')) { + str = g_string_append(str, "</i>"); + italic_count--; + in_italic = FALSE; + } else if (preceding_space && italic_count > 1 && !g_unichar_isspace(*(p+1))) { + str = g_string_append(str, "<i>"); + italic_count--; + in_italic = TRUE; + } else { + str = g_string_append_unichar(str, c); + } + preceding_space = TRUE; + } else if (c == '<' && !in_tag) { + str = g_string_append_unichar(str, c); + in_tag = TRUE; + } else if (c == '>' && in_tag) { + str = g_string_append_unichar(str, c); + in_tag = FALSE; + } else if (!in_tag) { + str = g_string_append_unichar(str, c); + if (g_unichar_isspace(c)) + preceding_space = TRUE; + else + preceding_space = FALSE; + } else { + str = g_string_append_unichar(str, c); + } + } + return g_string_free(str, FALSE); +} + + + +void google_buddy_node_chat(PurpleBlistNode *node, gpointer data) +{ + PurpleBuddy *buddy; + PurpleConnection *gc; + JabberStream *js; + JabberChat *chat; + gchar *room; + gchar *uuid = purple_uuid_random(); + + g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); + + buddy = PURPLE_BUDDY(node); + gc = purple_account_get_connection(purple_buddy_get_account(buddy)); + g_return_if_fail(gc != NULL); + js = purple_connection_get_protocol_data(gc); + + room = g_strdup_printf("private-chat-%s", uuid); + chat = jabber_join_chat(js, room, GOOGLE_GROUPCHAT_SERVER, js->user->node, + NULL, NULL); + if (chat) { + chat->muc = TRUE; + jabber_chat_invite(gc, chat->id, "", purple_buddy_get_name(buddy)); + } + + g_free(room); + g_free(uuid); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/google/google.h Wed Sep 22 14:17:09 2010 +0900 @@ -0,0 +1,35 @@ +/** + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#ifndef PURPLE_JABBER_GOOGLE_H_ +#define PURPLE_JABBER_GOOGLE_H_ + +/* This is a place for Google Talk-specific XMPP extensions to live + * such that they don't intermingle with code for the XMPP RFCs and XEPs :) */ + +#include "jabber.h" + +#define GOOGLE_GROUPCHAT_SERVER "groupchat.google.com" + +char *jabber_google_format_to_html(const char *text); + +void google_buddy_node_chat(PurpleBlistNode *node, gpointer data); + +#endif /* PURPLE_JABBER_GOOGLE_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/google/google_presence.c Wed Sep 22 14:17:09 2010 +0900 @@ -0,0 +1,43 @@ +/** + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "internal.h" +#include "debug.h" +#include "google_presence.h" + +void jabber_google_presence_incoming(JabberStream *js, const char *user, JabberBuddyResource *jbr) +{ + if (!js->googletalk) + return; + if (jbr->status && purple_str_has_prefix(jbr->status, "♫ ")) { + purple_prpl_got_user_status(js->gc->account, user, "tune", + PURPLE_TUNE_TITLE, jbr->status + strlen("♫ "), NULL); + g_free(jbr->status); + jbr->status = NULL; + } else { + purple_prpl_got_user_status_deactive(js->gc->account, user, "tune"); + } +} + +char *jabber_google_presence_outgoing(PurpleStatus *tune) +{ + const char *attr = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE); + return attr ? g_strdup_printf("♫ %s", attr) : g_strdup(""); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/google/google_presence.h Wed Sep 22 14:17:09 2010 +0900 @@ -0,0 +1,32 @@ +/** + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#ifndef PURPLE_JABBER_GOOGLE_PRESENCE_H_ +#define PURPLE_JABBER_GOOGLE_PRESENCE_H_ + +#include "jabber.h" +#include "buddy.h" +#include "status.h" + +void jabber_google_presence_incoming(JabberStream *js, const char *who, JabberBuddyResource *jbr); +char *jabber_google_presence_outgoing(PurpleStatus *tune); + + +#endif /* PURPLE_JABBER_GOOGLE_PRESENCE_H_ */ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/google/google_roster.c Wed Sep 22 14:17:09 2010 +0900 @@ -0,0 +1,206 @@ +/** + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "internal.h" +#include "google_roster.h" +#include "jabber.h" +#include "presence.h" +#include "debug.h" +#include "xmlnode.h" + +void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item) +{ + PurpleAccount *account = purple_connection_get_account(js->gc); + GSList *list = account->deny; + const char *jid = xmlnode_get_attrib(item, "jid"); + char *jid_norm = (char *)jabber_normalize(account, jid); + + while (list) { + if (!strcmp(jid_norm, (char*)list->data)) { + xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER); + xmlnode_set_attrib(query, "gr:ext", "2"); + xmlnode_set_attrib(item, "gr:t", "B"); + return; + } + list = list->next; + } +} + +gboolean jabber_google_roster_incoming(JabberStream *js, xmlnode *item) +{ + PurpleAccount *account = purple_connection_get_account(js->gc); + const char *jid = xmlnode_get_attrib(item, "jid"); + gboolean on_block_list = FALSE; + + char *jid_norm; + + const char *grt = xmlnode_get_attrib_with_namespace(item, "t", NS_GOOGLE_ROSTER); + const char *subscription = xmlnode_get_attrib(item, "subscription"); + const char *ask = xmlnode_get_attrib(item, "ask"); + + if ((!subscription || !strcmp(subscription, "none")) && !ask) { + /* The Google Talk servers will automatically add people from your Gmail address book + * with subscription=none. If we see someone with subscription=none, ignore them. + */ + return FALSE; + } + + jid_norm = g_strdup(jabber_normalize(account, jid)); + + on_block_list = NULL != g_slist_find_custom(account->deny, jid_norm, + (GCompareFunc)strcmp); + + if (grt && (*grt == 'H' || *grt == 'h')) { + /* Hidden; don't show this buddy. */ + GSList *buddies = purple_find_buddies(account, jid_norm); + if (buddies) + purple_debug_info("jabber", "Removing %s from local buddy list\n", + jid_norm); + + for ( ; buddies; buddies = g_slist_delete_link(buddies, buddies)) { + purple_blist_remove_buddy(buddies->data); + } + + g_free(jid_norm); + return FALSE; + } + + if (!on_block_list && (grt && (*grt == 'B' || *grt == 'b'))) { + purple_debug_info("jabber", "Blocking %s\n", jid_norm); + purple_privacy_deny_add(account, jid_norm, TRUE); + } else if (on_block_list && (!grt || (*grt != 'B' && *grt != 'b' ))){ + purple_debug_info("jabber", "Unblocking %s\n", jid_norm); + purple_privacy_deny_remove(account, jid_norm, TRUE); + } + + g_free(jid_norm); + return TRUE; +} + +void jabber_google_roster_add_deny(JabberStream *js, const char *who) +{ + PurpleAccount *account; + GSList *buddies; + JabberIq *iq; + xmlnode *query; + xmlnode *item; + xmlnode *group; + PurpleBuddy *b; + JabberBuddy *jb; + const char *balias; + + jb = jabber_buddy_find(js, who, TRUE); + + account = purple_connection_get_account(js->gc); + buddies = purple_find_buddies(account, who); + if(!buddies) + return; + + b = buddies->data; + + iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster"); + + query = xmlnode_get_child(iq->node, "query"); + item = xmlnode_new_child(query, "item"); + + while(buddies) { + PurpleGroup *g; + + b = buddies->data; + g = purple_buddy_get_group(b); + + group = xmlnode_new_child(item, "group"); + xmlnode_insert_data(group, purple_group_get_name(g), -1); + + buddies = buddies->next; + } + + balias = purple_buddy_get_local_buddy_alias(b); + xmlnode_set_attrib(item, "jid", who); + xmlnode_set_attrib(item, "name", balias ? balias : ""); + xmlnode_set_attrib(item, "gr:t", "B"); + xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER); + xmlnode_set_attrib(query, "gr:ext", "2"); + + jabber_iq_send(iq); + + /* Synthesize a sign-off */ + if (jb) { + JabberBuddyResource *jbr; + GList *l = jb->resources; + while (l) { + jbr = l->data; + if (jbr && jbr->name) + { + purple_debug_misc("jabber", "Removing resource %s\n", jbr->name); + jabber_buddy_remove_resource(jb, jbr->name); + } + l = l->next; + } + } + + purple_prpl_got_user_status(account, who, "offline", NULL); +} + +void jabber_google_roster_rem_deny(JabberStream *js, const char *who) +{ + GSList *buddies; + JabberIq *iq; + xmlnode *query; + xmlnode *item; + xmlnode *group; + PurpleBuddy *b; + const char *balias; + + buddies = purple_find_buddies(purple_connection_get_account(js->gc), who); + if(!buddies) + return; + + b = buddies->data; + + iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster"); + + query = xmlnode_get_child(iq->node, "query"); + item = xmlnode_new_child(query, "item"); + + while(buddies) { + PurpleGroup *g; + + b = buddies->data; + g = purple_buddy_get_group(b); + + group = xmlnode_new_child(item, "group"); + xmlnode_insert_data(group, purple_group_get_name(g), -1); + + buddies = buddies->next; + } + + balias = purple_buddy_get_local_buddy_alias(b); + xmlnode_set_attrib(item, "jid", who); + xmlnode_set_attrib(item, "name", balias ? balias : ""); + xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER); + xmlnode_set_attrib(query, "gr:ext", "2"); + + jabber_iq_send(iq); + + /* See if he's online */ + jabber_presence_subscription_set(js, who, "probe"); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/google/google_roster.h Wed Sep 22 14:17:09 2010 +0900 @@ -0,0 +1,37 @@ +/** + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#ifndef PURPLE_JABBER_GOOGLE_ROSTER_H_ +#define PURPLE_JABBER_GOOGLE_ROSTER_H_ + +#include "jabber.h" + +void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item); + +/* Returns FALSE if this should short-circuit processing of this roster item, or TRUE + * if this roster item should continue to be processed + */ +gboolean jabber_google_roster_incoming(JabberStream *js, xmlnode *item); + +void jabber_google_roster_add_deny(JabberStream *js, const char *who); +void jabber_google_roster_rem_deny(JabberStream *js, const char *who); + + +#endif /* PURPLE_JABBER_GOOGLE_ROSTER_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/google/google_session.c Wed Sep 22 14:17:09 2010 +0900 @@ -0,0 +1,867 @@ +/** + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "internal.h" +#include "debug.h" +#include "google_session.h" +#include "relay.h" + +#include "jingle/jingle.h" + +#ifdef USE_VV + +typedef struct { + PurpleMedia *media; + gboolean video; + GList *remote_audio_candidates; /* list of PurpleMediaCandidate */ + GList *remote_video_candidates; /* list of PurpleMediaCandidate */ + gboolean added_streams; /* this indicates if the streams have been + to media (ie. after getting relay credentials */ +} GoogleAVSessionData; + +static gboolean +google_session_id_equal(gconstpointer a, gconstpointer b) +{ + GoogleSessionId *c = (GoogleSessionId*)a; + GoogleSessionId *d = (GoogleSessionId*)b; + + return !strcmp(c->id, d->id) && !strcmp(c->initiator, d->initiator); +} + +static void +google_session_destroy(GoogleSession *session) +{ + GoogleAVSessionData *session_data = + (GoogleAVSessionData *) session->session_data; + g_free(session->id.id); + g_free(session->id.initiator); + g_free(session->remote_jid); + + if (session_data->remote_audio_candidates) + purple_media_candidate_list_free(session_data->remote_audio_candidates); + + if (session_data->remote_video_candidates) + purple_media_candidate_list_free(session_data->remote_video_candidates); + + if (session->description) + xmlnode_free(session->description); + + g_free(session->session_data); + g_free(session); +} + +static xmlnode * +google_session_create_xmlnode(GoogleSession *session, const char *type) +{ + xmlnode *node = xmlnode_new("session"); + xmlnode_set_namespace(node, NS_GOOGLE_SESSION); + xmlnode_set_attrib(node, "id", session->id.id); + xmlnode_set_attrib(node, "initiator", session->id.initiator); + xmlnode_set_attrib(node, "type", type); + return node; +} + +static void +google_session_send_candidates(PurpleMedia *media, gchar *session_id, + gchar *participant, GoogleSession *session) +{ + PurpleMedia *session_media = + ((GoogleAVSessionData *) session->session_data)->media; + GList *candidates = + purple_media_get_local_candidates(session_media, session_id, + session->remote_jid); + GList *iter; + PurpleMediaCandidate *transport; + gboolean video = FALSE; + + if (!strcmp(session_id, "google-video")) + video = TRUE; + + for (iter = candidates; iter; iter = iter->next) { + JabberIq *iq; + gchar *ip, *port, *username, *password; + gchar pref[16]; + PurpleMediaCandidateType type; + xmlnode *sess; + xmlnode *candidate; + guint component_id; + transport = PURPLE_MEDIA_CANDIDATE(iter->data); + component_id = purple_media_candidate_get_component_id( + transport); + + iq = jabber_iq_new(session->js, JABBER_IQ_SET); + sess = google_session_create_xmlnode(session, "candidates"); + xmlnode_insert_child(iq->node, sess); + xmlnode_set_attrib(iq->node, "to", session->remote_jid); + + candidate = xmlnode_new("candidate"); + + ip = purple_media_candidate_get_ip(transport); + port = g_strdup_printf("%d", + purple_media_candidate_get_port(transport)); + g_ascii_dtostr(pref, 16, + purple_media_candidate_get_priority(transport) / 1000.0); + username = purple_media_candidate_get_username(transport); + password = purple_media_candidate_get_password(transport); + type = purple_media_candidate_get_candidate_type(transport); + + xmlnode_set_attrib(candidate, "address", ip); + xmlnode_set_attrib(candidate, "port", port); + xmlnode_set_attrib(candidate, "name", + component_id == PURPLE_MEDIA_COMPONENT_RTP ? + video ? "video_rtp" : "rtp" : + component_id == PURPLE_MEDIA_COMPONENT_RTCP ? + video ? "video_rtcp" : "rtcp" : "none"); + xmlnode_set_attrib(candidate, "username", username); + /* + * As of this writing, Farsight 2 in Google compatibility + * mode doesn't provide a password. The Gmail client + * requires this to be set. + */ + xmlnode_set_attrib(candidate, "password", + password != NULL ? password : ""); + xmlnode_set_attrib(candidate, "preference", pref); + xmlnode_set_attrib(candidate, "protocol", + purple_media_candidate_get_protocol(transport) + == PURPLE_MEDIA_NETWORK_PROTOCOL_UDP ? + "udp" : "tcp"); + xmlnode_set_attrib(candidate, "type", type == + PURPLE_MEDIA_CANDIDATE_TYPE_HOST ? "local" : + type == + PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX ? "stun" : + type == + PURPLE_MEDIA_CANDIDATE_TYPE_RELAY ? "relay" : + NULL); + xmlnode_set_attrib(candidate, "generation", "0"); + xmlnode_set_attrib(candidate, "network", "0"); + xmlnode_insert_child(sess, candidate); + + g_free(ip); + g_free(port); + g_free(username); + g_free(password); + + jabber_iq_send(iq); + } + purple_media_candidate_list_free(candidates); +} + +static void +google_session_ready(GoogleSession *session) +{ + PurpleMedia *media = + ((GoogleAVSessionData *)session->session_data)->media; + gboolean video = + ((GoogleAVSessionData *)session->session_data)->video; + if (purple_media_codecs_ready(media, NULL) && + purple_media_candidates_prepared(media, NULL, NULL)) { + gchar *me = g_strdup_printf("%s@%s/%s", + session->js->user->node, + session->js->user->domain, + session->js->user->resource); + JabberIq *iq; + xmlnode *sess, *desc, *payload; + GList *codecs, *iter; + gboolean is_initiator = !strcmp(session->id.initiator, me); + + if (!is_initiator && + !purple_media_accepted(media, NULL, NULL)) { + g_free(me); + return; + } + + iq = jabber_iq_new(session->js, JABBER_IQ_SET); + + if (is_initiator) { + xmlnode_set_attrib(iq->node, "to", session->remote_jid); + xmlnode_set_attrib(iq->node, "from", session->id.initiator); + sess = google_session_create_xmlnode(session, "initiate"); + } else { + google_session_send_candidates(media, + "google-voice", session->remote_jid, + session); + google_session_send_candidates(media, + "google-video", session->remote_jid, + session); + xmlnode_set_attrib(iq->node, "to", session->remote_jid); + xmlnode_set_attrib(iq->node, "from", me); + sess = google_session_create_xmlnode(session, "accept"); + } + xmlnode_insert_child(iq->node, sess); + desc = xmlnode_new_child(sess, "description"); + if (video) + xmlnode_set_namespace(desc, NS_GOOGLE_SESSION_VIDEO); + else + xmlnode_set_namespace(desc, NS_GOOGLE_SESSION_PHONE); + + codecs = purple_media_get_codecs(media, "google-video"); + + for (iter = codecs; iter; iter = g_list_next(iter)) { + PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data; + gchar *id = g_strdup_printf("%d", + purple_media_codec_get_id(codec)); + gchar *encoding_name = + purple_media_codec_get_encoding_name(codec); + payload = xmlnode_new_child(desc, "payload-type"); + xmlnode_set_attrib(payload, "id", id); + xmlnode_set_attrib(payload, "name", encoding_name); + xmlnode_set_attrib(payload, "width", "320"); + xmlnode_set_attrib(payload, "height", "200"); + xmlnode_set_attrib(payload, "framerate", "30"); + g_free(encoding_name); + g_free(id); + } + purple_media_codec_list_free(codecs); + + codecs = purple_media_get_codecs(media, "google-voice"); + + for (iter = codecs; iter; iter = g_list_next(iter)) { + PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data; + gchar *id = g_strdup_printf("%d", + purple_media_codec_get_id(codec)); + gchar *encoding_name = + purple_media_codec_get_encoding_name(codec); + gchar *clock_rate = g_strdup_printf("%d", + purple_media_codec_get_clock_rate(codec)); + payload = xmlnode_new_child(desc, "payload-type"); + if (video) + xmlnode_set_namespace(payload, NS_GOOGLE_SESSION_PHONE); + xmlnode_set_attrib(payload, "id", id); + /* + * Hack to make Gmail accept speex as the codec. + * It shouldn't have to be case sensitive. + */ + if (purple_strequal(encoding_name, "SPEEX")) + xmlnode_set_attrib(payload, "name", "speex"); + else + xmlnode_set_attrib(payload, "name", encoding_name); + xmlnode_set_attrib(payload, "clockrate", clock_rate); + g_free(clock_rate); + g_free(encoding_name); + g_free(id); + } + purple_media_codec_list_free(codecs); + + jabber_iq_send(iq); + + if (is_initiator) { + google_session_send_candidates(media, + "google-voice", session->remote_jid, + session); + google_session_send_candidates(media, + "google-video", session->remote_jid, + session); + } + + g_signal_handlers_disconnect_by_func(G_OBJECT(media), + G_CALLBACK(google_session_ready), session); + } +} + +static void +google_session_state_changed_cb(PurpleMedia *media, PurpleMediaState state, + gchar *sid, gchar *name, GoogleSession *session) +{ + if (sid == NULL && name == NULL) { + if (state == PURPLE_MEDIA_STATE_END) { + google_session_destroy(session); + } + } +} + +static void +google_session_stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type, + gchar *sid, gchar *name, gboolean local, + GoogleSession *session) +{ + if (sid != NULL || name != NULL) + return; + + if (type == PURPLE_MEDIA_INFO_HANGUP) { + xmlnode *sess; + JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); + + xmlnode_set_attrib(iq->node, "to", session->remote_jid); + sess = google_session_create_xmlnode(session, "terminate"); + xmlnode_insert_child(iq->node, sess); + + jabber_iq_send(iq); + } else if (type == PURPLE_MEDIA_INFO_REJECT) { + xmlnode *sess; + JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); + + xmlnode_set_attrib(iq->node, "to", session->remote_jid); + sess = google_session_create_xmlnode(session, "reject"); + xmlnode_insert_child(iq->node, sess); + + jabber_iq_send(iq); + } else if (type == PURPLE_MEDIA_INFO_ACCEPT && local == TRUE) { + google_session_ready(session); + } +} + +static GParameter * +jabber_google_session_get_params(JabberStream *js, const gchar *relay_ip, + guint16 relay_udp, guint16 relay_tcp, guint16 relay_ssltcp, + const gchar *relay_username, const gchar *relay_password, guint *num) +{ + guint num_params; + GParameter *params = + jingle_get_params(js, relay_ip, relay_udp, relay_tcp, relay_ssltcp, + relay_username, relay_password, &num_params); + GParameter *new_params = g_new0(GParameter, num_params + 1); + + memcpy(new_params, params, sizeof(GParameter) * num_params); + + purple_debug_info("jabber", "setting Google jingle compatibility param\n"); + new_params[num_params].name = "compatibility-mode"; + g_value_init(&new_params[num_params].value, G_TYPE_UINT); + g_value_set_uint(&new_params[num_params].value, 1); /* NICE_COMPATIBILITY_GOOGLE */ + + g_free(params); + *num = num_params + 1; + return new_params; +} + + +static void +jabber_google_relay_response_session_initiate_cb(GoogleSession *session, + const gchar *relay_ip, guint relay_udp, guint relay_tcp, guint relay_ssltcp, + const gchar *relay_username, const gchar *relay_password) +{ + GParameter *params; + guint num_params; + JabberStream *js = session->js; + GoogleAVSessionData *session_data = + (GoogleAVSessionData *) session->session_data; + + session_data->media = purple_media_manager_create_media( + purple_media_manager_get(), + purple_connection_get_account(js->gc), + "fsrtpconference", session->remote_jid, TRUE); + + purple_media_set_prpl_data(session_data->media, session); + + g_signal_connect_swapped(G_OBJECT(session_data->media), + "candidates-prepared", + G_CALLBACK(google_session_ready), session); + g_signal_connect_swapped(G_OBJECT(session_data->media), "codecs-changed", + G_CALLBACK(google_session_ready), session); + g_signal_connect(G_OBJECT(session_data->media), "state-changed", + G_CALLBACK(google_session_state_changed_cb), session); + g_signal_connect(G_OBJECT(session_data->media), "stream-info", + G_CALLBACK(google_session_stream_info_cb), session); + + params = + jabber_google_session_get_params(js, relay_ip, relay_udp, relay_tcp, + relay_ssltcp, relay_username, relay_password, &num_params); + + if (purple_media_add_stream(session_data->media, "google-voice", + session->remote_jid, PURPLE_MEDIA_AUDIO, + TRUE, "nice", num_params, params) == FALSE || + (session_data->video && purple_media_add_stream( + session_data->media, "google-video", + session->remote_jid, PURPLE_MEDIA_VIDEO, + TRUE, "nice", num_params, params) == FALSE)) { + purple_media_error(session_data->media, "Error adding stream."); + purple_media_end(session_data->media, NULL, NULL); + g_free(params); + } else { + session_data->added_streams = TRUE; + } + + g_free(params); +} + + +gboolean +jabber_google_session_initiate(JabberStream *js, const gchar *who, PurpleMediaSessionType type) +{ + GoogleSession *session; + JabberBuddy *jb; + JabberBuddyResource *jbr; + gchar *jid; + GoogleAVSessionData *session_data = NULL; + + /* construct JID to send to */ + jb = jabber_buddy_find(js, who, FALSE); + if (!jb) { + purple_debug_error("jingle-rtp", + "Could not find Jabber buddy\n"); + return FALSE; + } + jbr = jabber_buddy_find_resource(jb, NULL); + if (!jbr) { + purple_debug_error("jingle-rtp", + "Could not find buddy's resource\n"); + } + + if ((strchr(who, '/') == NULL) && jbr && (jbr->name != NULL)) { + jid = g_strdup_printf("%s/%s", who, jbr->name); + } else { + jid = g_strdup(who); + } + + session = g_new0(GoogleSession, 1); + session->id.id = jabber_get_next_id(js); + session->id.initiator = g_strdup_printf("%s@%s/%s", js->user->node, + js->user->domain, js->user->resource); + session->state = SENT_INITIATE; + session->js = js; + session->remote_jid = jid; + session_data = g_new0(GoogleAVSessionData, 1); + session->session_data = session_data; + + if (type & PURPLE_MEDIA_VIDEO) + session_data->video = TRUE; + + /* if we got a relay token and relay host in google:jingleinfo, issue an + HTTP request to get that data */ + if (js->google_relay_host && js->google_relay_token) { + jabber_google_do_relay_request(js, session, + jabber_google_relay_response_session_initiate_cb); + } else { + jabber_google_relay_response_session_initiate_cb(session, NULL, 0, 0, 0, + NULL, NULL); + } + + /* we don't actually know yet wether it succeeded... maybe this is very + wrong... */ + return TRUE; +} + +static void +jabber_google_relay_response_session_handle_initiate_cb(GoogleSession *session, + const gchar *relay_ip, guint relay_udp, guint relay_tcp, guint relay_ssltcp, + const gchar *relay_username, const gchar *relay_password) +{ + GParameter *params; + guint num_params; + JabberStream *js = session->js; + xmlnode *codec_element; + const gchar *xmlns; + PurpleMediaCodec *codec; + GList *video_codecs = NULL; + GList *codecs = NULL; + JabberIq *result; + GoogleAVSessionData *session_data = + (GoogleAVSessionData *) session->session_data; + + params = + jabber_google_session_get_params(js, relay_ip, relay_udp, relay_tcp, + relay_ssltcp, relay_username, relay_password, &num_params); + + if (purple_media_add_stream(session_data->media, "google-voice", + session->remote_jid, PURPLE_MEDIA_AUDIO, FALSE, + "nice", num_params, params) == FALSE || + (session_data->video && purple_media_add_stream( + session_data->media, "google-video", + session->remote_jid, PURPLE_MEDIA_VIDEO, + FALSE, "nice", num_params, params) == FALSE)) { + purple_media_error(session_data->media, "Error adding stream."); + purple_media_stream_info(session_data->media, + PURPLE_MEDIA_INFO_REJECT, NULL, NULL, TRUE); + } else { + /* successfully added stream(s) */ + session_data->added_streams = TRUE; + + if (session_data->remote_audio_candidates) { + purple_media_add_remote_candidates(session_data->media, + "google-voice", session->remote_jid, + session_data->remote_audio_candidates); + purple_media_candidate_list_free(session_data->remote_audio_candidates); + session_data->remote_audio_candidates = NULL; + } + if (session_data->remote_video_candidates) { + purple_media_add_remote_candidates(session_data->media, + "google-video", session->remote_jid, + session_data->remote_video_candidates); + purple_media_candidate_list_free(session_data->remote_video_candidates); + session_data->remote_video_candidates = NULL; + } + } + + g_free(params); + + for (codec_element = xmlnode_get_child(session->description, "payload-type"); + codec_element; codec_element = codec_element->next) { + const char *id, *encoding_name, *clock_rate, + *width, *height, *framerate; + gboolean video; + if (codec_element->name && + strcmp(codec_element->name, "payload-type")) + continue; + + xmlns = xmlnode_get_namespace(codec_element); + encoding_name = xmlnode_get_attrib(codec_element, "name"); + id = xmlnode_get_attrib(codec_element, "id"); + + if (!session_data->video || + (xmlns && !strcmp(xmlns, NS_GOOGLE_SESSION_PHONE))) { + clock_rate = xmlnode_get_attrib( + codec_element, "clockrate"); + video = FALSE; + } else { + width = xmlnode_get_attrib(codec_element, "width"); + height = xmlnode_get_attrib(codec_element, "height"); + framerate = xmlnode_get_attrib( + codec_element, "framerate"); + clock_rate = "90000"; + video = TRUE; + } + + if (id) { + codec = purple_media_codec_new(atoi(id), encoding_name, + video ? PURPLE_MEDIA_VIDEO : + PURPLE_MEDIA_AUDIO, + clock_rate ? atoi(clock_rate) : 0); + if (video) + video_codecs = g_list_append( + video_codecs, codec); + else + codecs = g_list_append(codecs, codec); + } + } + + if (codecs) + purple_media_set_remote_codecs(session_data->media, "google-voice", + session->remote_jid, codecs); + if (video_codecs) + purple_media_set_remote_codecs(session_data->media, "google-video", + session->remote_jid, video_codecs); + + purple_media_codec_list_free(codecs); + purple_media_codec_list_free(video_codecs); + + result = jabber_iq_new(js, JABBER_IQ_RESULT); + jabber_iq_set_id(result, session->iq_id); + xmlnode_set_attrib(result->node, "to", session->remote_jid); + jabber_iq_send(result); +} + +static gboolean +google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id) +{ + const gchar *xmlns; + GoogleAVSessionData *session_data = + (GoogleAVSessionData *) session->session_data; + + if (session->state != UNINIT) { + purple_debug_error("jabber", "Received initiate for active session.\n"); + return FALSE; + } + + session->description = xmlnode_copy(xmlnode_get_child(sess, "description")); + xmlns = xmlnode_get_namespace(session->description); + + if (purple_strequal(xmlns, NS_GOOGLE_SESSION_PHONE)) + session_data->video = FALSE; + else if (purple_strequal(xmlns, NS_GOOGLE_SESSION_VIDEO)) + session_data->video = TRUE; + else { + purple_debug_error("jabber", "Received initiate with " + "invalid namespace %s.\n", xmlns); + return FALSE; + } + + session_data->media = purple_media_manager_create_media( + purple_media_manager_get(), + purple_connection_get_account(js->gc), + "fsrtpconference", session->remote_jid, FALSE); + + purple_media_set_prpl_data(session_data->media, session); + + g_signal_connect_swapped(G_OBJECT(session_data->media), + "candidates-prepared", + G_CALLBACK(google_session_ready), session); + g_signal_connect_swapped(G_OBJECT(session_data->media), "codecs-changed", + G_CALLBACK(google_session_ready), session); + g_signal_connect(G_OBJECT(session_data->media), "state-changed", + G_CALLBACK(google_session_state_changed_cb), session); + g_signal_connect(G_OBJECT(session_data->media), "stream-info", + G_CALLBACK(google_session_stream_info_cb), session); + + session->iq_id = g_strdup(iq_id); + + if (js->google_relay_host && js->google_relay_token) { + jabber_google_do_relay_request(js, session, + jabber_google_relay_response_session_handle_initiate_cb); + } else { + jabber_google_relay_response_session_handle_initiate_cb(session, NULL, + 0, 0, 0, NULL, NULL); + } + + return TRUE; +} + + +static void +google_session_handle_candidates(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id) +{ + JabberIq *result; + GList *list = NULL, *video_list = NULL; + xmlnode *cand; + static int name = 0; + char n[4]; + GoogleAVSessionData *session_data = + (GoogleAVSessionData *) session->session_data; + + for (cand = xmlnode_get_child(sess, "candidate"); cand; + cand = xmlnode_get_next_twin(cand)) { + PurpleMediaCandidate *info; + const gchar *cname = xmlnode_get_attrib(cand, "name"); + const gchar *type = xmlnode_get_attrib(cand, "type"); + const gchar *protocol = xmlnode_get_attrib(cand, "protocol"); + const gchar *address = xmlnode_get_attrib(cand, "address"); + const gchar *port = xmlnode_get_attrib(cand, "port"); + const gchar *preference = xmlnode_get_attrib(cand, "preference"); + guint component_id; + + if (cname && type && address && port) { + PurpleMediaCandidateType candidate_type; + guint prio = preference ? g_ascii_strtod(preference, NULL) * 1000 : 0; + + g_snprintf(n, sizeof(n), "S%d", name++); + + if (g_str_equal(type, "local")) + candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST; + else if (g_str_equal(type, "stun")) + candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX; + else if (g_str_equal(type, "relay")) + candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_RELAY; + else + candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST; + + if (purple_strequal(cname, "rtcp") || + purple_strequal(cname, "video_rtcp")) + component_id = PURPLE_MEDIA_COMPONENT_RTCP; + else + component_id = PURPLE_MEDIA_COMPONENT_RTP; + + info = purple_media_candidate_new(n, component_id, + candidate_type, + purple_strequal(protocol, "udp") ? + PURPLE_MEDIA_NETWORK_PROTOCOL_UDP : + PURPLE_MEDIA_NETWORK_PROTOCOL_TCP, + address, + atoi(port)); + g_object_set(info, "username", xmlnode_get_attrib(cand, "username"), + "password", xmlnode_get_attrib(cand, "password"), + "priority", prio, NULL); + if (!strncmp(cname, "video_", 6)) { + if (session_data->added_streams) { + video_list = g_list_append(video_list, info); + } else { + session_data->remote_video_candidates = + g_list_append(session_data->remote_video_candidates, + info); + } + } else { + if (session_data->added_streams) { + list = g_list_append(list, info); + } else { + session_data->remote_audio_candidates = + g_list_append(session_data->remote_audio_candidates, + info); + } + } + } + } + + if (list) { + purple_media_add_remote_candidates(session_data->media, "google-voice", + session->remote_jid, list); + purple_media_candidate_list_free(list); + } + if (video_list) { + purple_media_add_remote_candidates(session_data->media, "google-video", + session->remote_jid, video_list); + purple_media_candidate_list_free(video_list); + } + + result = jabber_iq_new(js, JABBER_IQ_RESULT); + jabber_iq_set_id(result, iq_id); + xmlnode_set_attrib(result->node, "to", session->remote_jid); + jabber_iq_send(result); +} + +static void +google_session_handle_accept(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id) +{ + xmlnode *desc_element = xmlnode_get_child(sess, "description"); + xmlnode *codec_element = xmlnode_get_child( + desc_element, "payload-type"); + GList *codecs = NULL, *video_codecs = NULL; + JabberIq *result = NULL; + const gchar *xmlns = xmlnode_get_namespace(desc_element); + gboolean video = (xmlns && !strcmp(xmlns, NS_GOOGLE_SESSION_VIDEO)); + GoogleAVSessionData *session_data = + (GoogleAVSessionData *) session->session_data; + + for (; codec_element; codec_element = codec_element->next) { + const gchar *xmlns, *encoding_name, *id, + *clock_rate, *width, *height, *framerate; + gboolean video_codec = FALSE; + + if (!purple_strequal(codec_element->name, "payload-type")) + continue; + + xmlns = xmlnode_get_namespace(codec_element); + encoding_name = xmlnode_get_attrib(codec_element, "name"); + id = xmlnode_get_attrib(codec_element, "id"); + + if (!video || purple_strequal(xmlns, NS_GOOGLE_SESSION_PHONE)) + clock_rate = xmlnode_get_attrib( + codec_element, "clockrate"); + else { + clock_rate = "90000"; + width = xmlnode_get_attrib(codec_element, "width"); + height = xmlnode_get_attrib(codec_element, "height"); + framerate = xmlnode_get_attrib( + codec_element, "framerate"); + video_codec = TRUE; + } + + if (id && encoding_name) { + PurpleMediaCodec *codec = purple_media_codec_new( + atoi(id), encoding_name, + video_codec ? PURPLE_MEDIA_VIDEO : + PURPLE_MEDIA_AUDIO, + clock_rate ? atoi(clock_rate) : 0); + if (video_codec) + video_codecs = g_list_append( + video_codecs, codec); + else + codecs = g_list_append(codecs, codec); + } + } + + if (codecs) + purple_media_set_remote_codecs(session_data->media, "google-voice", + session->remote_jid, codecs); + if (video_codecs) + purple_media_set_remote_codecs(session_data->media, "google-video", + session->remote_jid, video_codecs); + + purple_media_stream_info(session_data->media, PURPLE_MEDIA_INFO_ACCEPT, + NULL, NULL, FALSE); + + result = jabber_iq_new(js, JABBER_IQ_RESULT); + jabber_iq_set_id(result, iq_id); + xmlnode_set_attrib(result->node, "to", session->remote_jid); + jabber_iq_send(result); +} + +static void +google_session_handle_reject(JabberStream *js, GoogleSession *session, xmlnode *sess) +{ + GoogleAVSessionData *session_data = + (GoogleAVSessionData *) session->session_data; + purple_media_end(session_data->media, NULL, NULL); +} + +static void +google_session_handle_terminate(JabberStream *js, GoogleSession *session, xmlnode *sess) +{ + GoogleAVSessionData *session_data = + (GoogleAVSessionData *) session->session_data; + purple_media_end(session_data->media, NULL, NULL); +} + +static void +google_session_parse_iq(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id) +{ + const char *type = xmlnode_get_attrib(sess, "type"); + + if (!strcmp(type, "initiate")) { + google_session_handle_initiate(js, session, sess, iq_id); + } else if (!strcmp(type, "accept")) { + google_session_handle_accept(js, session, sess, iq_id); + } else if (!strcmp(type, "reject")) { + google_session_handle_reject(js, session, sess); + } else if (!strcmp(type, "terminate")) { + google_session_handle_terminate(js, session, sess); + } else if (!strcmp(type, "candidates")) { + google_session_handle_candidates(js, session, sess, iq_id); + } +} + +void +jabber_google_session_parse(JabberStream *js, const char *from, + JabberIqType type, const char *iq_id, + xmlnode *session_node) +{ + GoogleSession *session = NULL; + GoogleSessionId id; + + xmlnode *desc_node; + + GList *iter = NULL; + + if (type != JABBER_IQ_SET) + return; + + id.id = (gchar*)xmlnode_get_attrib(session_node, "id"); + if (!id.id) + return; + + id.initiator = (gchar*)xmlnode_get_attrib(session_node, "initiator"); + if (!id.initiator) + return; + + iter = purple_media_manager_get_media_by_account( + purple_media_manager_get(), + purple_connection_get_account(js->gc)); + for (; iter; iter = g_list_delete_link(iter, iter)) { + GoogleSession *gsession = + purple_media_get_prpl_data(iter->data); + if (google_session_id_equal(&(gsession->id), &id)) { + session = gsession; + break; + } + } + if (iter != NULL) { + g_list_free(iter); + } + + if (session) { + google_session_parse_iq(js, session, session_node, iq_id); + return; + } + + /* If the session doesn't exist, this has to be an initiate message */ + if (strcmp(xmlnode_get_attrib(session_node, "type"), "initiate")) + return; + desc_node = xmlnode_get_child(session_node, "description"); + if (!desc_node) + return; + session = g_new0(GoogleSession, 1); + session->id.id = g_strdup(id.id); + session->id.initiator = g_strdup(id.initiator); + session->state = UNINIT; + session->js = js; + session->remote_jid = g_strdup(session->id.initiator); + session->session_data = g_new0(GoogleAVSessionData, 1); + + google_session_handle_initiate(js, session, session_node, iq_id); +} +#endif /* USE_VV */ + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/google/google_session.h Wed Sep 22 14:17:09 2010 +0900 @@ -0,0 +1,56 @@ +/** + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#ifndef PURPLE_JABBER_GOOGLE_SESSION_H_ +#define PURPLE_JABBER_GOOGLE_SESSION_H_ + +#include "jabber.h" + +typedef struct { + char *id; + char *initiator; +} GoogleSessionId; + +typedef enum { + UNINIT, + SENT_INITIATE, + RECEIVED_INITIATE, + IN_PRORESS, + TERMINATED +} GoogleSessionState; + +typedef struct { + GoogleSessionId id; + GoogleSessionState state; + JabberStream *js; + char *remote_jid; + char *iq_id; + xmlnode *description; /* store incoming description through + relay credential fetching */ + gpointer session_data; +} GoogleSession; + +gboolean jabber_google_session_initiate(JabberStream *js, const gchar *who, + PurpleMediaSessionType type); + +void jabber_google_session_parse(JabberStream *js, const char *from, + JabberIqType type, const char *iq, xmlnode *session); + +#endif /* PURPLE_JABBER_GOOGLE_SESSION_H_ */ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/google/jingleinfo.c Wed Sep 22 14:17:09 2010 +0900 @@ -0,0 +1,174 @@ +/** + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "internal.h" +#include "debug.h" +#include "jingleinfo.h" + +static void +jabber_google_stun_lookup_cb(GSList *hosts, gpointer data, + const char *error_message) +{ + JabberStream *js = (JabberStream *) data; + + if (error_message) { + purple_debug_error("jabber", "Google STUN lookup failed: %s\n", + error_message); + g_slist_free(hosts); + js->stun_query = NULL; + return; + } + + if (hosts && g_slist_next(hosts)) { + struct sockaddr *addr = g_slist_next(hosts)->data; + char dst[INET6_ADDRSTRLEN]; + int port; + + if (addr->sa_family == AF_INET6) { + inet_ntop(addr->sa_family, &((struct sockaddr_in6 *) addr)->sin6_addr, + dst, sizeof(dst)); + port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port); + } else { + inet_ntop(addr->sa_family, &((struct sockaddr_in *) addr)->sin_addr, + dst, sizeof(dst)); + port = ntohs(((struct sockaddr_in *) addr)->sin_port); + } + + if (js->stun_ip) + g_free(js->stun_ip); + js->stun_ip = g_strdup(dst); + js->stun_port = port; + + purple_debug_info("jabber", "set Google STUN IP/port address: " + "%s:%d\n", dst, port); + + /* unmark ongoing query */ + js->stun_query = NULL; + } + + while (hosts != NULL) { + hosts = g_slist_delete_link(hosts, hosts); + /* Free the address */ + g_free(hosts->data); + hosts = g_slist_delete_link(hosts, hosts); + } +} + +static void +jabber_google_jingle_info_common(JabberStream *js, const char *from, + JabberIqType type, xmlnode *query) +{ + const xmlnode *stun = xmlnode_get_child(query, "stun"); + const xmlnode *relay = xmlnode_get_child(query, "relay"); + gchar *my_bare_jid; + + /* + * Make sure that random people aren't sending us STUN servers. Per + * http://code.google.com/apis/talk/jep_extensions/jingleinfo.html, these + * stanzas are stamped from our bare JID. + */ + if (from) { + my_bare_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain); + if (!purple_strequal(from, my_bare_jid)) { + purple_debug_warning("jabber", "got google:jingleinfo with invalid from (%s)\n", + from); + g_free(my_bare_jid); + return; + } + + g_free(my_bare_jid); + } + + if (type == JABBER_IQ_ERROR || type == JABBER_IQ_GET) + return; + + purple_debug_info("jabber", "got google:jingleinfo\n"); + + if (stun) { + xmlnode *server = xmlnode_get_child(stun, "server"); + + if (server) { + const gchar *host = xmlnode_get_attrib(server, "host"); + const gchar *udp = xmlnode_get_attrib(server, "udp"); + + if (host && udp) { + int port = atoi(udp); + /* if there, would already be an ongoing query, + cancel it */ + if (js->stun_query) + purple_dnsquery_destroy(js->stun_query); + + js->stun_query = purple_dnsquery_a(host, port, + jabber_google_stun_lookup_cb, js); + } + } + } + + if (relay) { + xmlnode *token = xmlnode_get_child(relay, "token"); + xmlnode *server = xmlnode_get_child(relay, "server"); + + if (token) { + gchar *relay_token = xmlnode_get_data(token); + + /* we let js own the string returned from xmlnode_get_data */ + js->google_relay_token = relay_token; + } + + if (server) { + js->google_relay_host = + g_strdup(xmlnode_get_attrib(server, "host")); + } + } +} + +static void +jabber_google_jingle_info_cb(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *packet, gpointer data) +{ + xmlnode *query = xmlnode_get_child_with_namespace(packet, "query", + NS_GOOGLE_JINGLE_INFO); + + if (query) + jabber_google_jingle_info_common(js, from, type, query); + else + purple_debug_warning("jabber", "Got invalid google:jingleinfo\n"); +} + +void +jabber_google_handle_jingle_info(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *child) +{ + jabber_google_jingle_info_common(js, from, type, child); +} + +void +jabber_google_send_jingle_info(JabberStream *js) +{ + JabberIq *jingle_info = + jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_JINGLE_INFO); + + jabber_iq_set_callback(jingle_info, jabber_google_jingle_info_cb, + NULL); + purple_debug_info("jabber", "sending google:jingleinfo query\n"); + jabber_iq_send(jingle_info); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/google/jingleinfo.h Wed Sep 22 14:17:09 2010 +0900 @@ -0,0 +1,32 @@ +/** + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#ifndef PURPLE_JABBER_GOOGLE_ROSTER_H_ +#define PURPLE_JABBER_GOOGLE_ROSTER_H_ + +#include "jabber.h" + +void jabber_google_handle_jingle_info(JabberStream *js, const char *from, + JabberIqType type, const char *id, + xmlnode *child); +void jabber_google_send_jingle_info(JabberStream *js); + + +#endif /* PURPLE_JABBER_GOOGLE_ROSTER_H_ */ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/google/relay.c Wed Sep 22 14:17:09 2010 +0900 @@ -0,0 +1,151 @@ +/** + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "internal.h" +#include "debug.h" + +#include "relay.h" + +typedef struct { + GoogleSession *session; + JabberGoogleRelayCallback *cb; +} JabberGoogleRelayCallbackData; + +static void +jabber_google_relay_parse_response(const gchar *response, gchar **ip, + guint *udp, guint *tcp, guint *ssltcp, gchar **username, gchar **password) +{ + gchar **lines = g_strsplit(response, "\n", -1); + int i = 0; + + for (; lines[i] ; i++) { + gchar *line = lines[i]; + gchar **parts = g_strsplit(line, "=", 2); + + if (parts[0] && parts[1]) { + if (purple_strequal(parts[0], "relay.ip")) { + *ip = g_strdup(parts[1]); + } else if (purple_strequal(parts[0], "relay.udp_port")) { + *udp = atoi(parts[1]); + } else if (purple_strequal(parts[0], "relay.tcp_port")) { + *tcp = atoi(parts[1]); + } else if (purple_strequal(parts[0], "relay.ssltcp_port")) { + *ssltcp = atoi(parts[1]); + } else if (purple_strequal(parts[0], "username")) { + *username = g_strdup(parts[1]); + } else if (purple_strequal(parts[0], "password")) { + *password = g_strdup(parts[1]); + } + } + g_strfreev(parts); + } + + g_strfreev(lines); +} + +static void +jabber_google_relay_remove_url_data(JabberStream *js, + PurpleUtilFetchUrlData *url_data) +{ + GList *iter = js->google_relay_requests; + + while (iter) { + if (iter->data == url_data) { + js->google_relay_requests = + g_list_delete_link(js->google_relay_requests, iter); + break; + } + } +} + +static void +jabber_google_relay_fetch_cb(PurpleUtilFetchUrlData *url_data, + gpointer user_data, const gchar *url_text, gsize len, + const gchar *error_message) +{ + JabberGoogleRelayCallbackData *data = + (JabberGoogleRelayCallbackData *) user_data; + GoogleSession *session = data->session; + JabberStream *js = session->js; + JabberGoogleRelayCallback *cb = data->cb; + gchar *relay_ip = NULL; + guint relay_udp = 0; + guint relay_tcp = 0; + guint relay_ssltcp = 0; + gchar *relay_username = NULL; + gchar *relay_password = NULL; + + g_free(data); + + if (url_data) { + jabber_google_relay_remove_url_data(js, url_data); + } + + purple_debug_info("jabber", "got response on HTTP request to relay server\n"); + + if (url_text && len > 0) { + purple_debug_info("jabber", "got Google relay request response:\n%s\n", + url_text); + jabber_google_relay_parse_response(url_text, &relay_ip, &relay_udp, + &relay_tcp, &relay_ssltcp, &relay_username, &relay_password); + } + + if (cb) + cb(session, relay_ip, relay_udp, relay_tcp, relay_ssltcp, + relay_username, relay_password); + + g_free(relay_ip); + g_free(relay_username); + g_free(relay_password); +} + +void +jabber_google_do_relay_request(JabberStream *js, GoogleSession *session, + JabberGoogleRelayCallback cb) +{ + PurpleUtilFetchUrlData *url_data = NULL; + gchar *url = g_strdup_printf("http://%s", js->google_relay_host); + /* yes, the relay token is included twice as different request headers, + this is apparently needed to make Google's relay servers work... */ + gchar *request = + g_strdup_printf("GET /create_session HTTP/1.0\r\n" + "Host: %s\r\n" + "X-Talk-Google-Relay-Auth: %s\r\n" + "X-Google-Relay-Auth: %s\r\n\r\n", + js->google_relay_host, js->google_relay_token, js->google_relay_token); + JabberGoogleRelayCallbackData *data = g_new0(JabberGoogleRelayCallbackData, 1); + + data->session = session; + data->cb = cb; + purple_debug_info("jabber", + "sending Google relay request %s to %s\n", request, url); + url_data = + purple_util_fetch_url_request(url, FALSE, NULL, FALSE, request, FALSE, + jabber_google_relay_fetch_cb, data); + if (url_data) { + js->google_relay_requests = + g_list_prepend(js->google_relay_requests, url_data); + } else { + purple_debug_error("jabber", "unable to create Google relay request\n"); + jabber_google_relay_fetch_cb(NULL, data, NULL, 0, NULL); + } + g_free(url); + g_free(request); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/google/relay.h Wed Sep 22 14:17:09 2010 +0900 @@ -0,0 +1,33 @@ +/** + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#ifndef JABBER_GOOGLE_RELAY +#define JABBER_GOOGLE_RELAY + +#include "google_session.h" + +typedef void (JabberGoogleRelayCallback)(GoogleSession *session, const gchar *ip, + guint udp_port, guint tcp_port, guint tls_port, + const gchar *username, const gchar *password); + +void jabber_google_do_relay_request(JabberStream *js, GoogleSession *session, + JabberGoogleRelayCallback cb); + +#endif /* JABBER_GOOGLE_RELAY */
--- a/libpurple/protocols/jabber/iq.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/iq.c Wed Sep 22 14:17:09 2010 +0900 @@ -28,7 +28,10 @@ #include "buddy.h" #include "disco.h" -#include "google.h" +#include "google/gmail.h" +#include "google/google.h" +#include "google/jingleinfo.h" +#include "google/google_session.h" #include "iq.h" #include "jingle/jingle.h" #include "oob.h"
--- a/libpurple/protocols/jabber/jabber.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/jabber.c Wed Sep 22 14:17:09 2010 +0900 @@ -51,7 +51,9 @@ #include "chat.h" #include "data.h" #include "disco.h" -#include "google.h" +#include "google/google.h" +#include "google/google_roster.h" +#include "google/google_session.h" #include "ibb.h" #include "iq.h" #include "jutil.h" @@ -205,7 +207,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); } @@ -232,7 +234,7 @@ return TRUE; } - if(purple_account_get_bool(account, "require_tls", JABBER_DEFAULT_REQUIRE_TLS)) { + if (g_str_equal("require_tls", purple_account_get_string(account, "connection_security", JABBER_DEFAULT_REQUIRE_TLS))) { purple_connection_error_reason(js->gc, PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, _("You require encryption, but no TLS/SSL support was found.")); @@ -244,12 +246,16 @@ void jabber_stream_features_parse(JabberStream *js, xmlnode *packet) { - if(xmlnode_get_child(packet, "starttls")) { - if(jabber_process_starttls(js, packet)) { + PurpleAccount *account = purple_connection_get_account(js->gc); + const char *connection_security = + purple_account_get_string(account, "connection_security", JABBER_DEFAULT_REQUIRE_TLS); + + if (xmlnode_get_child(packet, "starttls")) { + if (jabber_process_starttls(js, packet)) { jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION); return; } - } else if(purple_account_get_bool(js->gc->account, "require_tls", JABBER_DEFAULT_REQUIRE_TLS) && !jabber_stream_is_ssl(js)) { + } else if (g_str_equal(connection_security, "require_tls") && !jabber_stream_is_ssl(js)) { purple_connection_error_reason(js->gc, PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR, _("You require encryption, but it is not available on this server.")); @@ -974,6 +980,9 @@ js->stun_ip = NULL; js->stun_port = 0; js->stun_query = NULL; + js->google_relay_token = NULL; + js->google_relay_host = NULL; + js->google_relay_requests = NULL; /* if we are idle, set idle-ness on the stream (this could happen if we get disconnected and the reconnects while being idle. I don't think it makes @@ -1016,7 +1025,7 @@ js->certificate_CN = g_strdup(connect_server[0] ? connect_server : js->user->domain); /* if they've got old-ssl mode going, we probably want to ignore SRV lookups */ - if(purple_account_get_bool(account, "old_ssl", FALSE)) { + if (g_str_equal("old_ssl", purple_account_get_string(account, "connection_security", JABBER_DEFAULT_REQUIRE_TLS))) { if(purple_ssl_is_supported()) { js->gsc = purple_ssl_connect(account, js->certificate_CN, purple_account_get_int(account, "port", 5223), @@ -1633,6 +1642,8 @@ if(js->sasl_mechs) g_string_free(js->sasl_mechs, TRUE); g_free(js->sasl_cb); + /* Note: _not_ g_free. See auth_cyrus.c:jabber_sasl_cb_secret */ + free(js->sasl_secret); #endif g_free(js->serverFQDN); while(js->commands) { @@ -1675,6 +1686,21 @@ js->stun_query = NULL; } + /* remove Google relay-related stuff */ + g_free(js->google_relay_token); + g_free(js->google_relay_host); + if (js->google_relay_requests) { + while (js->google_relay_requests) { + PurpleUtilFetchUrlData *url_data = + (PurpleUtilFetchUrlData *) js->google_relay_requests->data; + purple_util_fetch_url_cancel(url_data); + g_free(url_data); + js->google_relay_requests = + g_list_delete_link(js->google_relay_requests, + js->google_relay_requests); + } + } + g_free(js); gc->proto_data = NULL; @@ -3232,9 +3258,9 @@ g_free(resource); if (type & PURPLE_MEDIA_AUDIO && - !jabber_resource_has_capability(jbr, - JINGLE_APP_RTP_SUPPORT_AUDIO) && - jabber_resource_has_capability(jbr, NS_GOOGLE_VOICE)) + !jabber_resource_has_capability(jbr, + JINGLE_APP_RTP_SUPPORT_AUDIO) && + jabber_resource_has_capability(jbr, NS_GOOGLE_VOICE)) return jabber_google_session_initiate(js, who, type); else return jingle_rtp_initiate_media(js, who, type); @@ -3496,7 +3522,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);
--- a/libpurple/protocols/jabber/jabber.h Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/jabber.h Wed Sep 22 14:17:09 2010 +0900 @@ -80,7 +80,7 @@ #define CAPS0115_NODE "http://pidgin.im/" -#define JABBER_DEFAULT_REQUIRE_TLS TRUE +#define JABBER_DEFAULT_REQUIRE_TLS "require_starttls" #define JABBER_DEFAULT_FT_PROXIES "proxy.eu.jabber.org" /* Index into attention_types list */ @@ -206,6 +206,7 @@ #ifdef HAVE_CYRUS_SASL sasl_conn_t *sasl; sasl_callback_t *sasl_cb; + sasl_secret_t *sasl_secret; const char *current_mech; int auth_fail_count; @@ -275,7 +276,12 @@ gchar *stun_ip; int stun_port; PurpleDnsQueryData *stun_query; - /* later add stuff to handle TURN relays... */ + + /* stuff for Google's relay handling */ + gchar *google_relay_token; + gchar *google_relay_host; + GList *google_relay_requests; /* the HTTP requests to get */ + /* relay info */ }; typedef gboolean (JabberFeatureEnabled)(JabberStream *js, const gchar *namespace); @@ -332,11 +338,25 @@ */ char *jabber_parse_error(JabberStream *js, xmlnode *packet, PurpleConnectionError *reason); -void jabber_add_feature(const gchar *namespace, JabberFeatureEnabled cb); /* cb may be NULL */ +/** + * Add a feature to the list of features advertised via disco#info. If you + * call this while accounts are connected, Bad Things(TM) will happen because + * the Entity Caps hash will be out-of-date (which should be fixed :/) + * + * @param namespace The namespace of the feature + * @param cb A callback determining whether or not this feature + * will advertised; may be NULL. + */ +void jabber_add_feature(const gchar *namespace, JabberFeatureEnabled cb); void jabber_remove_feature(const gchar *namespace); -/** Adds an identity to this jabber library instance. For list of valid values visit the - * website of the XMPP Registrar ( http://www.xmpp.org/registrar/disco-categories.html#client ). +/** Adds an identity to this jabber library instance. For list of valid values + * visit the website of the XMPP Registrar + * (http://www.xmpp.org/registrar/disco-categories.html#client). + * + * Like with jabber_add_feature, if you call this while accounts are connected, + * Bad Things will happen. + * * @param category the category of the identity. * @param type the type of the identity. * @param language the language localization of the name. Can be NULL.
--- a/libpurple/protocols/jabber/jingle/jingle.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/jingle/jingle.c Wed Sep 22 14:17:09 2010 +0900 @@ -35,6 +35,9 @@ #include "rtp.h" #include <string.h> +#ifdef USE_VV +#include <gst/gst.h> +#endif GType jingle_get_type(const gchar *type) @@ -431,32 +434,91 @@ jingle_terminate_sessions_gh, NULL); } +#ifdef USE_VV +static GValueArray * +jingle_create_relay_info(const gchar *ip, guint port, const gchar *username, + const gchar *password, const gchar *relay_type, GValueArray *relay_info) +{ + GValue value; + GstStructure *turn_setup = gst_structure_new("relay-info", + "ip", G_TYPE_STRING, ip, + "port", G_TYPE_UINT, port, + "username", G_TYPE_STRING, username, + "password", G_TYPE_STRING, password, + "relay-type", G_TYPE_STRING, relay_type, + NULL); + purple_debug_info("jabber", "created gst_structure %" GST_PTR_FORMAT "\n", + turn_setup); + if (turn_setup) { + memset(&value, 0, sizeof(GValue)); + g_value_init(&value, GST_TYPE_STRUCTURE); + gst_value_set_structure(&value, turn_setup); + relay_info = g_value_array_append(relay_info, &value); + gst_structure_free(turn_setup); + } + return relay_info; +} + GParameter * -jingle_get_params(JabberStream *js, guint *num) +jingle_get_params(JabberStream *js, const gchar *relay_ip, guint relay_udp, + guint relay_tcp, guint relay_ssltcp, const gchar *relay_username, + const gchar *relay_password, guint *num) { /* don't set a STUN server if one is set globally in prefs, in that case this will be handled in media.c */ gboolean has_account_stun = js->stun_ip && !purple_network_get_stun_ip(); - guint num_params = has_account_stun ? 2 : 0; + guint num_params = has_account_stun ? + (relay_ip ? 3 : 2) : (relay_ip ? 1 : 0); GParameter *params = NULL; - + int next_index = 0; + if (num_params > 0) { params = g_new0(GParameter, num_params); - purple_debug_info("jabber", - "setting param stun-ip for stream using auto-discovered IP: %s\n", - js->stun_ip); - params[0].name = "stun-ip"; - g_value_init(¶ms[0].value, G_TYPE_STRING); - g_value_set_string(¶ms[0].value, js->stun_ip); - purple_debug_info("jabber", - "setting param stun-port for stream using auto-discovered port: %d\n", - js->stun_port); - params[1].name = "stun-port"; - g_value_init(¶ms[1].value, G_TYPE_UINT); - g_value_set_uint(¶ms[1].value, js->stun_port); + if (has_account_stun) { + purple_debug_info("jabber", + "setting param stun-ip for stream using Google auto-config: %s\n", + js->stun_ip); + params[next_index].name = "stun-ip"; + g_value_init(¶ms[next_index].value, G_TYPE_STRING); + g_value_set_string(¶ms[next_index].value, js->stun_ip); + purple_debug_info("jabber", + "setting param stun-port for stream using Google auto-config: %d\n", + js->stun_port); + next_index++; + params[next_index].name = "stun-port"; + g_value_init(¶ms[next_index].value, G_TYPE_UINT); + g_value_set_uint(¶ms[next_index].value, js->stun_port); + next_index++; + } + + if (relay_ip) { + GValueArray *relay_info = g_value_array_new(0); + + if (relay_udp) { + relay_info = + jingle_create_relay_info(relay_ip, relay_udp, relay_username, + relay_password, "udp", relay_info); + } + if (relay_tcp) { + relay_info = + jingle_create_relay_info(relay_ip, relay_tcp, relay_username, + relay_password, "tcp", relay_info); + } + if (relay_ssltcp) { + relay_info = + jingle_create_relay_info(relay_ip, relay_ssltcp, relay_username, + relay_password, "tls", relay_info); + } + params[next_index].name = "relay-info"; + g_value_init(¶ms[next_index].value, G_TYPE_VALUE_ARRAY); + g_value_set_boxed(¶ms[next_index].value, relay_info); + g_value_array_free(relay_info); + } } *num = num_params; return params; } +#endif +
--- a/libpurple/protocols/jabber/jingle/jingle.h Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/jingle/jingle.h Wed Sep 22 14:17:09 2010 +0900 @@ -78,9 +78,13 @@ void jingle_terminate_sessions(JabberStream *js); +#ifdef USE_VV /* create a GParam array given autoconfigured STUN (and later perhaps TURN). if google_talk is TRUE, set compatability mode to GOOGLE_TALK */ -GParameter *jingle_get_params(JabberStream *js, guint *num_params); +GParameter *jingle_get_params(JabberStream *js, const gchar *relay_ip, + guint relay_udp, guint relay_tcp, guint relay_ssltcp, + const gchar *relay_username, const gchar *relay_password, guint *num_params); +#endif #ifdef __cplusplus }
--- a/libpurple/protocols/jabber/jingle/rtp.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/jingle/rtp.c Wed Sep 22 14:17:09 2010 +0900 @@ -611,7 +611,8 @@ : PURPLE_MEDIA_RECV_VIDEO; params = - jingle_get_params(jingle_session_get_js(session), &num_params); + jingle_get_params(jingle_session_get_js(session), NULL, 0, 0, 0, + NULL, NULL, &num_params); creator = jingle_content_get_creator(content); if (!strcmp(creator, "initiator"))
--- a/libpurple/protocols/jabber/jingle/transport.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/jingle/transport.c Wed Sep 22 14:17:09 2010 +0900 @@ -108,11 +108,8 @@ static void jingle_transport_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - JingleTransport *transport; g_return_if_fail(JINGLE_IS_TRANSPORT(object)); - transport = JINGLE_TRANSPORT(object); - switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -123,10 +120,7 @@ static void jingle_transport_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - JingleTransport *transport; g_return_if_fail(JINGLE_IS_TRANSPORT(object)); - - transport = JINGLE_TRANSPORT(object); switch (prop_id) { default:
--- a/libpurple/protocols/jabber/libxmpp.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/libxmpp.c Wed Sep 22 14:17:09 2010 +0900 @@ -41,7 +41,7 @@ #include "si.h" #include "message.h" #include "presence.h" -#include "google.h" +#include "google/google.h" #include "pep.h" #include "usermood.h" #include "usertune.h" @@ -253,6 +253,7 @@ { PurpleAccountUserSplit *split; PurpleAccountOption *option; + GList *encryption_values = NULL; /* Translators: 'domain' is used here in the context of Internet domains, e.g. pidgin.im */ split = purple_account_user_split_new(_("Domain"), NULL, '@'); @@ -263,13 +264,26 @@ purple_account_user_split_set_reverse(split, FALSE); prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); - option = purple_account_option_bool_new(_("Require SSL/TLS"), "require_tls", JABBER_DEFAULT_REQUIRE_TLS); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, - option); +#define ADD_VALUE(list, desc, v) { \ + PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1); \ + kvp->key = g_strdup((desc)); \ + kvp->value = g_strdup((v)); \ + list = g_list_prepend(list, kvp); \ +} - option = purple_account_option_bool_new(_("Force old (port 5223) SSL"), "old_ssl", FALSE); + ADD_VALUE(encryption_values, _("Require encryption"), "require_tls"); + ADD_VALUE(encryption_values, _("Use encryption if available"), "opportunistic_tls"); + ADD_VALUE(encryption_values, _("Use old-style SSL"), "old_ssl"); +#if 0 + ADD_VALUE(encryption_values, "None", "none"); +#endif + encryption_values = g_list_reverse(encryption_values); + +#undef ADD_VALUE + + option = purple_account_option_list_new(_("Connection security"), "connection_security", encryption_values); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, - option); + option); option = purple_account_option_bool_new( _("Allow plaintext auth over unencrypted streams"),
--- a/libpurple/protocols/jabber/message.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/message.c Wed Sep 22 14:17:09 2010 +0900 @@ -30,7 +30,7 @@ #include "buddy.h" #include "chat.h" #include "data.h" -#include "google.h" +#include "google/google.h" #include "message.h" #include "xmlnode.h" #include "pep.h" @@ -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 */
--- a/libpurple/protocols/jabber/oob.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/oob.c Wed Sep 22 14:17:09 2010 +0900 @@ -185,7 +185,7 @@ jabber_oob_xfer_recv_error(xfer, "406"); } -static void jabber_oob_xfer_recv_canceled(PurpleXfer *xfer) { +static void jabber_oob_xfer_recv_cancelled(PurpleXfer *xfer) { jabber_oob_xfer_recv_error(xfer, "404"); } @@ -233,7 +233,7 @@ purple_xfer_set_init_fnc(xfer, jabber_oob_xfer_init); purple_xfer_set_end_fnc(xfer, jabber_oob_xfer_end); purple_xfer_set_request_denied_fnc(xfer, jabber_oob_xfer_recv_denied); - purple_xfer_set_cancel_recv_fnc(xfer, jabber_oob_xfer_recv_canceled); + purple_xfer_set_cancel_recv_fnc(xfer, jabber_oob_xfer_recv_cancelled); purple_xfer_set_read_fnc(xfer, jabber_oob_xfer_read); purple_xfer_set_start_fnc(xfer, jabber_oob_xfer_start);
--- a/libpurple/protocols/jabber/parser.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/parser.c Wed Sep 22 14:17:09 2010 +0900 @@ -93,10 +93,25 @@ } } - if (js->stream_id == NULL) + if (js->stream_id == NULL) { +#if 0 + /* This was underspecified in rfc3920 as only being a SHOULD, so + * we cannot rely on it. See #12331 and Oracle's server. + */ purple_connection_error_reason(js->gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, _("XMPP stream missing ID")); +#else + /* Instead, let's make up a placeholder stream ID, which we need + * to do because we flag on it being NULL as a special case + * in this parsing code. + */ + js->stream_id = g_strdup(""); + purple_debug_info("jabber", "Server failed to specify a stream " + "ID (underspecified in rfc3920, but intended " + "to be a MUST; digest legacy auth may fail."); +#endif + } } else { if(js->current)
--- a/libpurple/protocols/jabber/presence.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/presence.c Wed Sep 22 14:17:09 2010 +0900 @@ -34,7 +34,8 @@ #include "buddy.h" #include "chat.h" -#include "google.h" +#include "google/google.h" +#include "google/google_presence.h" #include "presence.h" #include "iq.h" #include "jutil.h"
--- a/libpurple/protocols/jabber/roster.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/roster.c Wed Sep 22 14:17:09 2010 +0900 @@ -27,7 +27,8 @@ #include "buddy.h" #include "chat.h" -#include "google.h" +#include "google/google.h" +#include "google/google_roster.h" #include "presence.h" #include "roster.h" #include "iq.h" @@ -76,12 +77,9 @@ void jabber_roster_request(JabberStream *js) { - PurpleAccount *account; JabberIq *iq; xmlnode *query; - account = purple_connection_get_account(js->gc); - iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:roster"); query = xmlnode_get_child(iq->node, "query");
--- a/libpurple/protocols/jabber/si.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/jabber/si.c Wed Sep 22 14:17:09 2010 +0900 @@ -1677,12 +1677,8 @@ void jabber_si_xfer_send(PurpleConnection *gc, const char *who, const char *file) { - JabberStream *js; - PurpleXfer *xfer; - js = gc->proto_data; - xfer = jabber_si_new_xfer(gc, who); if (file) @@ -1745,7 +1741,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);
--- a/libpurple/protocols/msn/contact.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/msn/contact.c Wed Sep 22 14:17:09 2010 +0900 @@ -527,16 +527,20 @@ g_return_if_fail(session != NULL); if (resp != NULL) { +#ifdef MSN_PARTIAL_LISTS const char *abLastChange; const char *dynamicItemLastChange; +#endif purple_debug_misc("msn", "Got the contact list!\n"); msn_parse_contact_list(session, resp->xml); +#ifdef MSN_PARTIAL_LISTS abLastChange = purple_account_get_string(session->account, "ablastChange", NULL); dynamicItemLastChange = purple_account_get_string(session->account, - "dynamicItemLastChange", NULL); + "DynamicItemLastChanged", NULL); +#endif if (state->partner_scenario == MSN_PS_INITIAL) { #ifdef MSN_PARTIAL_LISTS @@ -684,20 +688,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 +840,7 @@ g_free(uid); g_free(type); g_free(mobile_number); + g_free(alias); } static gboolean @@ -885,7 +890,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 +900,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) { @@ -1564,7 +1569,7 @@ if (list == MSN_LIST_PL) { partner_scenario = MSN_PS_CONTACT_API; - if (user && user->networkid != MSN_NETWORK_PASSPORT) + if (user->networkid != MSN_NETWORK_PASSPORT) member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML, "EmailMember", "Email", user->member_id_on_pending_list);
--- a/libpurple/protocols/msn/httpconn.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/msn/httpconn.c Wed Sep 22 14:17:09 2010 +0900 @@ -239,6 +239,9 @@ } else { + /* I'll be honest, I don't fully understand all this, but this + * causes crashes, Stu. */ +#if 0 MsnServConn *servconn; /* It's going to die. */ @@ -246,10 +249,9 @@ servconn = httpconn->servconn; - /* I'll be honest, I don't fully understand all this, but this - * causes crashes, Stu. */ - /* if (servconn != NULL) - servconn->wasted = TRUE; */ + if (servconn != NULL) + servconn->wasted = TRUE; +#endif g_free(full_session_id); g_free(session_id);
--- a/libpurple/protocols/msn/msn.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/msn/msn.c Wed Sep 22 14:17:09 2010 +0900 @@ -641,7 +641,6 @@ { PurpleBuddy *buddy; PurpleConnection *gc; - MsnSession *session; MsnMobileData *data; PurpleAccount *account; const char *name; @@ -653,8 +652,6 @@ gc = purple_account_get_connection(account); name = purple_buddy_get_name(buddy); - session = gc->proto_data; - data = g_new0(MsnMobileData, 1); data->gc = gc; data->passport = name; @@ -2108,11 +2105,9 @@ msn_remove_group(PurpleConnection *gc, PurpleGroup *group) { MsnSession *session; - MsnCmdProc *cmdproc; const char *gname; session = gc->proto_data; - cmdproc = session->notification->cmdproc; gname = purple_group_get_name(group); purple_debug_info("msn", "Remove group %s\n", gname);
--- a/libpurple/protocols/msn/msnutils.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/msn/msnutils.c Wed Sep 22 14:17:09 2010 +0900 @@ -541,7 +541,7 @@ chlStringParts = (unsigned int *)buf; /* this is magic */ - for (i = 0; i < (strlen(buf) / 4); i += 2) { + for (i = 0; i < (len / 4); i += 2) { long long temp; chlStringParts[i] = GUINT_TO_LE(chlStringParts[i]);
--- a/libpurple/protocols/msn/notification.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/msn/notification.c Wed Sep 22 14:17:09 2010 +0900 @@ -92,7 +92,6 @@ { MsnCmdProc *cmdproc; MsnSession *session; - PurpleAccount *account; GString *vers; const char *ver_str; int i; @@ -101,7 +100,6 @@ cmdproc = servconn->cmdproc; session = servconn->session; - account = session->account; vers = g_string_new(""); @@ -178,10 +176,8 @@ usr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSession *session; - PurpleAccount *account; session = cmdproc->session; - account = session->account; if (!g_ascii_strcasecmp(cmd->params[1], "OK")) { @@ -1000,7 +996,6 @@ { MsnSession *session; PurpleAccount *account; - PurpleConnection *gc; MsnUser *user; MsnObject *msnobj = NULL; unsigned long clientid; @@ -1010,7 +1005,6 @@ session = cmdproc->session; account = session->account; - gc = purple_account_get_connection(account); state = cmd->params[1]; passport = cmd->params[2]; @@ -1203,7 +1197,6 @@ { MsnSession *session; PurpleAccount *account; - PurpleConnection *gc; MsnUser *user; MsnObject *msnobj; unsigned long clientid; @@ -1212,7 +1205,6 @@ session = cmdproc->session; account = session->account; - gc = purple_account_get_connection(account); state = cmd->params[0]; passport = cmd->params[1]; @@ -1387,11 +1379,13 @@ MsnSession *session; MsnSwitchBoard *swboard; const char *session_id; + const char *auth_key; char *host; int port; session = cmdproc->session; session_id = cmd->params[0]; + auth_key = cmd->params[3]; msn_parse_socket(cmd->params[1], &host, &port); @@ -1401,8 +1395,8 @@ swboard = msn_switchboard_new(session); msn_switchboard_set_invited(swboard, TRUE); - msn_switchboard_set_session_id(swboard, cmd->params[0]); - msn_switchboard_set_auth_key(swboard, cmd->params[3]); + msn_switchboard_set_session_id(swboard, session_id); + msn_switchboard_set_auth_key(swboard, auth_key); swboard->im_user = g_strdup(cmd->params[4]); /* msn_switchboard_add_user(swboard, cmd->params[4]); */ @@ -1571,13 +1565,11 @@ size_t len) { MsnSession *session; - PurpleAccount *account; MsnUser *user; const char *passport; char *str; session = cmdproc->session; - account = session->account; passport = cmd->params[0]; user = msn_userlist_find_user(session->userlist, passport); @@ -1649,7 +1641,9 @@ { MsnSession *session; const char *value; +#ifdef MSN_PARTIAL_LISTS const char *clLastChange; +#endif session = cmdproc->session; @@ -1692,9 +1686,9 @@ if ((value = msn_message_get_attr(msg, "EmailEnabled")) != NULL) session->passport_info.email_enabled = (gboolean)atol(value); +#ifdef MSN_PARTIAL_LISTS /*starting retrieve the contact list*/ clLastChange = purple_account_get_string(session->account, "CLLastChange", NULL); -#ifdef MSN_PARTIAL_LISTS /* msn_userlist_load defeats all attempts at trying to detect blist sync issues */ msn_userlist_load(session); msn_get_contact_list(session, MSN_PS_INITIAL, clLastChange); @@ -1898,7 +1892,7 @@ if ((type_s = g_hash_table_lookup(table, "Type")) != NULL) { int type = atoi(type_s); - char buf[MSN_BUF_LEN]; + char buf[MSN_BUF_LEN] = ""; int minutes; switch (type)
--- a/libpurple/protocols/msn/session.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/msn/session.c Wed Sep 22 14:17:09 2010 +0900 @@ -283,7 +283,7 @@ void msn_session_activate_login_timeout(MsnSession *session) { - if (!session->logged_in) { + if (!session->logged_in && session->connected) { session->login_timeout = purple_timeout_add_seconds(MSN_LOGIN_FQY_TIMEOUT, msn_login_timeout_cb, session);
--- a/libpurple/protocols/msn/slp.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/msn/slp.c Wed Sep 22 14:17:09 2010 +0900 @@ -1263,8 +1263,6 @@ if (userlist->buddy_icon_window > 0) { GQueue *queue; - PurpleAccount *account; - const char *username; queue = userlist->buddy_icon_requests; @@ -1273,9 +1271,6 @@ user = g_queue_pop_head(queue); - account = userlist->session->account; - username = user->passport; - userlist->buddy_icon_window--; request_user_display(user); @@ -1347,31 +1342,21 @@ got_user_display(MsnSlpCall *slpcall, const guchar *data, gsize size) { - MsnUserList *userlist; + MsnSlpLink *slplink; const char *info; PurpleAccount *account; g_return_if_fail(slpcall != NULL); + slplink = slpcall->slplink; info = slpcall->data_info; if (purple_debug_is_verbose()) - purple_debug_info("msn", "Got User Display: %s\n", slpcall->slplink->remote_user); - - userlist = slpcall->slplink->session->userlist; - account = slpcall->slplink->session->account; - - purple_buddy_icons_set_for_user(account, slpcall->slplink->remote_user, - g_memdup(data, size), size, info); + purple_debug_info("msn", "Got User Display: %s\n", slplink->remote_user); -#if 0 - /* Free one window slot */ - userlist->buddy_icon_window++; + account = slplink->session->account; - purple_debug_info("msn", "got_user_display(): buddy_icon_window++ yields =%d\n", - userlist->buddy_icon_window); - - msn_release_buddy_icon_request(userlist); -#endif + purple_buddy_icons_set_for_user(account, slplink->remote_user, + g_memdup(data, size), size, info); } static void
--- a/libpurple/protocols/msn/slplink.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/msn/slplink.c Wed Sep 22 14:17:09 2010 +0900 @@ -632,7 +632,7 @@ slpmsg = msn_slplink_message_find(slplink, header->session_id, header->id); if (slpmsg == NULL) { - /* Probably the transfer was canceled */ + /* Probably the transfer was cancelled */ purple_debug_error("msn", "Couldn't find slpmsg\n"); return; }
--- a/libpurple/protocols/msn/switchboard.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/msn/switchboard.c Wed Sep 22 14:17:09 2010 +0900 @@ -761,12 +761,8 @@ static void iro_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - PurpleAccount *account; - PurpleConnection *gc; MsnSwitchBoard *swboard; - account = cmdproc->session->account; - gc = account->gc; swboard = cmdproc->data; swboard->total_users = atoi(cmd->params[2]); @@ -778,16 +774,12 @@ joi_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSession *session; - PurpleAccount *account; - PurpleConnection *gc; MsnSwitchBoard *swboard; const char *passport; passport = cmd->params[0]; session = cmdproc->session; - account = session->account; - gc = account->gc; swboard = cmdproc->data; msn_switchboard_add_user(swboard, passport);
--- a/libpurple/protocols/oscar/Makefile.am Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/Makefile.am Wed Sep 22 14:17:09 2010 +0900 @@ -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)
--- a/libpurple/protocols/oscar/Makefile.mingw Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/Makefile.mingw Wed Sep 22 14:17:09 2010 +0900 @@ -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)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/oscar/authorization.c Wed Sep 22 14:17:09 2010 +0900 @@ -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
--- a/libpurple/protocols/oscar/bstream.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/bstream.c Wed Sep 22 14:17:09 2010 +0900 @@ -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; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/oscar/encoding.c Wed Sep 22 14:17:09 2010 +0900 @@ -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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/oscar/encoding.h Wed Sep 22 14:17:09 2010 +0900 @@ -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
--- a/libpurple/protocols/oscar/family_admin.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/family_admin.c Wed Sep 22 14:17:09 2010 +0900 @@ -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); }
--- a/libpurple/protocols/oscar/family_advert.c Tue Aug 17 17:23:13 2010 +0900 +++ /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; -}
--- a/libpurple/protocols/oscar/family_alert.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/family_alert.c Wed Sep 22 14:17:09 2010 +0900 @@ -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);
--- a/libpurple/protocols/oscar/family_auth.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/family_auth.c Wed Sep 22 14:17:09 2010 +0900 @@ -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);
--- a/libpurple/protocols/oscar/family_bart.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/family_bart.c Wed Sep 22 14:17:09 2010 +0900 @@ -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);
--- a/libpurple/protocols/oscar/family_bos.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/family_bos.c Wed Sep 22 14:17:09 2010 +0900 @@ -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) {
--- a/libpurple/protocols/oscar/family_buddy.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/family_buddy.c Wed Sep 22 14:17:09 2010 +0900 @@ -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
--- a/libpurple/protocols/oscar/family_chat.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/family_chat.c Wed Sep 22 14:17:09 2010 +0900 @@ -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. */
--- a/libpurple/protocols/oscar/family_chatnav.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/family_chatnav.c Wed Sep 22 14:17:09 2010 +0900 @@ -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); }
--- a/libpurple/protocols/oscar/family_feedbag.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/family_feedbag.c Wed Sep 22 14:17:09 2010 +0900 @@ -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) {
--- a/libpurple/protocols/oscar/family_icbm.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/family_icbm.c Wed Sep 22 14:17:09 2010 +0900 @@ -44,6 +44,7 @@ * Make sure flap_connection_findbygroup is used by all functions. */ +#include "encoding.h" #include "oscar.h" #include "peer.h" @@ -109,69 +110,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 @@ -288,7 +226,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); @@ -346,40 +284,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) { @@ -388,7 +300,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; @@ -396,37 +307,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); @@ -442,52 +333,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 */ @@ -522,7 +392,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 */ @@ -532,33 +402,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) @@ -668,7 +511,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); @@ -738,100 +581,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); @@ -884,7 +634,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); } @@ -919,7 +669,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); } @@ -974,7 +724,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); } @@ -1037,7 +787,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); } @@ -1084,17 +834,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; @@ -1123,7 +862,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); } @@ -1176,17 +915,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; @@ -1216,530 +944,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; @@ -1748,93 +1003,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); @@ -1852,39 +1034,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); } /* @@ -1902,10 +1061,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; } @@ -1931,7 +1087,7 @@ * ... * ... */ - while (byte_stream_empty(servdata)) + while (byte_stream_bytes_left(servdata)) { guint16 gnlen, numb; int i; @@ -2003,7 +1159,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); } /* @@ -2017,33 +1173,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 @@ -2203,7 +1360,7 @@ /* * Terminate connection/error code. 0x0001 means the other user - * canceled the connection. + * cancelled the connection. */ if (aim_tlv_gettlv(list2, 0x000b, 1)) args.errorcode = aim_tlv_get16(list2, 0x000b, 1); @@ -2228,20 +1385,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 */ @@ -2436,38 +1579,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) { @@ -2476,7 +1587,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); @@ -2496,9 +1607,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) @@ -2525,186 +1634,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); } /* @@ -2859,16 +1839,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; @@ -2878,8 +1852,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); @@ -2954,7 +1927,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); @@ -3042,7 +2015,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); @@ -3128,9 +2101,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); @@ -3175,8 +2148,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)
--- a/libpurple/protocols/oscar/family_icq.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/family_icq.c Wed Sep 22 14:17:09 2010 +0900 @@ -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
--- a/libpurple/protocols/oscar/family_invite.c Tue Aug 17 17:23:13 2010 +0900 +++ /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; -}
--- a/libpurple/protocols/oscar/family_locate.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/family_locate.c Wed Sep 22 14:17:09 2010 +0900 @@ -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) {
--- a/libpurple/protocols/oscar/family_odir.c Tue Aug 17 17:23:13 2010 +0900 +++ /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; -}
--- a/libpurple/protocols/oscar/family_oservice.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/family_oservice.c Wed Sep 22 14:17:09 2010 +0900 @@ -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);
--- a/libpurple/protocols/oscar/family_translate.c Tue Aug 17 17:23:13 2010 +0900 +++ /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; -}
--- a/libpurple/protocols/oscar/family_userlookup.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/family_userlookup.c Wed Sep 22 14:17:09 2010 +0900 @@ -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);
--- a/libpurple/protocols/oscar/flap_connection.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/flap_connection.c Wed Sep 22 14:17:09 2010 +0900 @@ -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;
--- a/libpurple/protocols/oscar/libaim.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/libaim.c Wed Sep 22 14:17:09 2010 +0900 @@ -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 */
--- a/libpurple/protocols/oscar/libicq.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/libicq.c Wed Sep 22 14:17:09 2010 +0900 @@ -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 */
--- a/libpurple/protocols/oscar/misc.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/misc.c Wed Sep 22 14:17:09 2010 +0900 @@ -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)))
--- a/libpurple/protocols/oscar/msgcookie.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/msgcookie.c Wed Sep 22 14:17:09 2010 +0900 @@ -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; - } -}
--- a/libpurple/protocols/oscar/odc.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/odc.c Wed Sep 22 14:17:09 2010 +0900 @@ -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); @@ -371,8 +372,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); @@ -391,8 +391,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); @@ -514,7 +513,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)
--- a/libpurple/protocols/oscar/oft.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/oft.c Wed Sep 22 14:17:09 2010 +0900 @@ -240,7 +240,7 @@ peer_oft_close(PeerConnection *conn) { /* - * If canceled by local user, and we're receiving a file, and + * If cancelled by local user, and we're receiving a file, and * we're not connected/ready then send an ICBM cancel message. */ if ((purple_xfer_get_status(conn->xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL) &&
--- a/libpurple/protocols/oscar/oscar.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/oscar.c Wed Sep 22 14:17:09 2010 +0900 @@ -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); @@ -792,255 +740,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("<a href=\"%s\">%s</a>", - 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; @@ -1524,22 +1223,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); @@ -1799,34 +1488,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; @@ -2281,18 +1942,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) /* @@ -2398,17 +2059,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) { @@ -2546,8 +2201,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; @@ -2575,24 +2229,13 @@ 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; // purple_debug_info("yaz oscar", "chat request %s\n", args->msg); @@ -2600,11 +2243,7 @@ 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) @@ -2627,8 +2266,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) { @@ -2636,7 +2274,7 @@ } else if (args->status == AIM_RENDEZVOUS_CANCEL) { - /* The other user canceled a peer request */ + /* The other user cancelled a peer request */ PeerConnection *conn; conn = peer_connection_find_by_cookie(od, userinfo->bn, args->cookie); @@ -2681,24 +2319,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", "<br>"); + 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"); @@ -2716,122 +2352,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) @@ -2875,7 +2395,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; @@ -2928,24 +2448,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; @@ -3409,105 +2922,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("<a href=\"%s/%s\">%s</a>", - 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; @@ -3650,13 +3064,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); @@ -3664,16 +3072,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); @@ -3689,7 +3088,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; @@ -3708,10 +3106,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); @@ -3829,41 +3224,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; @@ -3884,10 +3244,6 @@ */ warning_level = info->warnlevel/10.0 + 0.5; -#ifdef CRAZY_WARNING - purple_presence_set_warning_level(presence, warning_level); -#endif - return 1; } @@ -4026,16 +3382,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)); @@ -4067,206 +3421,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("<a href=\"mailto:%s\">%s</a>", 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("<a href=\"mailto:%s\">%s</a>", 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("<a href=\"%s\">%s</a>", 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("<a href=\"%s\">%s</a>", 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; @@ -4490,6 +3644,8 @@ { GString *msg; GString *data; + gchar *tmp; + gsize tmplen; guint16 charset; GData *attribs; const char *start, *end, *last; @@ -4550,9 +3706,16 @@ g_string_append(msg, "</BODY></HTML>"); +#if 0 /* iChat and AIM6 use 0x000d to send UTF8. moreover, AIM6 persists only to UTF8! --yaz */ charset = AIM_CHARSET_QUIRKUTF8; +#endif + /* Convert the message to a good encoding */ + tmp = oscar_encode_im(msg->str, &tmplen, &charset, NULL); + g_string_free(msg, TRUE); + msg = g_string_new_len(tmp, tmplen); + g_free(tmp); /* Append any binary data that we may have */ if (oscar_id) { @@ -4596,7 +3759,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); @@ -4629,7 +3792,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; @@ -4702,7 +3865,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. */ @@ -4719,14 +3882,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); } @@ -4753,16 +3914,6 @@ 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); @@ -4802,8 +3953,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; @@ -4847,7 +3998,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 @@ -4888,7 +4045,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) @@ -4921,7 +4078,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) @@ -4950,8 +4107,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); @@ -4964,28 +4119,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 @@ -5011,21 +4165,14 @@ 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) { @@ -5068,13 +4215,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) { @@ -5184,8 +4331,6 @@ return 1; } - oscar_set_status_icq(purple_connection_get_account(gc)); - return 1; } @@ -5226,12 +4371,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); @@ -5244,110 +4391,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) { @@ -5356,13 +4502,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) { @@ -5371,14 +4511,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) { @@ -5420,13 +4553,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); @@ -5435,12 +4562,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); @@ -5448,11 +4573,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); @@ -5484,7 +4609,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 */ @@ -5546,7 +4677,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 */ @@ -5595,15 +4726,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); @@ -5698,24 +4821,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); @@ -5725,16 +4842,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; } @@ -5907,9 +5015,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; @@ -5925,7 +5033,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" @@ -5941,10 +5049,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); @@ -5955,12 +5064,14 @@ message, buf2); } +#if 0 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"; +#endif aim_chat_send_im(od, c->conn, 0, buf2, len, charsetstr, "JA"); g_free(buf2); g_free(buf); @@ -6115,7 +5226,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); } @@ -6132,67 +5243,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 * @@ -6484,7 +5568,7 @@ peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL); /* OSCAR_DISCONNECT_LOCAL_CLOSED doesn't write anything to the convo - * window. Let the user know that we canceled the Direct IM. */ + * window. Let the user know that we cancelled the Direct IM. */ conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name); purple_conversation_write(conv, NULL, _("You closed the connection."), PURPLE_MESSAGE_SYSTEM, time(NULL)); @@ -6524,7 +5608,6 @@ static GList * oscar_buddy_menu(PurpleBuddy *buddy) { - PurpleConnection *gc; OscarData *od; GList *menu; @@ -6562,6 +5645,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 && @@ -6587,15 +5671,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) @@ -6609,7 +5684,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); } @@ -6646,7 +5721,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); } @@ -6761,41 +5836,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)<br>", text, bname, alias); - else - tmp = g_strdup_printf("%s %s<br>", 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(_("<i>you are not waiting for authorization</i>")); - } + } + + 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 " @@ -7010,6 +6073,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 { @@ -7039,12 +6108,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;
--- a/libpurple/protocols/oscar/oscar.h Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/oscar.h Wed Sep 22 14:17:09 2010 +0900 @@ -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 */ @@ -839,30 +619,6 @@ #define AIM_CHARSET_QUIRKUTF8 0x000d /* iChat and AIM6 use this in the meaning of UTF-8 in ODC. --yaz */ /* - * 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. @@ -870,84 +626,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 */ @@ -982,10 +693,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; @@ -997,11 +706,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 */ @@ -1018,7 +722,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); @@ -1027,38 +730,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 @@ -1131,22 +819,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); @@ -1154,10 +828,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); @@ -1172,25 +842,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; @@ -1206,41 +862,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 */ @@ -1256,15 +881,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 @@ -1291,11 +910,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); @@ -1312,49 +929,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 { @@ -1411,22 +1001,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); @@ -1566,17 +1151,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; @@ -1618,11 +1199,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); @@ -1631,15 +1208,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); @@ -1648,18 +1224,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); @@ -1694,7 +1270,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; @@ -1721,13 +1297,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
--- a/libpurple/protocols/oscar/oscar_data.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/oscar_data.c Wed Sep 22 14:17:09 2010 +0900 @@ -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);
--- a/libpurple/protocols/oscar/oscarcommon.h Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/oscarcommon.h Wed Sep 22 14:17:09 2010 +0900 @@ -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);
--- a/libpurple/protocols/oscar/peer_proxy.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/peer_proxy.c Wed Sep 22 14:17:09 2010 +0900 @@ -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;
--- a/libpurple/protocols/oscar/rxhandlers.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/rxhandlers.c Wed Sep 22 14:17:09 2010 +0900 @@ -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
--- a/libpurple/protocols/oscar/snac.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/snac.c Wed Sep 22 14:17:09 2010 +0900 @@ -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;
--- a/libpurple/protocols/oscar/tlv.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/tlv.c Wed Sep 22 14:17:09 2010 +0900 @@ -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 */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/oscar/userinfo.c Wed Sep 22 14:17:09 2010 +0900 @@ -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("<a href=\"%s%s\">%s</a>", 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("<a href=\"%s\">%s</a>", + 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("<a href=\"%s/%s\">%s</a>", + 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
--- a/libpurple/protocols/oscar/util.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/oscar/util.c Wed Sep 22 14:17:09 2010 +0900 @@ -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("<i>%s</i>", 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, "<br>"); + } + return g_string_free(result, FALSE); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/oscar/visibility.c Wed Sep 22 14:17:09 2010 +0900 @@ -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); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/oscar/visibility.h Wed Sep 22 14:17:09 2010 +0900 @@ -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
--- a/libpurple/protocols/qq/ChangeLog Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/ChangeLog Wed Sep 22 14:17:09 2010 +0900 @@ -233,7 +233,7 @@ 2008.08.06 - ccpaging <ccpaging(at)gmail.com> * Rename names of variables, Group, to Room * Functions of group_network merged into qq_network and qq_process - * Canceled managing glist of group packet, add sub_cmdd and room_id to transaction + * Cancelled managing glist of group packet, add sub_cmdd and room_id to transaction * Fixed error of demo group: If 'room list' and 'room infor' are not setup, response received from server will emits 'room_id = 0' packet.
--- a/libpurple/protocols/qq/buddy_info.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/buddy_info.c Wed Sep 22 14:17:09 2010 +0900 @@ -224,12 +224,10 @@ void qq_request_buddy_info(PurpleConnection *gc, guint32 uid, guint32 update_class, int action) { - qq_data *qd; gchar raw_data[16] = {0}; g_return_if_fail(uid != 0); - qd = (qq_data *) gc->proto_data; g_snprintf(raw_data, sizeof(raw_data), "%u", uid); qq_send_cmd_mess(gc, QQ_CMD_GET_BUDDY_INFO, (guint8 *) raw_data, strlen(raw_data), update_class, action); @@ -271,7 +269,6 @@ static void info_modify_ok_cb(modify_info_request *info_request, PurpleRequestFields *fields) { PurpleConnection *gc; - qq_data *qd; gchar **segments; int index; const char *utf8_str; @@ -279,8 +276,7 @@ int choice_num; gc = info_request->gc; - g_return_if_fail(gc != NULL && info_request->gc); - qd = (qq_data *) gc->proto_data; + g_return_if_fail(gc != NULL); segments = info_request->segments; g_return_if_fail(segments != NULL); @@ -390,14 +386,12 @@ static void info_modify_dialogue(PurpleConnection *gc, gchar **segments, int iclass) { - qq_data *qd; PurpleRequestFieldGroup *group; PurpleRequestFields *fields; modify_info_request *info_request; gchar *utf8_title, *utf8_prim; int index; - qd = (qq_data *) gc->proto_data; /* Keep one dialog once a time */ purple_request_close_with_handle(gc); @@ -416,9 +410,11 @@ case QQ_FIELD_CONTACT: utf8_title = g_strdup(_("Modify Contact")); utf8_prim = g_strdup_printf("%s for %s", _("Modify Contact"), segments[0]); + break; case QQ_FIELD_ADDR: utf8_title = g_strdup(_("Modify Address")); utf8_prim = g_strdup_printf("%s for %s", _("Modify Address"), segments[0]); + break; case QQ_FIELD_EXT: utf8_title = g_strdup(_("Modify Extended Information")); utf8_prim = g_strdup_printf("%s for %s", _("Modify Extended Information"), segments[0]); @@ -427,6 +423,7 @@ default: utf8_title = g_strdup(_("Modify Information")); utf8_prim = g_strdup_printf("%s for %s", _("Modify Information"), segments[0]); + break; } info_request = g_new0(modify_info_request, 1);
--- a/libpurple/protocols/qq/buddy_list.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/buddy_list.c Wed Sep 22 14:17:09 2010 +0900 @@ -55,11 +55,9 @@ /* get a list of online_buddies */ void qq_request_get_buddies_online(PurpleConnection *gc, guint8 position, guint32 update_class) { - qq_data *qd; guint8 *raw_data; gint bytes = 0; - qd = (qq_data *) gc->proto_data; raw_data = g_newa(guint8, 5); /* 000-000 get online friends cmd @@ -360,7 +358,6 @@ guint32 qq_process_get_buddies_and_rooms(guint8 *data, gint data_len, PurpleConnection *gc) { - qq_data *qd; gint i, j; gint bytes; guint8 sub_cmd, reply_code; @@ -371,8 +368,6 @@ g_return_val_if_fail(data != NULL && data_len != 0, -1); - qd = (qq_data *) gc->proto_data; - bytes = 0; bytes += qq_get8(&sub_cmd, data + bytes); g_return_val_if_fail(sub_cmd == 0x01, -1); @@ -468,11 +463,6 @@ guint8 away_cmd; guint32 misc_status; gboolean fake_video; - PurpleAccount *account; - PurplePresence *presence; - - account = purple_connection_get_account(gc); - presence = purple_account_get_presence(account); qd = (qq_data *) gc->proto_data; if (!qd->is_login) @@ -596,14 +586,13 @@ void qq_update_buddy_status(PurpleConnection *gc, guint32 uid, guint8 status, guint8 flag) { gchar *who; - gchar *status_id; + const gchar *status_id; g_return_if_fail(uid != 0); /* purple supports signon and idle time * but it is not much use for QQ, I do not use them */ /* serv_got_update(gc, name, online, 0, q_bud->signon, q_bud->idle, bud->uc); */ - status_id = "available"; switch(status) { case QQ_BUDDY_OFFLINE: status_id = "offline"; @@ -677,13 +666,10 @@ void qq_buddy_data_free_all(PurpleConnection *gc) { - qq_data *qd; PurpleBuddy *buddy; GSList *buddies, *it; gint count = 0; - qd = (qq_data *)purple_connection_get_protocol_data(gc); - buddies = purple_find_buddies(purple_connection_get_account(gc), NULL); for (it = buddies; it; it = it->next) { qq_buddy_data *qbd = NULL;
--- a/libpurple/protocols/qq/buddy_opt.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/buddy_opt.c Wed Sep 22 14:17:09 2010 +0900 @@ -262,7 +262,6 @@ void qq_process_auth_code(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid) { - qq_data *qd; gint bytes; guint8 cmd, reply; guint16 sub_cmd; @@ -272,8 +271,6 @@ g_return_if_fail(data != NULL && data_len != 0); g_return_if_fail(uid != 0); - qd = (qq_data *) gc->proto_data; - qq_show_packet("qq_process_auth_code", data, data_len); bytes = 0; bytes += qq_get8(&cmd, data + bytes); @@ -324,7 +321,7 @@ add_req->auth_len = 0; who = uid_to_purple_name(uid); - msg = g_strdup_printf(_("%u requires verification"), uid); + msg = g_strdup_printf(_("%u requires verification: %s"), uid, question); purple_request_input(gc, _("Add buddy question"), msg, _("Enter answer here"), NULL, @@ -400,7 +397,6 @@ void qq_process_question(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid) { - qq_data *qd; gint bytes; guint8 cmd, reply; gchar *question, *answer; @@ -409,8 +405,6 @@ g_return_if_fail(data != NULL && data_len != 0); - qd = (qq_data *) gc->proto_data; - qq_show_packet("qq_process_question", data, data_len); bytes = 0; bytes += qq_get8(&cmd, data + bytes); @@ -720,13 +714,10 @@ /* process reply to add_buddy_auth request */ void qq_process_add_buddy_auth(guint8 *data, gint data_len, PurpleConnection *gc) { - qq_data *qd; gchar **segments, *msg_utf8; g_return_if_fail(data != NULL && data_len != 0); - qd = (qq_data *) gc->proto_data; - if (data[0] == '0') { purple_debug_info("QQ", "Reply OK for sending authorize\n"); return; @@ -767,11 +758,9 @@ /* process the server reply for my request to remove myself from a buddy */ void qq_process_buddy_remove_me(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid) { - qq_data *qd; gchar *msg; g_return_if_fail(data != NULL && data_len != 0); - qd = (qq_data *) gc->proto_data; if (data[0] == 0) { purple_debug_info("QQ", "Reply OK for removing me from %u's buddy list\n", uid); @@ -1004,7 +993,6 @@ void qq_process_buddy_check_code(PurpleConnection *gc, guint8 *data, gint data_len) { - qq_data *qd; gint bytes; guint8 cmd; guint8 reply; @@ -1013,8 +1001,6 @@ g_return_if_fail(data != NULL && data_len >= 5); - qd = (qq_data *) gc->proto_data; - qq_show_packet("buddy_check_code", data, data_len); bytes = 0;
--- a/libpurple/protocols/qq/char_conv.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/char_conv.c Wed Sep 22 14:17:09 2010 +0900 @@ -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); }
--- a/libpurple/protocols/qq/file_trans.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/file_trans.c Wed Sep 22 14:17:09 2010 +0900 @@ -238,12 +238,9 @@ gint bytes = 0; guint32 file_key; qq_data *qd; - ft_info *info; qd = (qq_data *) gc->proto_data; - info = (ft_info *) qd->xfer->data; - raw_data = g_newa(guint8, MAX_PACKET_SIZE); file_key = _gen_file_key(); @@ -805,9 +802,6 @@ { gint bytes; guint8 tag; - qq_data *qd; - - qd = (qq_data *) gc->proto_data; bytes = 0; bytes += qq_get8(&tag, data + bytes);
--- a/libpurple/protocols/qq/group.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/group.c Wed Sep 22 14:17:09 2010 +0900 @@ -119,13 +119,11 @@ /* free roomlist space, I have no idea when this one is called... */ void qq_roomlist_cancel(PurpleRoomlist *list) { - qq_data *qd; PurpleConnection *gc; g_return_if_fail(list != NULL); gc = purple_account_get_connection(list->account); - qd = (qq_data *) gc->proto_data; purple_roomlist_set_in_progress(list, FALSE); purple_roomlist_unref(list); }
--- a/libpurple/protocols/qq/group_im.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/group_im.c Wed Sep 22 14:17:09 2010 +0900 @@ -48,12 +48,10 @@ PurpleConversation *qq_room_conv_open(PurpleConnection *gc, qq_room_data *rmd) { PurpleConversation *conv; - qq_data *qd; gchar *topic_utf8; g_return_val_if_fail(rmd != NULL, NULL); g_return_val_if_fail(rmd->title_utf8, NULL); - qd = (qq_data *) gc->proto_data; conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, rmd->title_utf8, purple_connection_get_account(gc)); @@ -207,7 +205,6 @@ /* recv an IM from a group chat */ void qq_process_room_im(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 msg_type) { - qq_data *qd; gchar *msg_smiley, *msg_fmt, *msg_utf8; gint bytes, tail_len; struct { @@ -229,7 +226,6 @@ /* at least include im_text.msg_len */ g_return_if_fail(data != NULL && data_len > 23); - qd = (qq_data *) gc->proto_data; /* qq_show_packet("ROOM_IM", data, data_len); */ memset(&im_text, 0, sizeof(im_text)); @@ -376,7 +372,6 @@ gint msg_len; const gchar *start_invalid; gboolean is_smiley_none; - guint8 frag_count, frag_index; g_return_val_if_fail(NULL != gc && NULL != gc->proto_data, -1); g_return_val_if_fail(id != 0 && what != NULL, -1); @@ -386,9 +381,6 @@ /* qq_show_packet("chat IM UTF8", (guint8 *)what, strlen(what)); */ - fmt = qq_im_fmt_new_by_purple(what); - is_smiley_none = qq_im_smiley_none(what); - msg_stripped = purple_markup_strip_html(what); g_return_val_if_fail(msg_stripped != NULL, -1); /* qq_show_packet("IM Stripped", (guint8 *)what, strlen(what)); */ @@ -417,26 +409,10 @@ qd->send_im_id++; fmt = qq_im_fmt_new_by_purple(what); - frag_count = g_slist_length(segments); - frag_index = 0; -/* - if (frag_count <= 1) { -*/ - for (it = segments; it; it = it->next) { - request_room_send_im(gc, id, fmt, (gchar *)it->data); - g_free(it->data); - } -/* - } else { - for (it = segments; it; it = it->next) { - request_room_send_im_ex(gc, id, fmt, (gchar *)it->data, - qd->send_im_id, frag_count, frag_index); - g_free(it->data); - frag_index++; - } + for (it = segments; it; it = g_slist_delete_link(it, it)) { + request_room_send_im(gc, id, fmt, (gchar *)it->data); + g_free(it->data); } -*/ qq_im_fmt_free(fmt); - g_slist_free(segments); return 1; }
--- a/libpurple/protocols/qq/group_join.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/group_join.c Wed Sep 22 14:17:09 2010 +0900 @@ -178,12 +178,10 @@ /* If comes here, cmd is OK already */ void qq_process_group_cmd_exit_group(guint8 *data, gint len, PurpleConnection *gc) { - qq_data *qd; gint bytes; guint32 id; g_return_if_fail(data != NULL && len > 0); - qd = (qq_data *) gc->proto_data; if (len < 4) { purple_debug_error("QQ", "Invalid exit group reply, expect %d bytes, read %d bytes\n", 4, len); @@ -201,12 +199,10 @@ { gint bytes; guint32 id; - qq_data *qd; qq_room_data *rmd; gchar *msg; g_return_if_fail(data != NULL && len > 0); - qd = (qq_data *) gc->proto_data; if (len < 4) { purple_debug_error("QQ", @@ -283,7 +279,6 @@ /* Attempt to join a group without auth */ void qq_group_join(PurpleConnection *gc, GHashTable *data) { - qq_data *qd; gchar *ext_id_str; gchar *id_str; guint32 ext_id; @@ -291,7 +286,6 @@ qq_room_data *rmd; g_return_if_fail(data != NULL); - qd = (qq_data *) gc->proto_data; ext_id_str = g_hash_table_lookup(data, QQ_ROOM_KEY_EXTERNAL_ID); id_str = g_hash_table_lookup(data, QQ_ROOM_KEY_INTERNAL_ID);
--- a/libpurple/protocols/qq/group_opt.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/group_opt.c Wed Sep 22 14:17:09 2010 +0900 @@ -134,12 +134,10 @@ { guint32 *old_members, *del_members, *add_members; qq_buddy_data *bd; - qq_data *qd; gint i = 0, old = 0, new = 0, del = 0, add = 0; GList *list; g_return_if_fail(rmd != NULL); - qd = (qq_data *) gc->proto_data; if (new_members[0] == 0xffffffff) return;
--- a/libpurple/protocols/qq/im.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/im.c Wed Sep 22 14:17:09 2010 +0900 @@ -725,7 +725,6 @@ /* process received normal text IM */ static void process_im_text(PurpleConnection *gc, guint8 *data, gint len, qq_im_header *im_header) { - qq_data *qd; guint16 purple_msg_type; gchar *who; gchar *msg_smiley, *msg_fmt, *msg_utf8; @@ -749,10 +748,9 @@ gchar *msg; /* no fixed length, ends with 0x00 */ } im_text; - g_return_if_fail (data != NULL && len > 0); + g_return_if_fail(data != NULL && len > 0); g_return_if_fail(im_header != NULL); - qd = (qq_data *) gc->proto_data; memset(&im_text, 0, sizeof(im_text)); /* qq_show_packet("IM text", data, len); */ @@ -823,7 +821,6 @@ /* process received extended (2007) text IM */ static void process_extend_im_text(PurpleConnection *gc, guint8 *data, gint len, qq_im_header *im_header) { - qq_data *qd; guint16 purple_msg_type; gchar *who; gchar *msg_smiley, *msg_fmt, *msg_utf8; @@ -848,10 +845,9 @@ guint8 fromMobileQQ; } im_text; - g_return_if_fail (data != NULL && len > 0); + g_return_if_fail(data != NULL && len > 0); g_return_if_fail(im_header != NULL); - qd = (qq_data *) gc->proto_data; memset(&im_text, 0, sizeof(im_text)); /* qq_show_packet("Extend IM text", data, len); */ @@ -1043,12 +1039,10 @@ { qq_data *qd; guint8 raw_data[MAX_PACKET_SIZE - 16]; - guint16 im_type; gint bytes; time_t now; qd = (qq_data *) gc->proto_data; - im_type = QQ_NORMAL_IM_TEXT; /* purple_debug_info("QQ", "Send IM %d-%d\n", frag_count, frag_index); */ bytes = 0; @@ -1118,13 +1112,12 @@ GString *new_string; GString *append_utf8; gchar *start, *p; - gint count, len; + gint len; qq_emoticon *emoticon; g_return_val_if_fail(msg_stripped != NULL, NULL); start = msg_stripped; - count = 0; new_string = g_string_new(""); append_utf8 = g_string_new(""); while (*start) {
--- a/libpurple/protocols/qq/qq.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/qq.c Wed Sep 22 14:17:09 2010 +0900 @@ -89,15 +89,12 @@ { PurpleConnection *gc; qq_data *qd; - PurpleProxyInfo *gpi; const gchar *custom_server; gc = purple_account_get_connection(account); g_return_if_fail(gc != NULL && gc->proto_data != NULL); qd = gc->proto_data; - gpi = purple_proxy_get_setup(account); - qd->use_tcp = purple_account_get_bool(account, "use_tcp", TRUE); custom_server = purple_account_get_string(account, "server", NULL); @@ -381,13 +378,10 @@ static const char *qq_list_emblem(PurpleBuddy *b) { 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))) + !purple_account_get_connection(account)) return NULL; buddy = purple_buddy_get_protocol_data(b); @@ -620,12 +614,10 @@ static void action_about_openq(PurplePluginAction *action) { PurpleConnection *gc = (PurpleConnection *) action->context; - qq_data *qd; GString *info; gchar *title; - g_return_if_fail(NULL != gc && NULL != gc->proto_data); - qd = (qq_data *) gc->proto_data; + g_return_if_fail(NULL != gc); info = g_string_new("<html><body>"); g_string_append(info, _("<p><b>Original Author</b>:<br>\n"));
--- a/libpurple/protocols/qq/qq_base.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/qq_base.c Wed Sep 22 14:17:09 2010 +0900 @@ -386,7 +386,6 @@ /* process the login reply packet */ guint8 qq_process_login( PurpleConnection *gc, guint8 *data, gint data_len) { - qq_data *qd; guint8 ret = data[0]; gchar *msg, *msg_utf8; gchar *error; @@ -394,8 +393,6 @@ g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR); - qd = (qq_data *) gc->proto_data; - switch (ret) { case QQ_LOGIN_REPLY_OK: purple_debug_info("QQ", "Login OK\n");
--- a/libpurple/protocols/qq/qq_network.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/qq_network.c Wed Sep 22 14:17:09 2010 +0900 @@ -482,13 +482,11 @@ static void udp_pending(gpointer data, gint source, PurpleInputCondition cond) { PurpleConnection *gc = NULL; - qq_data *qd; guint8 *buf; gint buf_len; gc = (PurpleConnection *) data; - g_return_if_fail(gc != NULL && gc->proto_data != NULL); - qd = (qq_data *) gc->proto_data; + g_return_if_fail(gc != NULL); if(cond != PURPLE_INPUT_READ) { purple_connection_error_reason(gc, @@ -748,14 +746,12 @@ { PurpleConnection *gc; qq_data *qd; - PurpleAccount *account ; qq_connection *conn; gc = (PurpleConnection *) data; g_return_if_fail(gc != NULL && gc->proto_data != NULL); qd = (qq_data *) gc->proto_data; - account = purple_connection_get_account(gc); /* conn_data will be destoryed */ qd->conn_data = NULL;
--- a/libpurple/protocols/qq/qq_process.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/qq_process.c Wed Sep 22 14:17:09 2010 +0900 @@ -58,15 +58,12 @@ /* default process, decrypt and dump */ static void process_unknow_cmd(PurpleConnection *gc,const gchar *title, guint8 *data, gint data_len, guint16 cmd, guint16 seq) { - qq_data *qd; gchar *msg; g_return_if_fail(data != NULL && data_len != 0); qq_show_packet(title, data, data_len); - qd = (qq_data *) gc->proto_data; - qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len, ">>> [%d] %s -> [default] decrypt and dump", @@ -80,12 +77,8 @@ /* parse the reply to send_im */ static void do_im_ack(guint8 *data, gint data_len, PurpleConnection *gc) { - qq_data *qd; - g_return_if_fail(data != NULL && data_len != 0); - qd = gc->proto_data; - if (data[0] != 0) { purple_debug_warning("QQ", "Failed sent IM\n"); purple_notify_error(gc, _("Error"), _("Unable to send message."), NULL); @@ -380,14 +373,11 @@ /* Send ACK if the sys message needs an ACK */ static void request_server_ack(PurpleConnection *gc, gchar *funct_str, gchar *from, guint16 seq) { - qq_data *qd; guint8 *raw_data; gint bytes; guint8 bar; g_return_if_fail(funct_str != NULL && from != NULL); - qd = (qq_data *) gc->proto_data; - bar = 0x1e; raw_data = g_newa(guint8, strlen(funct_str) + strlen(from) + 16); @@ -568,11 +558,9 @@ void qq_update_room(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) { - qq_data *qd; gint ret; - g_return_if_fail (gc != NULL && gc->proto_data != NULL); - qd = (qq_data *) gc->proto_data; + g_return_if_fail (gc != NULL); switch (room_cmd) { case 0: @@ -599,12 +587,10 @@ void qq_update_all_rooms(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) { - qq_data *qd; gboolean is_new_turn = FALSE; guint32 next_id; - g_return_if_fail (gc != NULL && gc->proto_data != NULL); - qd = (qq_data *) gc->proto_data; + g_return_if_fail(gc != NULL); next_id = qq_room_get_next(gc, room_id); purple_debug_info("QQ", "Update rooms, next id %u, prev id %u\n", next_id, room_id); @@ -689,11 +675,9 @@ static void update_all_rooms_online(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) { - qq_data *qd; guint32 next_id; - g_return_if_fail (gc != NULL && gc->proto_data != NULL); - qd = (qq_data *) gc->proto_data; + g_return_if_fail (gc != NULL); next_id = qq_room_get_next_conv(gc, room_id); if (next_id <= 0 && room_id <= 0) {
--- a/libpurple/protocols/qq/qq_trans.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/qq_trans.c Wed Sep 22 14:17:09 2010 +0900 @@ -109,11 +109,9 @@ static qq_transaction *trans_create(PurpleConnection *gc, gint fd, guint16 cmd, guint16 seq, guint8 *data, gint data_len, guint32 update_class, guint32 ship32) { - qq_data *qd; qq_transaction *trans; - g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, NULL); - qd = (qq_data *) gc->proto_data; + g_return_val_if_fail(gc != NULL, NULL); trans = g_new0(qq_transaction, 1); @@ -138,10 +136,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
--- a/libpurple/protocols/qq/send_file.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/qq/send_file.c Wed Sep 22 14:17:09 2010 +0900 @@ -637,10 +637,8 @@ { PurpleConnection *gc; PurpleAccount *account; - guint16 *seq; g_return_if_fail (xfer != NULL); - seq = (guint16 *) xfer->data; account = purple_xfer_get_account(xfer); gc = purple_account_get_connection(account); @@ -670,10 +668,8 @@ { PurpleConnection *gc; PurpleAccount *account; - ft_info *info; - g_return_if_fail (xfer != NULL && xfer->data != NULL); - info = (ft_info *) xfer->data; + g_return_if_fail(xfer != NULL); account = purple_xfer_get_account(xfer); gc = purple_account_get_connection(account); @@ -752,7 +748,7 @@ g_return_if_fail (data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; xfer = qd->xfer; - info = (ft_info *) qd->xfer->data; + info = (ft_info *) xfer->data; if (data_len <= 30 + QQ_CONN_INFO_LEN) { purple_debug_warning("QQ", "Received file reject message is empty\n"); @@ -761,7 +757,7 @@ bytes = 18 + 12; /* skip 30 bytes */ qq_get_conn_info(info, data + bytes); - _qq_xfer_init_socket(qd->xfer); + _qq_xfer_init_socket(xfer); _qq_xfer_init_udp_channel(info); _qq_send_packet_file_notifyip(gc, sender_uid);
--- a/libpurple/protocols/sametime/sametime.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/sametime/sametime.c Wed Sep 22 14:17:09 2010 +0900 @@ -2133,7 +2133,7 @@ static void ft_incoming_cancel(PurpleXfer *xfer) { - /* incoming transfer rejected or canceled in-progress */ + /* incoming transfer rejected or cancelled in-progress */ struct mwFileTransfer *ft = xfer->data; if(ft) mwFileTransfer_reject(ft); }
--- a/libpurple/protocols/silc/chat.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/silc/chat.c Wed Sep 22 14:17:09 2010 +0900 @@ -1395,7 +1395,7 @@ if (sg->roomlist) purple_roomlist_unref(sg->roomlist); - sg->roomlist_canceled = FALSE; + sg->roomlist_cancelled = FALSE; sg->roomlist = purple_roomlist_new(purple_connection_get_account(gc)); f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", "channel", TRUE); @@ -1429,6 +1429,6 @@ if (sg->roomlist == list) { purple_roomlist_unref(sg->roomlist); sg->roomlist = NULL; - sg->roomlist_canceled = TRUE; + sg->roomlist_cancelled = TRUE; } }
--- a/libpurple/protocols/silc/ops.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/silc/ops.c Wed Sep 22 14:17:09 2010 +0900 @@ -1455,7 +1455,7 @@ int usercount; PurpleRoomlistRoom *room; - if (sg->roomlist_canceled) + if (sg->roomlist_cancelled) break; if (error != SILC_STATUS_OK) {
--- a/libpurple/protocols/silc/silcpurple.h Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/silc/silcpurple.h Wed Sep 22 14:17:09 2010 +0900 @@ -85,7 +85,7 @@ SilcMimeAssembler mimeass; unsigned int detaching : 1; unsigned int resuming : 1; - unsigned int roomlist_canceled : 1; + unsigned int roomlist_cancelled : 1; unsigned int chpk : 1; } *SilcPurple;
--- a/libpurple/protocols/silc10/chat.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/silc10/chat.c Wed Sep 22 14:17:09 2010 +0900 @@ -1417,7 +1417,7 @@ if (sg->roomlist) purple_roomlist_unref(sg->roomlist); - sg->roomlist_canceled = FALSE; + sg->roomlist_cancelled = FALSE; sg->roomlist = purple_roomlist_new(purple_connection_get_account(gc)); f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", "channel", TRUE); @@ -1451,6 +1451,6 @@ if (sg->roomlist == list) { purple_roomlist_unref(sg->roomlist); sg->roomlist = NULL; - sg->roomlist_canceled = TRUE; + sg->roomlist_cancelled = TRUE; } }
--- a/libpurple/protocols/silc10/ops.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/silc10/ops.c Wed Sep 22 14:17:09 2010 +0900 @@ -1444,7 +1444,7 @@ int usercount; PurpleRoomlistRoom *room; - if (sg->roomlist_canceled) + if (sg->roomlist_cancelled) break; if (!success) {
--- a/libpurple/protocols/silc10/silcpurple.h Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/silc10/silcpurple.h Wed Sep 22 14:17:09 2010 +0900 @@ -80,7 +80,7 @@ #endif unsigned int detaching : 1; unsigned int resuming : 1; - unsigned int roomlist_canceled : 1; + unsigned int roomlist_cancelled : 1; unsigned int chpk : 1; } *SilcPurple;
--- a/libpurple/protocols/yahoo/libymsg.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/yahoo/libymsg.c Wed Sep 22 14:17:09 2010 +0900 @@ -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); @@ -3812,13 +3812,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)); @@ -3913,7 +3912,6 @@ PurpleBuddy *buddy; PurpleConnection *gc; - YahooData *yd; const char *game; char *game2; char *t; @@ -3924,7 +3922,6 @@ buddy = (PurpleBuddy *) node; gc = purple_account_get_connection(purple_buddy_get_account(buddy)); - yd = (YahooData *) gc->proto_data; f = yahoo_friend_find(gc, purple_buddy_get_name(buddy)); if (!f) @@ -4949,7 +4946,6 @@ struct yahoo_packet *pkt; const char *group = NULL; char *group2; - YahooFriend *f; const char *bname; const char *fed_bname; YahooFederation fed = YAHOO_FEDERATION_NONE; @@ -4961,7 +4957,6 @@ if (!purple_privacy_check(purple_connection_get_account(gc), bname)) return; - f = yahoo_friend_find(gc, bname); fed = yahoo_get_federation_from_name(bname); if (fed != YAHOO_FEDERATION_NONE) fed_bname += 4; @@ -5224,15 +5219,11 @@ { GHashTable *comp; PurpleConnection *gc; - YahooData *yd; - int id; if (!args || !args[0]) return PURPLE_CMD_RET_FAILED; gc = purple_conversation_get_gc(conv); - yd = gc->proto_data; - id = yd->conf_id; purple_debug_info("yahoo", "Trying to join %s \n", args[0]); comp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
--- a/libpurple/protocols/yahoo/util.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/yahoo/util.c Wed Sep 22 14:17:09 2010 +0900 @@ -44,7 +44,7 @@ if(proxy_ssl) ppi = purple_proxy_get_setup(account); else - ppi = purple_global_proxy_get_info(); + ppi = purple_proxy_get_setup(NULL); type = purple_proxy_info_get_type(ppi);
--- a/libpurple/protocols/yahoo/yahoo_aliases.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/yahoo/yahoo_aliases.c Wed Sep 22 14:17:09 2010 +0900 @@ -145,7 +145,7 @@ if (alias != NULL) { serv_got_alias(gc, yid, alias); purple_debug_info("yahoo", "Fetched alias '%s' (%s)\n", alias, id); - } else if (buddy_alias != NULL && strcmp(buddy_alias, "") != 0) { + } else if (buddy_alias && *buddy_alias && !g_str_equal(buddy_alias, yid)) { /* Or if we have an alias that Yahoo doesn't, send it up */ yahoo_update_alias(gc, yid, buddy_alias); purple_debug_info("yahoo", "Sent updated alias '%s'\n", buddy_alias);
--- a/libpurple/protocols/yahoo/yahoo_doodle.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/yahoo/yahoo_doodle.c Wed Sep 22 14:17:09 2010 +0900 @@ -372,7 +372,7 @@ /* TODO Ask if user wants to save picture before the session is closed */ - wb->state = DOODLE_STATE_CANCELED; + wb->state = DOODLE_STATE_CANCELLED; purple_whiteboard_destroy(wb); } @@ -460,7 +460,7 @@ /* g_debug_debug("yahoo", "doodle: yahoo_doodle_end()\n"); */ - if (gc && wb->state != DOODLE_STATE_CANCELED) + if (gc && wb->state != DOODLE_STATE_CANCELLED) yahoo_doodle_command_send_shutdown(gc, wb->who); g_free(ds->imv_key);
--- a/libpurple/protocols/yahoo/yahoo_doodle.h Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/yahoo/yahoo_doodle.h Wed Sep 22 14:17:09 2010 +0900 @@ -56,7 +56,7 @@ #define DOODLE_STATE_REQUESTING 0 #define DOODLE_STATE_REQUESTED 1 #define DOODLE_STATE_ESTABLISHED 2 -#define DOODLE_STATE_CANCELED 3 +#define DOODLE_STATE_CANCELLED 3 /* Doodle canvas dimensions */ #define DOODLE_CANVAS_WIDTH 368
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/yahoo/yahoo_filexfer.c Wed Sep 22 14:17:09 2010 +0900 @@ -1240,14 +1240,14 @@ PurpleXfer *xfer; struct yahoo_xfer_data *xd; PurpleAccount *account; - YahooData* yd; + PurpleConnection *gc; if (!(xfer = data)) return; if (!(xd = xfer->data)) return; - yd = xd->gc->proto_data; - account = purple_connection_get_account(xd->gc); + gc = xd->gc; + account = purple_connection_get_account(gc); if ((source < 0) || (xd->path == NULL) || (xd->host == NULL)) { purple_xfer_error(PURPLE_XFER_RECEIVE, purple_xfer_get_account(xfer), xfer->who, _("Unable to connect.")); @@ -1258,7 +1258,14 @@ if (xd->txbuflen == 0) { gchar* cookies; - cookies = yahoo_get_cookies(xd->gc); + YahooData *yd = gc->proto_data; + + /* cookies = yahoo_get_cookies(gc); + * This doesn't seem to be working. The function is returning NULL, which yahoo servers don't like + * For now let us not use this function */ + + cookies = g_strdup_printf("Y=%s; T=%s", yd->cookie_y, yd->cookie_t); + if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && xd->status_15 == ACCEPTED) { if(xd->info_val_249 == 2)
--- a/libpurple/protocols/yahoo/yahoochat.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/protocols/yahoo/yahoochat.c Wed Sep 22 14:17:09 2010 +0900 @@ -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 ? */ @@ -618,9 +617,6 @@ char *who = NULL; char *room = NULL; GSList *l; - YahooData *yd; - - yd = gc->proto_data; for (l = pkt->hash; l; l = l->next) { struct yahoo_pair *pair = l->data; @@ -639,8 +635,7 @@ purple_conv_chat_remove_user(PURPLE_CONV_CHAT(c), who, NULL); } - if (room) - g_free(room); + g_free(room); } void yahoo_process_chat_message(PurpleConnection *gc, struct yahoo_packet *pkt) @@ -880,7 +875,6 @@ { YahooData *yd = gc->proto_data; struct yahoo_packet *pkt; - PurpleConversation *c; char *eroom; gboolean utf8 = 1; @@ -905,7 +899,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)
--- a/libpurple/proxy.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/proxy.c Wed Sep 22 14:17:09 2010 +0900 @@ -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;
--- a/libpurple/purple-remote Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/purple-remote Wed Sep 22 14:17:09 2010 +0900 @@ -1,5 +1,6 @@ #!/usr/bin/env python +import codecs import dbus import re import urllib @@ -7,6 +8,9 @@ import xml.dom.minidom +sys.stdin = codecs.getwriter('utf-8')(sys.stdin); +sys.stdout = codecs.getwriter('utf-8')(sys.stdout); + xml.dom.minidom.Element.all = xml.dom.minidom.Element.getElementsByTagName obj = None
--- a/libpurple/request.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/request.c Wed Sep 22 14:17:09 2010 +0900 @@ -1399,6 +1399,11 @@ handles = g_list_append(handles, info); return info->ui_handle; + } else { + /* Fall back on the non-icon request if the UI doesn't support icon + requests */ + return purple_request_action_varg(handle, title, primary, secondary, + default_action, account, who, conv, user_data, action_count, actions); } return NULL;
--- a/libpurple/stun.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/stun.c Wed Sep 22 14:17:09 2010 +0900 @@ -105,11 +105,11 @@ } static void do_callbacks(void) { - while(callbacks) { + while (callbacks) { StunCallback cb = callbacks->data; - if(cb) + if (cb) cb(&nattype); - callbacks = g_slist_remove(callbacks, cb); + callbacks = g_slist_delete_link(callbacks, callbacks); } } @@ -280,7 +280,6 @@ GSList *hosts = data; struct stun_conn *sc; static struct stun_header hdr_data; - int ret; if(fd < 0) { nattype.status = PURPLE_STUN_STATUS_UNKNOWN; @@ -298,15 +297,14 @@ sc->incb = purple_input_add(fd, PURPLE_INPUT_READ, reply_cb, sc); - ret = GPOINTER_TO_INT(hosts->data); - hosts = g_slist_remove(hosts, hosts->data); + hosts = g_slist_delete_link(hosts, hosts); memcpy(&(sc->addr), hosts->data, sizeof(struct sockaddr_in)); g_free(hosts->data); - hosts = g_slist_remove(hosts, hosts->data); - while(hosts) { - hosts = g_slist_remove(hosts, hosts->data); + hosts = g_slist_delete_link(hosts, hosts); + while (hosts) { + hosts = g_slist_delete_link(hosts, hosts); g_free(hosts->data); - hosts = g_slist_remove(hosts, hosts->data); + hosts = g_slist_delete_link(hosts, hosts); } hdr_data.type = htons(MSGTYPE_BINDINGREQUEST); @@ -341,10 +339,10 @@ } if (!purple_network_listen_range(12108, 12208, SOCK_DGRAM, hbn_listen_cb, hosts)) { - while(hosts) { - hosts = g_slist_remove(hosts, hosts->data); + while (hosts) { + hosts = g_slist_delete_link(hosts, hosts); g_free(hosts->data); - hosts = g_slist_remove(hosts, hosts->data); + hosts = g_slist_delete_link(hosts, hosts); } nattype.status = PURPLE_STUN_STATUS_UNKNOWN;
--- a/libpurple/util.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/util.c Wed Sep 22 14:17:09 2010 +0900 @@ -2840,6 +2840,10 @@ progname = g_find_program_in_path(argv[0]); is_valid = (progname != NULL); + if(purple_debug_is_verbose()) + purple_debug_info("program_is_valid", "Tested program %s. %s.\n", program, + is_valid ? "Valid" : "Invalid"); + g_strfreev(argv); g_free(progname); @@ -3143,7 +3147,7 @@ if (text[i] != thechar) text[j++] = text[i]; - text[j++] = '\0'; + text[j] = '\0'; } void
--- a/libpurple/win32/global.mak Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/win32/global.mak Wed Sep 22 14:17:09 2010 +0900 @@ -37,7 +37,6 @@ PURPLE_PLUGINS_TOP := $(PURPLE_TOP)/plugins PURPLE_PERL_TOP := $(PURPLE_PLUGINS_TOP)/perl PIDGIN_TOP := $(PIDGIN_TREE_TOP)/pidgin -PIDGIN_IDLETRACK_TOP := $(PIDGIN_TOP)/win32/IdleTracker PIDGIN_PIXMAPS_TOP := $(PIDGIN_TOP)/pixmaps PIDGIN_PLUGINS_TOP := $(PIDGIN_TOP)/plugins PURPLE_PO_TOP := $(PIDGIN_TREE_TOP)/po @@ -48,7 +47,6 @@ PURPLE_CONFIG_H := $(PIDGIN_TREE_TOP)/config.h PIDGIN_REVISION_H := $(PIDGIN_TREE_TOP)/package_revision.h PIDGIN_REVISION_RAW_TXT := $(PIDGIN_TREE_TOP)/package_revision_raw.txt -PIDGIN_IDLETRACK_DLL := $(PIDGIN_IDLETRACK_TOP)/idletrack.dll PURPLE_PURPLE_H := $(PURPLE_TOP)/purple.h PURPLE_VERSION_H := $(PURPLE_TOP)/version.h PURPLE_DLL := $(PURPLE_TOP)/libpurple.dll
--- a/libpurple/win32/libc_interface.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/win32/libc_interface.c Wed Sep 22 14:17:09 2010 +0900 @@ -317,26 +317,26 @@ if (errornum > WSABASEERR) { switch(errornum) { case WSAECONNABORTED: /* 10053 */ - g_snprintf(errbuf, sizeof(errbuf), _("Connection interrupted by other software on your computer.")); + g_snprintf(errbuf, sizeof(errbuf), "%s", _("Connection interrupted by other software on your computer.")); break; case WSAECONNRESET: /* 10054 */ - g_snprintf(errbuf, sizeof(errbuf), _("Remote host closed connection.")); + g_snprintf(errbuf, sizeof(errbuf), "%s", _("Remote host closed connection.")); break; case WSAETIMEDOUT: /* 10060 */ - g_snprintf(errbuf, sizeof(errbuf), _("Connection timed out.")); + g_snprintf(errbuf, sizeof(errbuf), "%s", _("Connection timed out.")); break; case WSAECONNREFUSED: /* 10061 */ - g_snprintf(errbuf, sizeof(errbuf), _("Connection refused.")); + g_snprintf(errbuf, sizeof(errbuf), "%s", _("Connection refused.")); break; case WSAEADDRINUSE: /* 10048 */ - g_snprintf(errbuf, sizeof(errbuf), _("Address already in use.")); + g_snprintf(errbuf, sizeof(errbuf), "%s", _("Address already in use.")); break; default: g_snprintf(errbuf, sizeof(errbuf), "Windows socket error #%d", errornum); } } else { const char *tmp = g_strerror(errornum); - g_snprintf(errbuf, sizeof(errbuf), tmp); + g_snprintf(errbuf, sizeof(errbuf), "%s", tmp); } return errbuf; }
--- a/libpurple/win32/targets.mak Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/win32/targets.mak Wed Sep 22 14:17:09 2010 +0900 @@ -36,9 +36,6 @@ $(PIDGIN_DLL) $(PIDGIN_DLL).a: $(MAKE) -C $(PIDGIN_TOP) -f $(MINGW_MAKEFILE) pidgin.dll -$(PIDGIN_IDLETRACK_DLL) $(PIDGIN_IDLETRACK_DLL).a: - $(MAKE) -C $(PIDGIN_IDLETRACK_TOP) -f $(MINGW_MAKEFILE) idletrack.dll - $(PIDGIN_EXE): $(MAKE) -C $(PIDGIN_TOP) -f $(MINGW_MAKEFILE) pidgin.exe
--- a/libpurple/win32/win32dep.c Tue Aug 17 17:23:13 2010 +0900 +++ b/libpurple/win32/win32dep.c Wed Sep 22 14:17:09 2010 +0900 @@ -35,7 +35,7 @@ static char *app_data_dir = NULL, *install_dir = NULL, *lib_dir = NULL, *locale_dir = NULL; -static HINSTANCE libpurpledll_hInstance = 0; +static HINSTANCE libpurpledll_hInstance = NULL; /* * PUBLIC CODE @@ -77,16 +77,23 @@ BOOL did_load = FALSE; FARPROC proc = 0; - if(!(hmod = GetModuleHandle(dllname))) { + wchar_t *wc_dllname = g_utf8_to_utf16(dllname, -1, NULL, NULL, NULL); + + if(!(hmod = GetModuleHandleW(wc_dllname))) { purple_debug_warning("wpurple", "%s not already loaded; loading it...\n", dllname); - if(!(hmod = LoadLibrary(dllname))) { - purple_debug_error("wpurple", "Could not load: %s\n", dllname); + if(!(hmod = LoadLibraryW(wc_dllname))) { + purple_debug_error("wpurple", "Could not load: %s (%s)\n", dllname, + g_win32_error_message(GetLastError())); + g_free(wc_dllname); return NULL; } else did_load = TRUE; } + g_free(wc_dllname); + wc_dllname = NULL; + if((proc = GetProcAddress(hmod, procedure))) { purple_debug_info("wpurple", "This version of %s contains %s\n", dllname, procedure); @@ -124,7 +131,7 @@ if (!initialized) { char *tmp = NULL; wchar_t winstall_dir[MAXPATHLEN]; - if (GetModuleFileNameW(NULL, winstall_dir, + if (GetModuleFileNameW(libpurpledll_hInstance, winstall_dir, MAXPATHLEN) > 0) { tmp = g_utf16_to_utf8(winstall_dir, -1, NULL, NULL, NULL);
--- a/pidgin.spec.in Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin.spec.in Wed Sep 22 14:17:09 2010 +0900 @@ -46,12 +46,14 @@ %if "%{_vendor}" == "suse" # For SuSE: BuildRequires: gnutls-devel +%define sslopts "--enable-gnutls=yes --enable-nss=no" %{?_with_dbus:BuildRequires: dbus-1-devel >= 0.35} %{!?_without_gstreamer:BuildRequires: gstreamer010-devel >= 0.10} Requires(pre): gconf2 Requires(post): gconf2 Requires(preun): gconf2 %else +%define sslopts "--enable-gnutls=no --enable-nss=yes" %{?_with_dbus:BuildRequires: dbus-devel >= 0.35} %{!?_without_gstreamer:BuildRequires: gstreamer-devel >= 0.10} Requires(pre): GConf2 @@ -230,6 +232,7 @@ --mandir=%{_mandir} \ --sysconfdir=%{_sysconfdir} \ --disable-schemas-install \ + %{sslopts} \ %{!?_with_vv:--disable-vv} \ %{!?_with_dbus:--disable-dbus} \ %{!?_with_avahi:--disable-avahi} \ @@ -471,6 +474,9 @@ %endif %changelog +* Wed Sep 01 2010 Stu Tomlinson <stu@nosnilmot.com> +- Ensure predictable use of SSL libs + * Wed Jun 02 2010 Stu Tomlinson <stu@nosnilmot.com> - add an option to build RPMs using --enable-trayicon-compat (--with trayiconcompat)
--- a/pidgin/Makefile.am Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/Makefile.am Wed Sep 22 14:17:09 2010 +0900 @@ -5,9 +5,6 @@ Makefile.mingw \ pidgin.pc.in \ pidgin-uninstalled.pc.in \ - win32/IdleTracker/Makefile.mingw \ - win32/IdleTracker/idletrack.c \ - win32/IdleTracker/idletrack.h \ win32/MinimizeToTray.h \ win32/MinimizeToTray.c \ win32/pidgin_dll_rc.rc.in \
--- a/pidgin/Makefile.mingw Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/Makefile.mingw Wed Sep 22 14:17:09 2010 +0900 @@ -33,7 +33,6 @@ INCLUDE_PATHS += \ $(PURPLE_INCLUDE_PATHS) \ - -I$(PIDGIN_IDLETRACK_TOP) \ -I$(PIDGIN_TOP) \ -I$(PIDGIN_TOP)/win32 \ -I$(GTK_TOP)/include/gtk-2.0 \ @@ -45,8 +44,7 @@ LIB_PATHS += -L$(GTK_TOP)/lib \ -L$(PURPLE_TOP) \ - -L$(PIDGIN_TOP) \ - -L$(PIDGIN_IDLETRACK_TOP) + -L$(PIDGIN_TOP) ## ## SOURCES, OBJECTS @@ -121,7 +119,6 @@ -lgthread-2.0 \ -lpurple \ -lz \ - -lidletrack \ -lgtk-win32-2.0 \ -latk-1.0 \ -lpango-1.0 \ @@ -151,7 +148,6 @@ install: install_shallow all $(MAKE) -C $(PIDGIN_PLUGINS_TOP) -f $(MINGW_MAKEFILE) install $(MAKE) -C $(PIDGIN_PIXMAPS_TOP) -f $(MINGW_MAKEFILE) install - $(MAKE) -C $(PIDGIN_IDLETRACK_TOP) -f $(MINGW_MAKEFILE) install win32/pidgin_dll_rc.rc: win32/pidgin_dll_rc.rc.in $(PIDGIN_TREE_TOP)/VERSION sed -e 's/@PIDGIN_VERSION@/$(PIDGIN_VERSION)/g' \ @@ -159,7 +155,7 @@ $(EXE_OBJECTS) $(PIDGIN_OBJECTS): $(PIDGIN_CONFIG_H) -$(PIDGIN_TARGET).dll $(PIDGIN_TARGET).dll.a: $(PURPLE_DLL).a $(PIDGIN_IDLETRACK_DLL).a $(PIDGIN_OBJECTS) +$(PIDGIN_TARGET).dll $(PIDGIN_TARGET).dll.a: $(PURPLE_DLL).a $(PIDGIN_OBJECTS) $(CC) -shared $(PIDGIN_OBJECTS) $(LIB_PATHS) $(PIDGIN_LIBS) $(DLL_LD_FLAGS) -Wl,--output-def,$(PIDGIN_TARGET).def,--out-implib,$(PIDGIN_TARGET).dll.a -o $(PIDGIN_TARGET).dll $(EXE_TARGET).exe: $(PIDGIN_CONFIG_H) $(PIDGIN_DLL).a $(EXE_OBJECTS) $(PIDGIN_TARGET).dll @@ -169,7 +165,6 @@ ## CLEAN RULES ## clean: - $(MAKE) -C $(PIDGIN_IDLETRACK_TOP) -f $(MINGW_MAKEFILE) clean $(MAKE) -C $(PIDGIN_PLUGINS_TOP) -f $(MINGW_MAKEFILE) clean $(MAKE) -C $(PIDGIN_PIXMAPS_TOP) -f $(MINGW_MAKEFILE) clean rm -f $(PIDGIN_OBJECTS) $(PIDGIN_RC_SRC) $(EXE_OBJECTS) $(EXE_RC_SRC)
--- a/pidgin/gtkaccount.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkaccount.c Wed Sep 22 14:17:09 2010 +0900 @@ -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);
--- a/pidgin/gtkblist.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkblist.c Wed Sep 22 14:17:09 2010 +0900 @@ -3173,7 +3173,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) { @@ -3659,6 +3658,9 @@ ***************************************************/ static GtkItemFactoryEntry blist_menu[] = { +/* NOTE: Do not set any accelerator to Control+O. It is mapped by + gtk_blist_key_press_cb to "Get User Info" on the selected buddy. */ + /* Buddies menu */ { N_("/_Buddies"), NULL, NULL, 0, "<Branch>", NULL }, { N_("/Buddies/New Instant _Message..."), "<CTL>M", pidgin_dialogs_im, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW }, @@ -3692,7 +3694,7 @@ { N_("/Tools/Plu_gins"), "<CTL>U", pidgin_plugin_dialog_show, 2, "<StockItem>", PIDGIN_STOCK_TOOLBAR_PLUGINS }, { N_("/Tools/Pr_eferences"), "<CTL>P", pidgin_prefs_show, 0, "<StockItem>", GTK_STOCK_PREFERENCES }, { N_("/Tools/Pr_ivacy"), NULL, pidgin_privacy_dialog_show, 0, "<Item>", NULL }, - { N_("/Tools/Set _Mood"), "<CTL>O", set_mood_show, 0, "<Item>", NULL }, + { N_("/Tools/Set _Mood"), "<CTL>D", set_mood_show, 0, "<Item>", NULL }, { "/Tools/sep2", NULL, NULL, 0, "<Separator>", NULL }, { N_("/Tools/_File Transfers"), "<CTL>T", pidgin_xfer_dialog_show, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_TRANSFER }, { N_("/Tools/R_oom List"), NULL, pidgin_roomlist_dialog_show, 0, "<Item>", NULL }, @@ -3972,7 +3974,6 @@ tmp); g_free(tmp); } - count = 0; count = purple_blist_get_group_size(group, FALSE); if (count != 0) { @@ -3983,7 +3984,6 @@ tmp); g_free(tmp); } - count = 0; tmp = purple_notify_user_info_get_text_with_newline(user_info, "\n"); g_string_append(str, tmp); @@ -4030,7 +4030,6 @@ { PurpleBuddy *buddy = NULL; struct _pidgin_blist_node *gtknode = node->ui_data; - struct _pidgin_blist_node *gtkbuddynode = NULL; PurplePlugin *prpl; PurplePluginProtocolInfo *prpl_info; const char *name = NULL; @@ -4041,11 +4040,9 @@ if(PURPLE_BLIST_NODE_IS_CONTACT(node)) { if(!gtknode->contact_expanded) { buddy = purple_contact_get_priority_buddy((PurpleContact*)node); - gtkbuddynode = ((PurpleBlistNode*)buddy)->ui_data; } } else if(PURPLE_BLIST_NODE_IS_BUDDY(node)) { buddy = (PurpleBuddy*)node; - gtkbuddynode = node->ui_data; p = purple_buddy_get_presence(buddy); if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_MOBILE)) { /* This emblem comes from the small emoticon set now, @@ -4138,7 +4135,6 @@ pidgin_blist_get_status_icon(PurpleBlistNode *node, PidginStatusIconSize size) { GdkPixbuf *ret; - const char *protoname = NULL; const char *icon = NULL; struct _pidgin_blist_node *gtknode = node->ui_data; struct _pidgin_blist_node *gtkbuddynode = NULL; @@ -4165,7 +4161,6 @@ if(buddy || chat) { PurpleAccount *account; PurplePlugin *prpl; - PurplePluginProtocolInfo *prpl_info; if(buddy) account = buddy->account; @@ -4175,12 +4170,6 @@ prpl = purple_find_prpl(purple_account_get_protocol_id(account)); if(!prpl) return NULL; - - prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); - - if(prpl_info && prpl_info->list_icon) { - protoname = prpl_info->list_icon(account, buddy); - } } if(buddy) {
--- a/pidgin/gtkconv.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkconv.c Wed Sep 22 14:17:09 2010 +0900 @@ -806,9 +806,9 @@ do_invite(GtkWidget *w, int resp, InviteBuddyInfo *info) { const char *buddy, *message; - PidginConversation *gtkconv; - - gtkconv = PIDGIN_CONVERSATION(info->conv); + PurpleConversation *conv; + + conv = info->conv; if (resp == GTK_RESPONSE_OK) { buddy = gtk_entry_get_text(GTK_ENTRY(info->entry)); @@ -817,8 +817,8 @@ if (!g_ascii_strcasecmp(buddy, "")) return; - serv_chat_invite(purple_conversation_get_gc(info->conv), - purple_conv_chat_get_id(PURPLE_CONV_CHAT(info->conv)), + serv_chat_invite(purple_conversation_get_gc(conv), + purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)), message, buddy); } @@ -912,7 +912,6 @@ InviteBuddyInfo *info = NULL; if (invite_dialog == NULL) { - PurpleConnection *gc; PidginWindow *gtkwin; GtkWidget *label; GtkWidget *vbox, *hbox; @@ -925,7 +924,6 @@ info = g_new0(InviteBuddyInfo, 1); info->conv = conv; - gc = purple_conversation_get_gc(conv); gtkwin = pidgin_conv_get_window(gtkconv); /* Create the new dialog. */ @@ -1256,12 +1254,10 @@ menu_insert_image_cb(gpointer data, guint action, GtkWidget *widget) { PidginWindow *win = data; - PurpleConversation *conv; PidginConversation *gtkconv; GtkIMHtmlToolbar *toolbar; gtkconv = pidgin_conv_window_get_active_gtkconv(win); - conv = gtkconv->active_conv; toolbar = GTK_IMHTMLTOOLBAR(gtkconv->toolbar); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->image), @@ -1967,10 +1963,8 @@ conv_keypress_common(PidginConversation *gtkconv, GdkEventKey *event) { PidginWindow *win; - PurpleConversation *conv; int curconv; - conv = gtkconv->active_conv; win = gtkconv->win; curconv = gtk_notebook_get_current_page(GTK_NOTEBOOK(win->notebook)); @@ -2065,13 +2059,11 @@ static gboolean entry_key_press_cb(GtkWidget *entry, GdkEventKey *event, gpointer data) { - PidginWindow *win; PurpleConversation *conv; PidginConversation *gtkconv; gtkconv = (PidginConversation *)data; conv = gtkconv->active_conv; - win = gtkconv->win; if (conv_keypress_common(gtkconv, event)) return TRUE; @@ -2406,12 +2398,9 @@ gchar *new_text, gint new_text_length, gpointer user_data) { PidginConversation *gtkconv = (PidginConversation *)user_data; - PurpleConversation *conv; g_return_if_fail(gtkconv != NULL); - conv = gtkconv->active_conv; - if (!purple_prefs_get_bool("/purple/conversations/im/send_typing")) return; @@ -2673,7 +2662,6 @@ PidginConversation *gtkconv = (PidginConversation *)data; PurpleConversation *conv = gtkconv->active_conv; PurpleAccount *account; - PurplePluginProtocolInfo *prpl_info = NULL; GdkPixbuf *buf; GdkPixbuf *scale; @@ -2684,9 +2672,7 @@ gtkconv = PIDGIN_CONVERSATION(conv); account = purple_conversation_get_account(conv); - if(account && account->gc) { - prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(account->gc->prpl); - } else { + if (!(account && account->gc)) { gtkconv->u.im->icon_timer = 0; return FALSE; } @@ -2758,7 +2744,6 @@ GList *children; GtkWidget *event; PurpleConversation *conv = gtkconv->active_conv; - PidginWindow *gtkwin; g_return_if_fail(conv != NULL); @@ -2786,8 +2771,6 @@ gtkconv->u.im->anim = NULL; gtkconv->u.im->iter = NULL; gtkconv->u.im->show_icon = FALSE; - - gtkwin = gtkconv->win; } static void @@ -3753,13 +3736,10 @@ static void update_typing_icon(PidginConversation *gtkconv) { - PidginWindow *gtkwin; PurpleConvIm *im = NULL; PurpleConversation *conv = gtkconv->active_conv; char *message = NULL; - gtkwin = gtkconv->win; - if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) im = PURPLE_CONV_IM(conv); @@ -3996,7 +3976,7 @@ continue; account = purple_buddy_get_account(buddy); - if (purple_account_is_connected(account)) + if (purple_account_is_connected(account) || account == gtkconv->active_conv->account) { /* Use the PurplePresence to get unique buddies. */ PurplePresence *presence = purple_buddy_get_presence(buddy); @@ -5833,10 +5813,8 @@ time_t mtime) { PidginConversation *gtkconv; - PidginWindow *win; PurpleConnection *gc; PurpleAccount *account; - PurplePluginProtocolInfo *prpl_info; int gtk_font_options = 0; int gtk_font_options_all = 0; int max_scrollback_lines; @@ -5923,9 +5901,6 @@ g_free(tmp); } - win = gtkconv->win; - prpl_info = gc ? PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl) : NULL; - line_count = gtk_text_buffer_get_line_count( gtk_text_view_get_buffer(GTK_TEXT_VIEW( gtkconv->imhtml))); @@ -6356,7 +6331,6 @@ pidgin_conv_chat_update_user(PurpleConversation *conv, const char *user) { PurpleConvChat *chat; - PurpleConvChatBuddyFlags flags; PurpleConvChatBuddy *cbuddy; PidginConversation *gtkconv; PidginChatPane *gtkchat; @@ -6399,8 +6373,6 @@ g_return_if_fail(alias != NULL); - flags = purple_conv_chat_user_get_flags(chat, user); - cbuddy = purple_conv_chat_cb_find(chat, user); if (cbuddy) add_chat_buddy_common(conv, cbuddy, NULL); @@ -6822,7 +6794,6 @@ PurpleConvIm *im = NULL; PurpleAccount *account = purple_conversation_get_account(conv); PurpleBuddy *buddy = NULL; - PurplePresence *p = NULL; char *markup = NULL; AtkObject *accessibility_obj; /* I think this is a little longer than it needs to be but I'm lazy. */ @@ -6845,7 +6816,6 @@ if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { buddy = purple_find_buddy(account, conv->name); if (buddy) { - p = purple_buddy_get_presence(buddy); markup = pidgin_blist_get_name_markup(buddy, FALSE, FALSE); } else { markup = title; @@ -7078,7 +7048,6 @@ int size = 0; PurpleAccount *account; - PurplePluginProtocolInfo *prpl_info = NULL; PurpleBuddyIcon *icon; @@ -7095,8 +7064,6 @@ return; account = purple_conversation_get_account(conv); - if(account && account->gc) - prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(account->gc->prpl); /* Remove the current icon stuff */ children = gtk_container_get_children(GTK_CONTAINER(gtkconv->u.im->icon_container)); @@ -8763,7 +8730,7 @@ static gboolean notebook_press_cb(GtkWidget *widget, GdkEventButton *e, PidginWindow *win) { - gint nb_x, nb_y, x_rel, y_rel; + gint nb_x, nb_y; int tab_clicked; GtkWidget *page; GtkWidget *tab; @@ -8806,9 +8773,6 @@ */ gdk_window_get_origin(win->notebook->window, &nb_x, &nb_y); - x_rel = e->x_root - nb_x; - y_rel = e->y_root - nb_y; - /* Reset the min/max x/y */ win->drag_min_x = 0; win->drag_min_y = 0; @@ -9375,6 +9339,7 @@ if (win && win->window && !GTK_WIDGET_VISIBLE(win->window) && conv_width != 0) { +#ifdef _WIN32 /* only override window manager placement on Windows */ /* ...check position is on screen... */ if (conv_x >= gdk_screen_width()) conv_x = gdk_screen_width() - 100; @@ -9387,7 +9352,6 @@ conv_y = 100; /* ...and move it back. */ -#ifdef _WIN32 /* only override window manager placement on Windows */ gtk_window_move(GTK_WINDOW(win->window), conv_x, conv_y); #endif gtk_window_resize(GTK_WINDOW(win->window), conv_width, conv_height); @@ -9639,7 +9603,7 @@ gtk_widget_show(gtkconv->menu_tabby); - if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) + if (conv_type == PURPLE_CONV_TYPE_IM) pidgin_conv_update_buddy_icon(conv); /* Build and set conversations tab */ @@ -9766,9 +9730,7 @@ pidgin_conv_window_remove_gtkconv(PidginWindow *win, PidginConversation *gtkconv) { unsigned int index; - PurpleConversationType conv_type; - - conv_type = purple_conversation_get_type(gtkconv->active_conv); + index = gtk_notebook_page_num(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont); g_object_ref(gtkconv->tab_cont); @@ -10101,12 +10063,9 @@ static void conv_placement_by_group(PidginConversation *conv) { - PurpleConversationType type; PurpleGroup *group = NULL; GList *wl, *cl; - type = purple_conversation_get_type(conv->active_conv); - group = conv_get_group(conv); /* Go through the list of IMs and find one with this group. */ @@ -10140,12 +10099,10 @@ static void conv_placement_by_account(PidginConversation *conv) { - PurpleConversationType type; GList *wins, *convs; PurpleAccount *account; account = purple_conversation_get_account(conv->active_conv); - type = purple_conversation_get_type(conv->active_conv); /* Go through the list of IMs and find one with this group. */ for (wins = pidgin_conv_windows_get_list(); wins != NULL; wins = wins->next) {
--- a/pidgin/gtkdebug.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkdebug.c Wed Sep 22 14:17:09 2010 +0900 @@ -39,6 +39,11 @@ #ifdef HAVE_REGEX_H # include <regex.h> +# define USE_REGEX 1 +#else +#if GLIB_CHECK_VERSION(2,14,0) +# define USE_REGEX 1 +#endif #endif /* HAVE_REGEX_H */ #include <gdk/gdkkeysyms.h> @@ -52,7 +57,7 @@ gboolean paused; -#ifdef HAVE_REGEX_H +#ifdef USE_REGEX GtkWidget *filter; GtkWidget *expression; @@ -60,11 +65,14 @@ gboolean highlight; guint timer; - +# ifdef HAVE_REGEX_H regex_t regex; +# else + GRegex *regex; +# endif /* HAVE_REGEX_H */ #else GtkWidget *find; -#endif /* HAVE_REGEX_H */ +#endif /* USE_REGEX */ GtkWidget *filterlevel; } DebugWindow; @@ -80,17 +88,17 @@ static DebugWindow *debug_win = NULL; static guint debug_enabled_timer = 0; -#ifdef HAVE_REGEX_H +#ifdef USE_REGEX static void regex_filter_all(DebugWindow *win); static void regex_show_all(DebugWindow *win); -#endif /* HAVE_REGEX_H */ +#endif /* USE_REGEX */ static gint debug_window_destroy(GtkWidget *w, GdkEvent *event, void *unused) { purple_prefs_disconnect_by_handle(pidgin_debug_get_handle()); -#ifdef HAVE_REGEX_H +#ifdef USE_REGEX if(debug_win->timer != 0) { const gchar *text; @@ -99,9 +107,12 @@ text = gtk_entry_get_text(GTK_ENTRY(debug_win->expression)); purple_prefs_set_string(PIDGIN_PREFS_ROOT "/debug/regex", text); } - +#ifdef HAVE_REGEX_H regfree(&debug_win->regex); -#endif +#else + g_regex_unref(debug_win->regex); +#endif /* HAVE_REGEX_H */ +#endif /* USE_REGEX */ /* If the "Save Log" dialog is open then close it */ purple_request_close_with_handle(debug_win); @@ -125,7 +136,7 @@ return FALSE; } -#ifndef HAVE_REGEX_H +#ifndef USE_REGEX struct _find { DebugWindow *window; GtkWidget *entry; @@ -206,7 +217,7 @@ gtk_widget_show_all(win->find); gtk_widget_grab_focus(f->entry); } -#endif /* HAVE_REGEX_H */ +#endif /* USE_REGEX */ static void save_writefile_cb(void *user_data, const char *filename) @@ -242,9 +253,9 @@ { gtk_imhtml_clear(GTK_IMHTML(win->text)); -#ifdef HAVE_REGEX_H +#ifdef USE_REGEX gtk_list_store_clear(win->store); -#endif /* HAVE_REGEX_H */ +#endif /* USE_REGEX */ } static void @@ -252,20 +263,20 @@ { win->paused = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(w)); -#ifdef HAVE_REGEX_H +#ifdef USE_REGEX if(!win->paused) { if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) regex_filter_all(win); else regex_show_all(win); } -#endif /* HAVE_REGEX_H */ +#endif /* USE_REGEX */ } /****************************************************************************** * regex stuff *****************************************************************************/ -#ifdef HAVE_REGEX_H +#ifdef USE_REGEX static void regex_clear_color(GtkWidget *w) { gtk_widget_modify_base(w, GTK_STATE_NORMAL, NULL); @@ -295,16 +306,18 @@ static void regex_match(DebugWindow *win, const gchar *text) { GtkIMHtml *imhtml = GTK_IMHTML(win->text); +#ifdef HAVE_REGEX_H regmatch_t matches[4]; /* adjust if necessary */ size_t n_matches = sizeof(matches) / sizeof(matches[0]); + gint inverted; +#else + GMatchInfo *match_info; +#endif /* HAVE_REGEX_H */ gchar *plaintext; - gint inverted; if(!text) return; - inverted = (win->invert) ? REG_NOMATCH : 0; - /* I don't like having to do this, but we need it for highlighting. Plus * it makes the ^ and $ operators work :) */ @@ -313,9 +326,14 @@ /* we do a first pass to see if it matches at all. If it does we append * it, and work out the offsets to highlight. */ +#ifdef HAVE_REGEX_H + inverted = (win->invert) ? REG_NOMATCH : 0; if(regexec(&win->regex, plaintext, n_matches, matches, 0) == inverted) { +#else + if(g_regex_match(win->regex, plaintext, 0, &match_info) != win->invert) { +#endif /* HAVE_REGEX_H */ + gchar *p = plaintext; GtkTextIter ins; - gchar *p = plaintext; gint i, offset = 0; gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &ins, @@ -327,14 +345,18 @@ /* If we're not highlighting or the expression is inverted, we're * done and move on. */ - if(!win->highlight || inverted == REG_NOMATCH) { + if(!win->highlight || win->invert) { g_free(plaintext); +#ifndef HAVE_REGEX_H + g_match_info_free(match_info); +#endif return; } /* we use a do-while to highlight the first match, and then continue * if necessary... */ +#ifdef HAVE_REGEX_H do { size_t m; @@ -357,6 +379,41 @@ p += offset; } while(regexec(&win->regex, p, n_matches, matches, REG_NOTBOL) == inverted); +#else + do + { + gint m; + gint start_pos, end_pos; + GtkTextIter ms, me; + + if (!g_match_info_matches(match_info)) + break; + + for (m = 0; m < g_match_info_get_match_count(match_info); m++) + { + if (m == 1) + continue; + + g_match_info_fetch_pos(match_info, m, &start_pos, &end_pos); + + if (end_pos == -1) + break; + + gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &ms, + i + start_pos); + gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &me, + i + end_pos); + gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "regex", + &ms, &me); + offset = end_pos; + } + + g_match_info_free(match_info); + p += offset; + i += offset; + } while (g_regex_match(win->regex, p, G_REGEX_MATCH_NOTBOL, &match_info) != win->invert); + g_match_info_free(match_info); +#endif /* HAVE_REGEX_H */ } g_free(plaintext); @@ -430,9 +487,15 @@ return; } +#ifdef HAVE_REGEX_H regfree(&win->regex); - if(regcomp(&win->regex, text, REG_EXTENDED | REG_ICASE) != 0) { +#else + if (win->regex) + g_regex_unref(win->regex); + win->regex = g_regex_new(text, G_REGEX_EXTENDED | G_REGEX_CASELESS, 0, NULL); + if(win->regex == NULL) { +#endif /* failed to compile */ regex_change_color(win->expression, 0xFFFF, 0xAFFF, 0xAFFF); gtk_widget_set_sensitive(win->filter, FALSE); @@ -616,7 +679,7 @@ else regex_show_all(win); } -#endif /* HAVE_REGEX_H */ +#endif /* USE_REGEX */ static void filter_level_changed_cb(GtkWidget *combo, gpointer null) @@ -702,7 +765,7 @@ handle = pidgin_debug_get_handle(); -#ifdef HAVE_REGEX_H +#ifdef USE_REGEX /* the list store for all the messages */ win->store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT); @@ -714,7 +777,7 @@ g_signal_connect(G_OBJECT(win->store), "row-changed", G_CALLBACK(regex_row_changed_cb), win); -#endif /* HAVE_REGEX_H */ +#endif /* USE_REGEX */ /* Setup the vbox */ vbox = gtk_vbox_new(FALSE, 0); @@ -741,7 +804,7 @@ gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0); -#ifndef HAVE_REGEX_H +#ifndef USE_REGEX /* Find button */ item = gtk_tool_button_new_from_stock(GTK_STOCK_FIND); gtk_tool_item_set_is_important(item, TRUE); @@ -752,7 +815,7 @@ #endif g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(find_cb), win); gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(item)); -#endif /* HAVE_REGEX_H */ +#endif /* USE_REGEX */ /* Save */ item = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE); @@ -790,7 +853,7 @@ g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(pause_cb), win); gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(item)); -#ifdef HAVE_REGEX_H +#ifdef USE_REGEX /* regex stuff */ item = gtk_separator_tool_item_new(); gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(item)); @@ -853,7 +916,7 @@ purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/debug/highlight", regex_pref_highlight_cb, win); -#endif /* HAVE_REGEX_H */ +#endif /* USE_REGEX */ item = gtk_separator_tool_item_new(); gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(item)); @@ -880,7 +943,7 @@ gtk_combo_box_append_text(GTK_COMBO_BOX(win->filterlevel), _("Fatal Error")); gtk_combo_box_set_active(GTK_COMBO_BOX(win->filterlevel), purple_prefs_get_int(PIDGIN_PREFS_ROOT "/debug/filterlevel")); -#ifdef HAVE_REGEX_H +#ifdef USE_REGEX purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/debug/filterlevel", filter_level_pref_changed, win); #endif @@ -895,13 +958,13 @@ gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0); gtk_widget_show(frame); -#ifdef HAVE_REGEX_H +#ifdef USE_REGEX /* add the tag for regex highlighting */ gtk_text_buffer_create_tag(GTK_IMHTML(win->text)->text_buffer, "regex", "background", "#FFAFAF", "weight", "bold", NULL); -#endif /* HAVE_REGEX_H */ +#endif /* USE_REGEX */ gtk_widget_show_all(win->window); @@ -1002,13 +1065,13 @@ purple_prefs_add_int(PIDGIN_PREFS_ROOT "/debug/width", 450); purple_prefs_add_int(PIDGIN_PREFS_ROOT "/debug/height", 250); -#ifdef HAVE_REGEX_H +#ifdef USE_REGEX purple_prefs_add_string(PIDGIN_PREFS_ROOT "/debug/regex", ""); purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/debug/filter", FALSE); purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/debug/invert", FALSE); purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/debug/case_insensitive", FALSE); purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/debug/highlight", FALSE); -#endif /* HAVE_REGEX_H */ +#endif /* USE_REGEX */ purple_prefs_connect_callback(NULL, PIDGIN_PREFS_ROOT "/debug/enabled", debug_enabled_cb, NULL); @@ -1070,9 +1133,9 @@ pidgin_debug_print(PurpleDebugLevel level, const char *category, const char *arg_s) { -#ifdef HAVE_REGEX_H +#ifdef USE_REGEX GtkTreeIter iter; -#endif /* HAVE_REGEX_H */ +#endif /* USE_REGEX */ gchar *ts_s; gchar *esc_s, *cat_s, *tmp, *s; const char *mdate; @@ -1111,14 +1174,14 @@ s = tmp; } -#ifdef HAVE_REGEX_H +#ifdef USE_REGEX /* add the text to the list store */ gtk_list_store_append(debug_win->store, &iter); gtk_list_store_set(debug_win->store, &iter, 0, s, 1, level, -1); -#else /* HAVE_REGEX_H */ +#else /* USE_REGEX */ if(!debug_win->paused && level >= purple_prefs_get_int(PIDGIN_PREFS_ROOT "/debug/filterlevel")) gtk_imhtml_append_text(GTK_IMHTML(debug_win->text), s, 0); -#endif /* !HAVE_REGEX_H */ +#endif /* !USE_REGEX */ g_free(s); }
--- a/pidgin/gtkdialogs.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkdialogs.c Wed Sep 22 14:17:09 2010 +0900 @@ -1288,7 +1288,7 @@ purple_debug_info("blist", "Removing '%s' from buddy list.\n", buddy->name); /* TODO - Should remove from blist first... then call purple_account_remove_buddy()? */ - purple_account_remove_buddy(buddy->account, buddy, group); + purple_account_remove_buddy(account, buddy, group); purple_blist_remove_buddy(buddy); g_free(name);
--- a/pidgin/gtkft.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkft.c Wed Sep 22 14:17:09 2010 +0900 @@ -112,13 +112,10 @@ get_xfer_info_strings(PurpleXfer *xfer, char **kbsec, char **time_elapsed, char **time_remaining) { - PidginXferUiData *data; double kb_sent, kb_rem; double kbps = 0.0; time_t elapsed, now; - data = PIDGINXFER(xfer); - if (xfer->end_time != 0) now = xfer->end_time; else @@ -159,7 +156,7 @@ *time_remaining = g_strdup(_("Finished")); } else if (purple_xfer_is_canceled(xfer)) { - *time_remaining = g_strdup(_("Canceled")); + *time_remaining = g_strdup(_("Cancelled")); } else if (purple_xfer_get_size(xfer) == 0 || (kb_sent > 0 && kbps == 0)) { *time_remaining = g_strdup(_("Unknown")); @@ -995,7 +992,7 @@ GTK_ICON_SIZE_MENU, NULL); if (purple_xfer_is_canceled(xfer)) - status = _("Canceled"); + status = _("Cancelled"); else status = _("Failed"); @@ -1015,7 +1012,6 @@ { PidginXferUiData *data; char *size_str, *remaining_str; - GtkTreeSelection *selection; time_t current_time; GtkTreeIter iter; gboolean valid; @@ -1066,8 +1062,6 @@ g_object_unref(pixbuf); } - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(xfer_dialog->tree)); - update_title_progress(dialog); if (xfer == dialog->selected_xfer) update_detailed_info(xfer_dialog, xfer);
--- a/pidgin/gtkft.h Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkft.h Wed Sep 22 14:17:09 2010 +0900 @@ -88,10 +88,10 @@ PurpleXfer *xfer); /** - * Indicate in a file transfer dialog that a transfer was canceled. + * Indicate in a file transfer dialog that a transfer was cancelled. * * @param dialog The file transfer dialog. - * @param xfer The file transfer that was canceled. + * @param xfer The file transfer that was cancelled. */ void pidgin_xfer_dialog_cancel_xfer(PidginXferDialog *dialog, PurpleXfer *xfer);
--- a/pidgin/gtkidle.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkidle.c Wed Sep 22 14:17:09 2010 +0900 @@ -29,7 +29,7 @@ #else # ifdef USE_SCREENSAVER # ifdef _WIN32 -# include "idletrack.h" +# include "gtkwin32dep.h" # else /* We're on X11 and not MacOS X with IOKit. */ # include <X11/Xlib.h>
--- a/pidgin/gtkimhtml.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkimhtml.c Wed Sep 22 14:17:09 2010 +0900 @@ -1490,10 +1490,8 @@ static void gtk_imhtml_class_init (GtkIMHtmlClass *klass) { GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; - GtkObjectClass *object_class; GtkBindingSet *binding_set; GObjectClass *gobject_class; - object_class = (GtkObjectClass*) klass; gobject_class = (GObjectClass*) klass; parent_class = g_type_class_ref(GTK_TYPE_TEXT_VIEW); signals[URL_CLICKED] = g_signal_new("url_clicked",
--- a/pidgin/gtkimhtmltoolbar.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkimhtmltoolbar.c Wed Sep 22 14:17:09 2010 +0900 @@ -1205,9 +1205,7 @@ /* Boring GTK+ stuff */ static void gtk_imhtmltoolbar_class_init (GtkIMHtmlToolbarClass *class) { - GtkObjectClass *object_class; GObjectClass *gobject_class; - object_class = (GtkObjectClass*) class; gobject_class = (GObjectClass*) class; parent_class = g_type_class_ref(GTK_TYPE_HBOX); gobject_class->finalize = gtk_imhtmltoolbar_finalize;
--- a/pidgin/gtknotify.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtknotify.c Wed Sep 22 14:17:09 2010 +0900 @@ -1370,11 +1370,32 @@ command = g_strdup_printf("opera %s", escaped); } + else if (!strcmp(web_browser, "google-chrome")) + { + /* Google Chrome doesn't have command-line arguments that control the + * opening of links from external calls. This is controlled solely from + * a preference within Google Chrome. */ + command = g_strdup_printf("google-chrome %s", escaped); + } + else if (!strcmp(web_browser, "chrome")) + { + /* Chromium doesn't have command-line arguments that control the + * opening of links from external calls. This is controlled solely from + * a preference within Chromium. */ + command = g_strdup_printf("chrome %s", escaped); + } + else if (!strcmp(web_browser, "chromium-browser")) + { + /* Chromium doesn't have command-line arguments that control the + * opening of links from external calls. This is controlled solely from + * a preference within Chromium. */ + command = g_strdup_printf("chromium-browser %s", escaped); + } else if (!strcmp(web_browser, "custom")) { const char *web_command; - web_command = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/browsers/command"); + web_command = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/browsers/manual_command"); if (web_command == NULL || *web_command == '\0') {
--- a/pidgin/gtkplugin.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkplugin.c Wed Sep 22 14:17:09 2010 +0900 @@ -800,5 +800,8 @@ g_signal_connect (G_OBJECT (sel), "changed", G_CALLBACK (prefs_plugin_sel), NULL); g_signal_connect(G_OBJECT(plugin_dialog), "response", G_CALLBACK(plugin_dialog_response_cb), sel); gtk_window_set_default_size(GTK_WINDOW(plugin_dialog), 430, 530); + + pidgin_auto_parent_window(plugin_dialog); + gtk_widget_show_all(plugin_dialog); }
--- a/pidgin/gtkpounce.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkpounce.c Wed Sep 22 14:17:09 2010 +0900 @@ -194,7 +194,6 @@ { GtkTreeIter iter; PurpleAccount *account; - PurplePounceEvent events; gboolean recurring; const char *pouncer; const char *pouncee; @@ -202,8 +201,6 @@ account = purple_pounce_get_pouncer(pounce); - events = purple_pounce_get_events(pounce); - pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_MEDIUM); pouncer = purple_account_get_username(account);
--- a/pidgin/gtkprefs.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkprefs.c Wed Sep 22 14:17:09 2010 +0900 @@ -1042,11 +1042,40 @@ } static GtkWidget * +add_theme_prefs_combo(GtkWidget *vbox, + GtkSizeGroup *combo_sg, GtkSizeGroup *label_sg, + GtkListStore *theme_store, + GCallback combo_box_cb, gpointer combo_box_cb_user_data, + const char *label_str, const char *prefs_path, + const char *theme_type) +{ + GtkWidget *label; + GtkWidget *combo_box = NULL; + GtkWidget *themesel_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); + + label = gtk_label_new(label_str); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_size_group_add_widget(label_sg, label); + gtk_box_pack_start(GTK_BOX(themesel_hbox), label, FALSE, FALSE, 0); + + combo_box = prefs_build_theme_combo_box(theme_store, + purple_prefs_get_string(prefs_path), + theme_type); + g_signal_connect(G_OBJECT(combo_box), "changed", + (GCallback)combo_box_cb, combo_box_cb_user_data); + gtk_size_group_add_widget(combo_sg, combo_box); + gtk_box_pack_start(GTK_BOX(themesel_hbox), combo_box, TRUE, TRUE, 0); + + gtk_box_pack_start(GTK_BOX(vbox), themesel_hbox, FALSE, FALSE, 0); + + return combo_box; +} + +static GtkWidget * theme_page(void) { + GtkWidget *label; GtkWidget *ret, *vbox; - GtkWidget *label; - GtkWidget *themesel_hbox; GtkSizeGroup *label_sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); GtkSizeGroup *combo_sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); @@ -1067,76 +1096,28 @@ gtk_widget_show(label); /* Buddy List Themes */ - themesel_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); - - label = gtk_label_new(_("Buddy List Theme:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_size_group_add_widget(label_sg, label); - gtk_box_pack_start(GTK_BOX(themesel_hbox), label, FALSE, FALSE, 0); - - prefs_blist_themes_combo_box = prefs_build_theme_combo_box(prefs_blist_themes, - purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/theme"), - "blist"); - g_signal_connect(G_OBJECT(prefs_blist_themes_combo_box), "changed", - (GCallback)prefs_set_blist_theme_cb, NULL); - gtk_size_group_add_widget(combo_sg, prefs_blist_themes_combo_box); - gtk_box_pack_start(GTK_BOX(themesel_hbox), prefs_blist_themes_combo_box, TRUE, TRUE, 0); - - gtk_box_pack_start(GTK_BOX(vbox), themesel_hbox, FALSE, FALSE, 0); + prefs_blist_themes_combo_box = add_theme_prefs_combo( + vbox, combo_sg, label_sg, prefs_blist_themes, + (GCallback)prefs_set_blist_theme_cb, NULL, + _("Buddy List Theme:"), PIDGIN_PREFS_ROOT "/blist/theme", "blist"); /* Status Icon Themes */ - themesel_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); - - label = gtk_label_new(_("Status Icon Theme:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_size_group_add_widget(label_sg, label); - gtk_box_pack_start(GTK_BOX(themesel_hbox), label, FALSE, FALSE, 0); - - prefs_status_themes_combo_box = prefs_build_theme_combo_box(prefs_status_icon_themes, - purple_prefs_get_string(PIDGIN_PREFS_ROOT "/status/icon-theme"), - "icon"); - g_signal_connect(G_OBJECT(prefs_status_themes_combo_box), "changed", - (GCallback)prefs_set_status_icon_theme_cb, NULL); - gtk_size_group_add_widget(combo_sg, prefs_status_themes_combo_box); - gtk_box_pack_start(GTK_BOX(themesel_hbox), prefs_status_themes_combo_box, TRUE, TRUE, 0); - - gtk_box_pack_start(GTK_BOX(vbox), themesel_hbox, FALSE, FALSE, 0); + prefs_status_themes_combo_box = add_theme_prefs_combo( + vbox, combo_sg, label_sg, prefs_status_icon_themes, + (GCallback)prefs_set_status_icon_theme_cb, NULL, + _("Status Icon Theme:"), PIDGIN_PREFS_ROOT "/status/icon-theme", "icon"); /* Sound Themes */ - themesel_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); - - label = gtk_label_new(_("Sound Theme:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_size_group_add_widget(label_sg, label); - gtk_box_pack_start(GTK_BOX(themesel_hbox), label, FALSE, FALSE, 0); - - prefs_sound_themes_combo_box = prefs_build_theme_combo_box(prefs_sound_themes, - purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/theme"), - "sound"); - g_signal_connect(G_OBJECT(prefs_sound_themes_combo_box), "changed", - (GCallback)prefs_set_sound_theme_cb, NULL); - gtk_size_group_add_widget(combo_sg, prefs_sound_themes_combo_box); - gtk_box_pack_start(GTK_BOX(themesel_hbox), prefs_sound_themes_combo_box, TRUE, TRUE, 0); - - gtk_box_pack_start(GTK_BOX(vbox), themesel_hbox, FALSE, FALSE, 0); + prefs_sound_themes_combo_box = add_theme_prefs_combo( + vbox, combo_sg, label_sg, prefs_sound_themes, + (GCallback)prefs_set_sound_theme_cb, NULL, + _("Sound Theme:"), PIDGIN_PREFS_ROOT "/sound/theme", "sound"); /* Smiley Themes */ - themesel_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); - - label = gtk_label_new(_("Smiley Theme:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_size_group_add_widget(label_sg, label); - gtk_box_pack_start(GTK_BOX(themesel_hbox), label, FALSE, FALSE, 0); - - prefs_smiley_themes_combo_box = prefs_build_theme_combo_box(prefs_smiley_themes, - purple_prefs_get_string(PIDGIN_PREFS_ROOT "/smileys/theme"), - "smiley"); - g_signal_connect(G_OBJECT(prefs_smiley_themes_combo_box), "changed", - (GCallback)prefs_set_smiley_theme_cb, NULL); - gtk_size_group_add_widget(combo_sg, prefs_smiley_themes_combo_box); - gtk_box_pack_start(GTK_BOX(themesel_hbox), prefs_smiley_themes_combo_box, TRUE, TRUE, 0); - - gtk_box_pack_start(GTK_BOX(vbox), themesel_hbox, FALSE, FALSE, 0); + prefs_smiley_themes_combo_box = add_theme_prefs_combo( + vbox, combo_sg, label_sg, prefs_smiley_themes, + (GCallback)prefs_set_smiley_theme_cb, NULL, + _("Smiley Theme:"), PIDGIN_PREFS_ROOT "/smileys/theme", "smiley"); /* Custom sort so "none" theme is at top of list */ gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(prefs_smiley_themes), @@ -1812,9 +1793,10 @@ hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_TURN server:"), sg, entry, TRUE, NULL); - - pidgin_prefs_labeled_spin_button(hbox, _("_Port:"), + + pidgin_prefs_labeled_spin_button(hbox, _("_UDP Port:"), "/purple/network/turn_port", 0, 65535, NULL); + hbox = pidgin_prefs_labeled_entry(vbox, _("Use_rname:"), "/purple/network/turn_username", sg); pidgin_prefs_labeled_password(hbox, _("Pass_word:"), @@ -1832,7 +1814,7 @@ { const char *program = gtk_entry_get_text(GTK_ENTRY(entry)); - purple_prefs_set_path(PIDGIN_PREFS_ROOT "/browsers/command", program); + purple_prefs_set_string(PIDGIN_PREFS_ROOT "/browsers/manual_command", program); /* carry on normally */ return FALSE; @@ -1853,12 +1835,19 @@ {N_("Netscape"), "netscape"}, {N_("Mozilla"), "mozilla"}, {N_("Konqueror"), "kfmclient"}, + {N_("Google Chrome"), "google-chrome"}, + /* Do not move the line below. Code below expects gnome-open to be in + * this list immediately after xdg-open! */ {N_("Desktop Default"), "xdg-open"}, {N_("GNOME Default"), "gnome-open"}, {N_("Galeon"), "galeon"}, {N_("Firefox"), "firefox"}, {N_("Firebird"), "mozilla-firebird"}, - {N_("Epiphany"), "epiphany"} + {N_("Epiphany"), "epiphany"}, + /* Translators: please do not translate "chromium-browser" here! */ + {N_("Chromium (chromium-browser)"), "chromium-browser"}, + /* Translators: please do not translate "chrome" here! */ + {N_("Chromium (chrome)"), "chrome"} }; static const int num_possible_browsers = G_N_ELEMENTS(possible_browsers); @@ -1982,7 +1971,7 @@ entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), - purple_prefs_get_path(PIDGIN_PREFS_ROOT "/browsers/command")); + purple_prefs_get_string(PIDGIN_PREFS_ROOT "/browsers/manual_command")); g_signal_connect(G_OBJECT(entry), "focus-out-event", G_CALLBACK(manual_browser_set), NULL); hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Manual:\n(%s for URL)"), sg, entry, TRUE, NULL); @@ -2842,7 +2831,7 @@ /* Browsers */ purple_prefs_add_none(PIDGIN_PREFS_ROOT "/browsers"); purple_prefs_add_int(PIDGIN_PREFS_ROOT "/browsers/place", PIDGIN_BROWSER_DEFAULT); - purple_prefs_add_path(PIDGIN_PREFS_ROOT "/browsers/command", ""); + purple_prefs_add_string(PIDGIN_PREFS_ROOT "/browsers/manual_command", ""); purple_prefs_add_string(PIDGIN_PREFS_ROOT "/browsers/browser", "mozilla"); #endif @@ -2873,7 +2862,7 @@ void pidgin_prefs_update_old(void) { - const char *str; + const char *str = NULL; purple_prefs_rename("/gaim/gtk", PIDGIN_PREFS_ROOT); @@ -2889,6 +2878,17 @@ purple_prefs_rename_boolean_toggle(PIDGIN_PREFS_ROOT "/conversations/ignore_colors", PIDGIN_PREFS_ROOT "/conversations/show_incoming_formatting"); + /* + * this path pref changed to a string, so migrate. I know this will break + * things for and confuse users that use multiple versions with the same + * config directory, but I'm not inclined to want to deal with that at the + * moment. -- rekkanoryo + */ + if((str = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/browsers/command")) != NULL) { + purple_prefs_set_string(PIDGIN_PREFS_ROOT "/browsers/manual_command", str); + purple_prefs_remove(PIDGIN_PREFS_ROOT "/browsers/command"); + } + /* this string pref moved into the core, try to be friendly */ purple_prefs_rename(PIDGIN_PREFS_ROOT "/idle/reporting_method", "/purple/away/idle_reporting"); if ((str = purple_prefs_get_string("/purple/away/idle_reporting")) &&
--- a/pidgin/gtkroomlist.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkroomlist.c Wed Sep 22 14:17:09 2010 +0900 @@ -362,8 +362,6 @@ style = grl->tipwindow->style; - max_text_width = 0; - max_text_width = MAX(grl->tip_width, grl->tip_name_width); max_width = TOOLTIP_BORDER + SMALL_SPACE + max_text_width + TOOLTIP_BORDER;
--- a/pidgin/gtksession.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtksession.c Wed Sep 22 14:17:09 2010 +0900 @@ -166,7 +166,7 @@ ret[j++] = g_strdup("--display"); ret[j++] = g_strdup((gchar *)gdk_display_get_name(gdk_display_get_default())); - ret[j++] = NULL; + ret[j] = NULL; return ret; }
--- a/pidgin/gtksmiley.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtksmiley.c Wed Sep 22 14:17:09 2010 +0900 @@ -520,9 +520,6 @@ GtkTreeIter *iter, gpointer data) { PurpleSmiley *smiley = NULL; - SmileyManager *dialog; - - dialog = (SmileyManager*)data; gtk_tree_model_get(model, iter, SMILEY, &smiley,
--- a/pidgin/gtksourceundomanager.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtksourceundomanager.c Wed Sep 22 14:17:09 2010 +0900 @@ -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,
--- a/pidgin/gtkstatusbox.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkstatusbox.c Wed Sep 22 14:17:09 2010 +0900 @@ -657,7 +657,6 @@ static void pidgin_status_box_refresh(PidginStatusBox *status_box) { - GtkIconSize icon_size; GtkStyle *style; char aa_color[8]; PurpleSavedStatus *saved_status; @@ -668,8 +667,6 @@ gboolean account_status = FALSE; PurpleAccount *acct = (status_box->account) ? status_box->account : status_box->token_status_account; - icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL); - style = gtk_widget_get_style(GTK_WIDGET(status_box)); snprintf(aa_color, sizeof(aa_color), "#%02x%02x%02x", style->text_aa[GTK_STATE_NORMAL].red >> 8, @@ -969,11 +966,7 @@ PurpleSavedStatus *saved = cur->data; const gchar *message; gchar *stripped = NULL; - PurpleStatusPrimitive prim; - PidginStatusBoxItemType type = PIDGIN_STATUS_BOX_TYPE_POPULAR; - - /* Get an appropriate status icon */ - prim = purple_savedstatus_get_type(saved); + PidginStatusBoxItemType type; if (purple_savedstatus_is_transient(saved)) { @@ -982,16 +975,18 @@ * API returns the message when purple_savedstatus_get_title() is * called, so we don't need to get the message a second time. */ + type = PIDGIN_STATUS_BOX_TYPE_POPULAR; } else { + type = PIDGIN_STATUS_BOX_TYPE_SAVED_POPULAR; + message = purple_savedstatus_get_message(saved); if (message != NULL) { stripped = purple_markup_strip_html(message); purple_util_chrreplace(stripped, '\n', ' '); } - type = PIDGIN_STATUS_BOX_TYPE_SAVED_POPULAR; } pidgin_status_box_add(statusbox, type, @@ -1074,17 +1069,13 @@ PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, NULL, purple_status_type_get_name(status_type), NULL, - GINT_TO_POINTER(purple_status_type_get_primitive(status_type))); + GINT_TO_POINTER(prim)); } } static void pidgin_status_box_regenerate(PidginStatusBox *status_box, gboolean status_changed) { - GtkIconSize icon_size; - - icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL); - /* Unset the model while clearing it */ gtk_tree_view_set_model(GTK_TREE_VIEW(status_box->tree_view), NULL); gtk_list_store_clear(status_box->dropdown_store);
--- a/pidgin/gtkutils.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkutils.c Wed Sep 22 14:17:09 2010 +0900 @@ -680,7 +680,6 @@ create_protocols_menu(const char *default_proto_id) { AopMenu *aop_menu = NULL; - PurplePluginProtocolInfo *prpl_info; PurplePlugin *plugin; GdkPixbuf *pixbuf = NULL; GtkSizeGroup *sg; @@ -702,7 +701,6 @@ p = p->next, i++) { plugin = (PurplePlugin *)p->data; - prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); if (gtalk_name && strcmp(gtalk_name, plugin->info->name) < 0) { char *filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", @@ -784,8 +782,6 @@ sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); for (p = list, i = 0; p != NULL; p = p->next, i++) { - PurplePlugin *plugin; - if (show_all) account = (PurpleAccount *)p->data; else { @@ -799,8 +795,6 @@ continue; } - plugin = purple_find_prpl(purple_account_get_protocol_id(account)); - pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL); if (pixbuf) { @@ -1036,7 +1030,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 +1072,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 +2605,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 +2619,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 +2639,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); } /* @@ -2771,79 +2784,78 @@ gboolean pidgin_gdk_pixbuf_is_opaque(GdkPixbuf *pixbuf) { - int width, height, rowstride, i; - unsigned char *pixels; - unsigned char *row; - - if (!gdk_pixbuf_get_has_alpha(pixbuf)) - return TRUE; - - width = gdk_pixbuf_get_width (pixbuf); - height = gdk_pixbuf_get_height (pixbuf); - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - pixels = gdk_pixbuf_get_pixels (pixbuf); - - row = pixels; - for (i = 3; i < rowstride; i+=4) { - if (row[i] < 0xfe) - return FALSE; - } - - for (i = 1; i < height - 1; i++) { - row = pixels + (i*rowstride); - if (row[3] < 0xfe || row[rowstride-1] < 0xfe) { - return FALSE; - } - } - - row = pixels + ((height-1) * rowstride); - for (i = 3; i < rowstride; i+=4) { - if (row[i] < 0xfe) - return FALSE; - } - - return TRUE; + int height, rowstride, i; + unsigned char *pixels; + unsigned char *row; + + if (!gdk_pixbuf_get_has_alpha(pixbuf)) + return TRUE; + + height = gdk_pixbuf_get_height (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + pixels = gdk_pixbuf_get_pixels (pixbuf); + + row = pixels; + for (i = 3; i < rowstride; i+=4) { + if (row[i] < 0xfe) + return FALSE; + } + + for (i = 1; i < height - 1; i++) { + row = pixels + (i * rowstride); + if (row[3] < 0xfe || row[rowstride - 1] < 0xfe) { + return FALSE; + } + } + + row = pixels + ((height - 1) * rowstride); + for (i = 3; i < rowstride; i += 4) { + if (row[i] < 0xfe) + return FALSE; + } + + return TRUE; } void pidgin_gdk_pixbuf_make_round(GdkPixbuf *pixbuf) { int width, height, rowstride; - guchar *pixels; - if (!gdk_pixbuf_get_has_alpha(pixbuf)) - return; - width = gdk_pixbuf_get_width(pixbuf); - height = gdk_pixbuf_get_height(pixbuf); - rowstride = gdk_pixbuf_get_rowstride(pixbuf); - pixels = gdk_pixbuf_get_pixels(pixbuf); - - if (width < 6 || height < 6) - return; - /* Top left */ - pixels[3] = 0; - pixels[7] = 0x80; - pixels[11] = 0xC0; - pixels[rowstride + 3] = 0x80; - pixels[rowstride * 2 + 3] = 0xC0; - - /* Top right */ - pixels[width * 4 - 1] = 0; - pixels[width * 4 - 5] = 0x80; - pixels[width * 4 - 9] = 0xC0; - pixels[rowstride + (width * 4) - 1] = 0x80; - pixels[(2 * rowstride) + (width * 4) - 1] = 0xC0; - - /* Bottom left */ - pixels[(height - 1) * rowstride + 3] = 0; - pixels[(height - 1) * rowstride + 7] = 0x80; - pixels[(height - 1) * rowstride + 11] = 0xC0; - pixels[(height - 2) * rowstride + 3] = 0x80; - pixels[(height - 3) * rowstride + 3] = 0xC0; - - /* Bottom right */ - pixels[height * rowstride - 1] = 0; - pixels[(height - 1) * rowstride - 1] = 0x80; - pixels[(height - 2) * rowstride - 1] = 0xC0; - pixels[height * rowstride - 5] = 0x80; - pixels[height * rowstride - 9] = 0xC0; + guchar *pixels; + if (!gdk_pixbuf_get_has_alpha(pixbuf)) + return; + width = gdk_pixbuf_get_width(pixbuf); + height = gdk_pixbuf_get_height(pixbuf); + rowstride = gdk_pixbuf_get_rowstride(pixbuf); + pixels = gdk_pixbuf_get_pixels(pixbuf); + + if (width < 6 || height < 6) + return; + /* Top left */ + pixels[3] = 0; + pixels[7] = 0x80; + pixels[11] = 0xC0; + pixels[rowstride + 3] = 0x80; + pixels[rowstride * 2 + 3] = 0xC0; + + /* Top right */ + pixels[width * 4 - 1] = 0; + pixels[width * 4 - 5] = 0x80; + pixels[width * 4 - 9] = 0xC0; + pixels[rowstride + (width * 4) - 1] = 0x80; + pixels[(2 * rowstride) + (width * 4) - 1] = 0xC0; + + /* Bottom left */ + pixels[(height - 1) * rowstride + 3] = 0; + pixels[(height - 1) * rowstride + 7] = 0x80; + pixels[(height - 1) * rowstride + 11] = 0xC0; + pixels[(height - 2) * rowstride + 3] = 0x80; + pixels[(height - 3) * rowstride + 3] = 0xC0; + + /* Bottom right */ + pixels[height * rowstride - 1] = 0; + pixels[(height - 1) * rowstride - 1] = 0x80; + pixels[(height - 2) * rowstride - 1] = 0xC0; + pixels[height * rowstride - 5] = 0x80; + pixels[height * rowstride - 9] = 0xC0; } const char *pidgin_get_dim_grey_string(GtkWidget *widget) {
--- a/pidgin/gtkutils.h Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/gtkutils.h Wed Sep 22 14:17:09 2010 +0900 @@ -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,
--- a/pidgin/minidialog.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/minidialog.c Wed Sep 22 14:17:09 2010 +0900 @@ -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 */
--- a/pidgin/minidialog.h Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/minidialog.h Wed Sep 22 14:17:09 2010 +0900 @@ -73,6 +73,8 @@ * <dd>The Gtk stock id of an icon for the dialog, or @c NULL for no icon. * @see pidginstock.h * </dd> + * <dt><tt>"custom-icon"</tt> (<tt>GdkPixbuf *</tt>)</dt> + * <dd>The custom icon to use instead of a stock one (overrides the "icon-name" property).</dd> * </dl> */ 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 <tt>clicked</tt> signal. After a button is clicked, the dialog is * destroyed.
--- a/pidgin/pidginstock.h Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/pidginstock.h Wed Sep 22 14:17:09 2010 +0900 @@ -44,7 +44,7 @@ #define PIDGIN_STOCK_DOWNLOAD "pidgin-download" #define PIDGIN_STOCK_EDIT "pidgin-edit" #define PIDGIN_STOCK_FGCOLOR "pidgin-fgcolor" -#define PIDGIN_STOCK_FILE_CANCELED "pidgin-file-canceled" +#define PIDGIN_STOCK_FILE_CANCELED "pidgin-file-cancelled" #define PIDGIN_STOCK_FILE_DONE "pidgin-file-done" #define PIDGIN_STOCK_IGNORE "pidgin-ignore" #define PIDGIN_STOCK_INFO "pidgin-info"
--- a/pidgin/pixmaps/emotes/default/24/default.theme.in Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/pixmaps/emotes/default/24/default.theme.in Wed Sep 22 14:17:09 2010 +0900 @@ -419,6 +419,98 @@ female-fighter.png o-+ O-+ yin-yang.png (%) +# Following Yahoo! Messenger 8.1 +[Yahoo JAPAN] +happy.png :) :-) +question.png :-/ :-\\ +shocked.png :-O :O :-o :o +devil.png >:) +angel.png O:-) o:-) 0:-) +sick.png :-& +sleepy.png (:| +hypnotized.png @-) +on-the-phone.png :)] +sad.png :( :-( +amorous.png :x :-x :X :-X +angry.png X-( x-( X( x( +crying.png :(( +glasses-nerdy.png :-B :-b +quiet.png :-$ +drool.png =P~ =p~ +lying.png :^O :^o +call-me.png :-c +wink.png ;) ;-) +embarrassed.png :"> +mean.png :-> :> +laugh.png :)) :-)) +bye.png =; +arrogant.png [-( +thinking.png :-? +waiting.png :-w :-W +at-wits-end.png ~x( ~X( +excited.png :D :-D :d :-d +tongue.png :-P :P :-p :p +glasses-cool.png B-) b-) +neutral.png :| :-| +sleeping.png I-) i-) |-) +clown.png :o) :O) +doh.png #-o #-O +weep.png :-< +go-away.png :-h +lashes.png ;;) +kiss.png :-* :* +confused.png :-S :-s +sarcastic.png /:) +eyeroll.png 8-| +silly.png 8-} +clap.png =D> =d> +mad-tongue.png >:P >:p +time-out.png :-t :-T +hug-left.png >:D< >:d< +love-over.png =(( +hot.png #:-S #:-s +rotfl.png =)) :-j :-J +loser.png L-) l-) +party.png <:-P <:-p +nervous.png :-SS :-Ss :-sS :-ss +cowboy.png <):) +desire.png 8-> +! skywalker.png C:-) c:-) C:) c:) +! monkey.png :-(|) :(|) + +# Hidden Yahoo emotes +alien.png =:) >-) +beat-up.png b-( B-( +chicken.png ~:> +coffee.png ~o) ~O) +cow.png 3:-O 3:-o +dance.png \\:D/ \\:d/ +rose.png @};- +dont-know.png :-L :-l +skeleton.png 8-X 8-x +lamp.png *-:) +monkey.png :(|) +coins.png $-) +peace.png :)>- +pig.png :@) +pray.png [-o< [-O< +pumpkin.png (~~) +shame.png [-X [-x +flag.png **== +clover.png %%- +musical-note.png :-" +giggle.png ;)) +worship.png ^:)^ +star.png (*) +waving.png >:/ +talktohand.png :-@ + +# Only available after activating the Yahoo! Fighter IMVironment +male-fighter1.png o-> O-> +male-fighter2.png o=> O=> +female-fighter.png o-+ O-+ +yin-yang.png (%) + # Following MySpaceIM Beta 1.0.697.0 [MySpaceIM] @@ -428,7 +520,7 @@ glasses-nerdy.png B) bulgy-eyes.png %) freaked-out.png :E -smile.png :) :-) +happy.png :) :-) amorous.png :X laugh.png :)) mohawk.png -:
--- a/pidgin/pixmaps/emotes/small/16/Makefile.am Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/pixmaps/emotes/small/16/Makefile.am Wed Sep 22 14:17:09 2010 +0900 @@ -34,7 +34,6 @@ confused.png \ console.png \ cold.png \ - cool.png \ cross.png \ crying.png \ devil.png \ @@ -44,7 +43,6 @@ excruciating.png \ eyeroll.png \ girl.png \ - grin.png \ happy.png \ hug-left.png \ hug-right.png \ @@ -77,6 +75,7 @@ star.png \ stressed.png \ thinking.png \ + thunder.png \ tongue.png \ tv.png \ uhm-yeah.png \
--- a/pidgin/pixmaps/emotes/small/16/small.theme.in Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/pixmaps/emotes/small/16/small.theme.in Wed Sep 22 14:17:09 2010 +0900 @@ -1,5 +1,5 @@ _Name=Small -_Description=Smaller versions of the default smilies +_Description=Smaller versions of the default smileys Icon=wink.png Author=Hylke Bons @@ -13,10 +13,12 @@ tongue.png :P :p :-P :-p shocked.png =-O =-o kiss.png :-* +glasses-cool.png 8-) embarrassed.png :-[ crying.png :'( :'-( thinking.png :-/ :-\\ angel.png O:-) o:-) +shut-mouth.png :-X [XMPP] @@ -29,18 +31,23 @@ tongue.png :P :p :-P :-p shocked.png =-O =-o :-O :-o kiss.png :kiss: :-* +glasses-cool.png 8-) B-) embarrassed.png :-[ crying.png :'-( :'( thinking.png :-/ :-\\ angel.png O:-) o:-) +shut-mouth.png :-X # Following XEP-0038 + GTalk angry.png >:-( >:( X-( x-( +rose.png @->-- :rose: phone.png :telephone: +lamp.png :jabber: in_love.png :heart: :love: <3 musical-note.png :music: beer.png :beer: coffee.png :coffee: +star.png :star: # Others neutral.png :| :-| @@ -61,6 +68,8 @@ angel.png O:-) thinking.png :-\\ :-/ crying.png :'( +shut-mouth.png :-X +glasses-cool.png 8-) # Following Windows Live Messenger 8.1 @@ -70,6 +79,7 @@ wink.png ;) ;-) shocked.png :-O :-o :O :o tongue.png :-P :P :-p :p +glasses-cool.png (H) (h) angry.png :@ :-@ embarrassed.png :$ :-$ confused.png :S :s :-S :-s @@ -79,21 +89,28 @@ devil.png (6) angel.png (A) (a) in_love.png (L) (l) +star.png (*) musical-note.png (8) +rose.png (F) (f) kiss.png (K) (k) camera.png (P) (p) +lamp.png (I) (i) coffee.png (C) (c) phone.png (T) (t) hug-left.png ({) hug-right.png (}) beer.png (B) (b) +boy.png (Z) (z) +girl.png (X) (x) sarcastic.png ^o) sick.png +o( plate.png (pl) mobile.png (mp) dont-know.png :^) thinking.png *-) +thunder.png (li) party.png <:o) +eyeroll.png 8-) sleepy.png |-) # Hidden MSN emotes @@ -106,28 +123,37 @@ shocked.png /:O /jy /surprised party.png /8-) /dy /revel crying.png /:< /ll /cry +shut-mouth.png /:X /bz /shut_mouth sleeping.png /:Z /shui /sleep embarrassed.png /:-| /gg /embarassed +pissed-off.png /:@ /fn /pissed_off excited.png /:D /cy /toothy_smile happy.png /:) /wx /small_smile sad.png /:( /ng /sad +glasses-cool.png /:+ /kuk /cool sick.png /:T /tu /vomit sleepy.png /|-) /kun /sleepy hot.png /:L /sweat question.png /? /yiw /question +excruciating.png /:8 /zhem /excrutiating afraid.png /shake /fad /shake amorous.png /love /aiq /love search.png /find /zhao /search hug-left.png /hug /yb /hug +lamp.png /! /dp /lightbulb +thunder.png /li /shd /lightning musical-note.png /music /yy /music coffee.png /coffee /kf /coffee hungry.png /eat /fan /eat +rose.png /rose /mg /rose kiss.png /kiss /wen /kiss in_love.png /heart /xin /heart meeting.png /meeting /hy /meeting phone.png /phone /dh /phone tv.png /TV /ds /TV angry.png /<O> /oh /angry +girl.png /<00> /nv /woman +boy.png /<11> /nan /man # Following ICQ 6.0 @@ -146,9 +172,12 @@ embarrassed.png :-[ devil.png ]:-> angel.png O:-) +rose.png @}->-- +shut-mouth.png :-X :X :-x :x thinking.png :-\\ :-/ beer.png *DRINK* excited.png :-D :D +glasses-cool.png 8-) amorous.png *IN\ LOVE* @@ -165,17 +194,21 @@ amorous.png :x :-x :X :-X angry.png X-( x-( X( x( crying.png :(( +drool.png =P~ =p~ +lying.png :^O :^o wink.png ;) ;-) embarrassed.png :"> mean.png :-> :> thinking.png :-? excited.png :D :-D :d :-d tongue.png :-P :P :-p :p +glasses-cool.png B-) b-) neutral.png :| :-| sleeping.png I-) i-) |-) kiss.png :-* :* confused.png :-S :-s sarcastic.png /:) +eyeroll.png 8-| hug-left.png >:D< >:d< hot.png #:-S #:-s party.png <:-P <:-p @@ -183,38 +216,48 @@ # Hidden Yahoo emotes coffee.png ~o) ~O) +rose.png @};- dont-know.png :-L :-l +lamp.png *-:) shame.png [-X [-x musical-note.png :-" +star.png (*) # Following Yahoo! Messenger 8.1 [Yahoo JAPAN] -smile.png :) :-) +happy.png :) :-) question.png :-/ :-\\ -shock.png :-O :O :-o :o +shocked.png :-O :O :-o :o devil.png >:) angel.png O:-) o:-) 0:-) sick.png :-& -yawn.png (:| +sleepy.png (:| sad.png :( :-( +amorous.png :x :-x :X :-X angry.png X-( x-( X( x( crying.png :(( wink.png ;) ;-) thinking.png :-? -smile-big.png :D :-D :d :-d +excited.png :D :-D :d :-d tongue.png :-P :P :-p :p +glasses-cool.png B-) b-) neutral.png :| :-| -sleepy.png I-) i-) |-) +sleeping.png I-) i-) |-) kiss.png :-* :* confused.png :-S :-s +sarcastic.png /:) +eyeroll.png 8-| hug-left.png >:D< >:d< party.png <:-P <:-p # Hidden Yahoo emotes coffee.png ~o) ~O) +rose.png @};- dont-know.png :-L :-l +lamp.png *-:) shame.png [-X [-x musical-note.png :-" +star.png (*) # Following MySpaceIM Beta 1.0.697.0 @@ -222,10 +265,13 @@ excited.png :D :-D devil.png }:) confused.png :Z +happy.png :) :-) amorous.png :X +pirate.png P) shocked.png :O neutral.png :| tongue.png :P :p +pissed-off.png B| wink.png ;-) ;) sad.png :[ kiss.png :x @@ -240,7 +286,7 @@ shocked.png :-O :O tongue.png :-P :P embarrassed.png :-$ :$ -cool.png 8-) +glasses-cool.png 8-) in_love.png (H) rose.png (F) ### Added in v3.0 @@ -252,7 +298,7 @@ lamp.png (i) pissed-off.png :e :-e shut-mouth.png :-x :x -grumpy.png (z) +thunder.png (z) coffee.png (U) mrgreen.png (G) ### Added in v5.0 @@ -265,7 +311,7 @@ drool.png :-~ :~ sleeping.png :-z :z lying.png :L) -nerdy.png 8-| 8| +glasses-nerdy.png 8-| 8| pirate.png P-) ### Added in v5.9.7 bored.png :-[ :[
--- a/pidgin/plugins/gevolution/add_buddy_dialog.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/plugins/gevolution/add_buddy_dialog.c Wed Sep 22 14:17:09 2010 +0900 @@ -54,8 +54,7 @@ gevo_addrbooks_model_unref(dialog->addrbooks); - if (dialog->username != NULL) - g_free(dialog->username); + g_free(dialog->username); g_free(dialog); @@ -289,7 +288,7 @@ { EContact *contact = E_CONTACT(c->data); const char *name; - GList *aims, *jabbers, *yahoos, *msns, *icqs, *novells; + GList *aims, *jabbers, *yahoos, *msns, *icqs, *novells, *ggs; name = e_contact_get_const(contact, E_CONTACT_FULL_NAME); @@ -299,9 +298,11 @@ msns = e_contact_get(contact, E_CONTACT_IM_MSN); icqs = e_contact_get(contact, E_CONTACT_IM_ICQ); novells = e_contact_get(contact, E_CONTACT_IM_GROUPWISE); + ggs = e_contact_get(contact, E_CONTACT_IM_GADUGADU); if (aims == NULL && jabbers == NULL && yahoos == NULL && - msns == NULL && icqs == NULL && novells == NULL) + msns == NULL && icqs == NULL && novells == NULL && + ggs == NULL) { GtkTreeIter iter; @@ -320,6 +321,7 @@ add_ims(dialog, contact, name, msns, "prpl-msn"); add_ims(dialog, contact, name, icqs, "prpl-icq"); add_ims(dialog, contact, name, novells, "prpl-novell"); + add_ims(dialog, contact, name, ggs, "prpl-gg"); } } @@ -365,7 +367,7 @@ { EContact *contact = E_CONTACT(l->data); const char *name; - GList *aims, *jabbers, *yahoos, *msns, *icqs, *novells; + GList *aims, *jabbers, *yahoos, *msns, *icqs, *novells, *ggs; name = e_contact_get_const(contact, E_CONTACT_FULL_NAME); @@ -381,9 +383,11 @@ msns = e_contact_get(contact, E_CONTACT_IM_MSN); icqs = e_contact_get(contact, E_CONTACT_IM_ICQ); novells = e_contact_get(contact, E_CONTACT_IM_GROUPWISE); + ggs = e_contact_get(contact, E_CONTACT_IM_GADUGADU); if (aims == NULL && jabbers == NULL && yahoos == NULL && - msns == NULL && icqs == NULL && novells == NULL) + msns == NULL && icqs == NULL && novells == NULL && + ggs == NULL) { GtkTreeIter iter; @@ -402,6 +406,7 @@ add_ims(dialog, contact, name, msns, "prpl-msn"); add_ims(dialog, contact, name, icqs, "prpl-icq"); add_ims(dialog, contact, name, novells, "prpl-novell"); + add_ims(dialog, contact, name, ggs, "prpl-gg"); } } }
--- a/pidgin/plugins/gevolution/gevo-util.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/plugins/gevolution/gevo-util.c Wed Sep 22 14:17:09 2010 +0900 @@ -111,6 +111,8 @@ protocol_field = E_CONTACT_IM_JABBER; else if (!strcmp(protocol_id, "prpl-novell")) protocol_field = E_CONTACT_IM_GROUPWISE; + else if (!strcmp(protocol_id, "prpl-gg")) + protocol_field = E_CONTACT_IM_GADUGADU; return protocol_field; }
--- a/pidgin/plugins/gevolution/gevolution.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/plugins/gevolution/gevolution.c Wed Sep 22 14:17:09 2010 +0900 @@ -125,6 +125,7 @@ update_ims_from_contact(contact, name, "prpl-msn", E_CONTACT_IM_MSN); update_ims_from_contact(contact, name, "prpl-icq", E_CONTACT_IM_ICQ); update_ims_from_contact(contact, name, "prpl-novell", E_CONTACT_IM_GROUPWISE); + update_ims_from_contact(contact, name, "prpl-gg", E_CONTACT_IM_GADUGADU); } static void
--- a/pidgin/plugins/gevolution/new_person_dialog.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/plugins/gevolution/new_person_dialog.c Wed Sep 22 14:17:09 2010 +0900 @@ -153,6 +153,8 @@ field = E_CONTACT_IM_MSN; else if (!strcmp(im_service, "prpl-novell")) field = E_CONTACT_IM_GROUPWISE; + else if (!strcmp(im_service, "prpl-gg")) + field = E_CONTACT_IM_GADUGADU; if (field > 0) { @@ -202,8 +204,7 @@ if (name != NULL) e_contact_name_free(name); - if (full_name != NULL) - g_free(full_name); + g_free(full_name); delete_win_cb(NULL, NULL, dialog); }
--- a/pidgin/plugins/notify.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/plugins/notify.c Wed Sep 22 14:17:09 2010 +0900 @@ -303,7 +303,6 @@ attach_signals(PurpleConversation *conv) { PidginConversation *gtkconv = NULL; - PidginWindow *gtkwin = NULL; GSList *imhtml_ids = NULL, *entry_ids = NULL; guint id; @@ -313,8 +312,6 @@ return 0; } - gtkwin = gtkconv->win; - if (purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_focus")) { /* TODO should really find a way to make this work no matter * where the focus is inside the conv window, without having @@ -358,13 +355,11 @@ detach_signals(PurpleConversation *conv) { PidginConversation *gtkconv = NULL; - PidginWindow *gtkwin = NULL; GSList *ids = NULL, *l; gtkconv = PIDGIN_CONVERSATION(conv); if (!gtkconv) return; - gtkwin = gtkconv->win; ids = purple_conversation_get_data(conv, "notify-imhtml-signals"); for (l = ids; l != NULL; l = l->next) @@ -650,7 +645,6 @@ apply_method() { GList *convs; - PidginWindow *purplewin = NULL; for (convs = purple_get_conversations(); convs != NULL; convs = convs->next) { @@ -659,7 +653,6 @@ /* remove notifications */ unnotify(conv, FALSE); - purplewin = PIDGIN_CONVERSATION(conv)->win; if (GPOINTER_TO_INT(purple_conversation_get_data(conv, "notify-message-count")) != 0) /* reattach appropriate notifications */ notify(conv, FALSE);
--- a/pidgin/plugins/vvconfig.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/plugins/vvconfig.c Wed Sep 22 14:17:09 2010 +0900 @@ -28,6 +28,9 @@ #include <gst/interfaces/propertyprobe.h> +/* container window for showing a stand-alone configurator */ +static GtkWidget *window = NULL; + static PurpleMediaElementInfo *old_video_src = NULL, *old_video_sink = NULL, *old_audio_src = NULL, *old_audio_sink = NULL; @@ -502,6 +505,59 @@ return TRUE; } +static void +config_destroy(GtkObject *w, gpointer nul) +{ + purple_debug_info("vvconfig", "closing vv configuration window\n"); + window = NULL; +} + +static void +config_close(GtkObject *w, gpointer nul) +{ + gtk_widget_destroy(GTK_WIDGET(window)); +} + +static void +show_config(PurplePluginAction *action) +{ + if (!window) { + GtkWidget *vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER); + GtkWidget *hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER); + GtkWidget *config_frame = get_plugin_config_frame(NULL); + GtkWidget *close = gtk_button_new_from_stock(GTK_STOCK_CLOSE); + + gtk_container_add(GTK_CONTAINER(vbox), config_frame); + gtk_container_add(GTK_CONTAINER(vbox), hbox); + window = pidgin_create_window(_("Voice/Video Settings"), + PIDGIN_HIG_BORDER, NULL, TRUE); + g_signal_connect(G_OBJECT(window), "destroy", + G_CALLBACK(config_destroy), NULL); + g_signal_connect(G_OBJECT(close), "clicked", + G_CALLBACK(config_close), NULL); + gtk_box_pack_end(GTK_BOX(hbox), close, FALSE, FALSE, PIDGIN_HIG_BORDER); + gtk_container_add(GTK_CONTAINER(window), vbox); + gtk_widget_show(GTK_WIDGET(close)); + gtk_widget_show(GTK_WIDGET(vbox)); + gtk_widget_show(GTK_WIDGET(hbox)); + } + gtk_window_present(GTK_WINDOW(window)); +} + + +static GList * +actions(PurplePlugin *plugin, gpointer context) +{ + GList *l = NULL; + PurplePluginAction *act = NULL; + + act = purple_plugin_action_new(_("Voice and Video Settings"), + show_config); + l = g_list_append(l, act); + + return l; +} + static gboolean plugin_unload(PurplePlugin *plugin) { @@ -525,32 +581,32 @@ static PurplePluginInfo info = { - PURPLE_PLUGIN_MAGIC, /**< magic */ - PURPLE_MAJOR_VERSION, /**< major version */ - PURPLE_MINOR_VERSION, /**< minor version */ - PURPLE_PLUGIN_STANDARD, /**< type */ - PIDGIN_PLUGIN_TYPE, /**< ui_requirement */ - 0, /**< flags */ - NULL, /**< dependencies */ - PURPLE_PRIORITY_DEFAULT, /**< priority */ + PURPLE_PLUGIN_MAGIC, /**< magic */ + PURPLE_MAJOR_VERSION, /**< major version */ + PURPLE_MINOR_VERSION, /**< minor version */ + PURPLE_PLUGIN_STANDARD, /**< type */ + PIDGIN_PLUGIN_TYPE, /**< ui_requirement */ + 0, /**< flags */ + NULL, /**< dependencies */ + PURPLE_PRIORITY_DEFAULT, /**< priority */ - "gtk-maiku-vvconfig", /**< id */ - N_("Voice/Video Settings"), /**< name */ - DISPLAY_VERSION, /**< version */ - N_("Configure your microphone and webcam."), /**< summary */ + "gtk-maiku-vvconfig", /**< id */ + N_("Voice/Video Settings"), /**< name */ + DISPLAY_VERSION, /**< version */ + N_("Configure your microphone and webcam."), /**< summary */ N_("Configure microphone and webcam " - "settings for voice/video calls."), /**< description */ - "Mike Ruprecht <cmaiku@gmail.com>", /**< author */ - PURPLE_WEBSITE, /**< homepage */ + "settings for voice/video calls."), /**< description */ + "Mike Ruprecht <cmaiku@gmail.com>", /**< author */ + PURPLE_WEBSITE, /**< homepage */ - plugin_load, /**< load */ - plugin_unload, /**< unload */ - NULL, /**< destroy */ + plugin_load, /**< load */ + plugin_unload, /**< unload */ + NULL, /**< destroy */ - &ui_info, /**< ui_info */ - NULL, /**< extra_info */ - NULL, /**< prefs_info */ - NULL, /**< actions */ + &ui_info, /**< ui_info */ + NULL, /**< extra_info */ + NULL, /**< prefs_info */ + actions, /**< actions */ /* padding */ NULL,
--- a/pidgin/plugins/xmppconsole.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/plugins/xmppconsole.c Wed Sep 22 14:17:09 2010 +0900 @@ -183,7 +183,7 @@ { GtkTextIter start, end; PurplePluginProtocolInfo *prpl_info = NULL; - PurpleConnection *gc = console->gc; + PurpleConnection *gc; GtkTextBuffer *buffer; char *text;
--- a/pidgin/win32/IdleTracker/Makefile.mingw Tue Aug 17 17:23:13 2010 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -# -# Makefile.mingw -# -# Description: Makefile for idletrack -# - -PIDGIN_TREE_TOP := ../../.. -include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak - -TARGET = idletrack - -## -## SOURCES, OBJECTS -## - -C_SRC = idletrack.c - -OBJECTS = $(C_SRC:%.c=%.o) - -include $(PIDGIN_COMMON_RULES) - -## -## TARGET DEFINITIONS -## - -.PHONY: all install clean - -all: $(TARGET).dll - -install: $(PIDGIN_INSTALL_DIR) - cp $(TARGET).dll $(PIDGIN_INSTALL_DIR) - -## -## BUILD DLL -## - -$(TARGET).dll $(TARGET).dll.a: $(OBJECTS) - $(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -Wl,--out-implib,$(TARGET).dll.a -o $(TARGET).dll - -## -## CLEAN RULES -## - -clean: - rm -f $(OBJECTS) $(TARGET).dll $(TARGET).dll.a - -include $(PIDGIN_COMMON_TARGETS)
--- a/pidgin/win32/IdleTracker/idletrack.c Tue Aug 17 17:23:13 2010 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +0,0 @@ -/* - * idletrack.c - * - * Authors: mrgentry @ http://www.experts-exchange.com - * Herman Bloggs <hermanator12002@yahoo.com> - * Date: February, 2003 - * Description: Track user inactivity. - * - * Andrew Whewell <awhewell@users.sourceforge.net> - 25th June 2004. Added - * support for GetLastInputInfo under Windows 2000 and above. This avoids having - * IDLETRACK.DLL hook itself into every process on the machine, which makes - * upgrades easier. The hook mechanism is also used by key loggers, so not - * using hooks doesn't put the willys up programs that keep an eye out for - * loggers. - * - * Windows 9x doesn't have GetLastInputInfo - when Purple runs on these machines - * the code silently falls back onto the old hooking scheme. - */ -#define _WIN32_WINNT 0x0500 -#include "idletrack.h" - -#define EXPORT __declspec(dllexport) - -static HANDLE hMapObject = NULL; -static DWORD *lastTime = NULL; -static HHOOK keyHook = NULL; -static HHOOK mouseHook = NULL; -static HINSTANCE g_hInstance = NULL; -static POINT g_point; - -/* GetLastInputInfo address and module - if g_GetLastInputInfo == NULL then - * we fall back on the old "hook the world" method. GetLastInputInfo was brought - * in with Windows 2000 so Windows 9x will still hook everything. - */ -typedef BOOL (WINAPI *GETLASTINPUTINFO)(LASTINPUTINFO *); -static HMODULE g_user32 = NULL; -static GETLASTINPUTINFO g_GetLastInputInfo = NULL; - -static DWORD* setup_shared_mem() { - BOOL fInit; - - /* Set up the shared memory. */ - hMapObject = CreateFileMapping((HANDLE) 0xFFFFFFFF, /* use paging file */ - NULL, /* no security attributes */ - PAGE_READWRITE, /* read/write access */ - 0, /* size: high 32-bits */ - sizeof(DWORD), /* size: low 32-bits */ - "timermem"); /* name of map object */ - - if(hMapObject == NULL) - return NULL; - - /* The first process to attach initializes memory. */ - fInit = (GetLastError() != ERROR_ALREADY_EXISTS); - - /* Get a pointer to the file-mapped shared memory. */ - lastTime = (DWORD*) MapViewOfFile(hMapObject, /* object to map view of */ - FILE_MAP_WRITE, /* read/write access */ - 0, /* high offset: map from */ - 0, /* low offset: beginning */ - 0); /* default: map entire file */ - - if(lastTime == NULL) - return NULL; - - *lastTime = GetTickCount(); - - return lastTime; -} - - -static LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) { - if(!(code < 0)) { - if(lastTime == NULL) - lastTime = setup_shared_mem(); - - if(lastTime) - *lastTime = GetTickCount(); - } - return CallNextHookEx(keyHook, code, wParam, lParam); -} - - -static LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam) { - /* We need to verify that the Mouse pointer has actually moved. */ - if(!(code < 0) && - !((g_point.x == ((MOUSEHOOKSTRUCT*) lParam)->pt.x) && - (g_point.y == ((MOUSEHOOKSTRUCT*) lParam)->pt.y))) { - g_point.x = ((MOUSEHOOKSTRUCT*) lParam)->pt.x; - g_point.y = ((MOUSEHOOKSTRUCT*) lParam)->pt.y; - - if(lastTime == NULL) - lastTime = setup_shared_mem(); - - if(lastTime) - *lastTime = GetTickCount(); - } - return CallNextHookEx(mouseHook, code, wParam, lParam); -} - - -EXPORT DWORD winpidgin_get_lastactive() { - DWORD result = 0; - - /* If we have GetLastInputInfo then use it, otherwise use the hooks*/ - if(g_GetLastInputInfo != NULL) { - LASTINPUTINFO lii; - memset(&lii, 0, sizeof(lii)); - lii.cbSize = sizeof(lii); - if(g_GetLastInputInfo(&lii)) { - result = lii.dwTime; - } - } else { - if(lastTime == NULL) - lastTime = setup_shared_mem(); - - if(lastTime) - result = *lastTime; - } - - return result; -} - - -EXPORT BOOL winpidgin_set_idlehooks() { - /* Is GetLastInputInfo available?*/ - g_user32 = LoadLibrary("user32.dll"); - if(g_user32) { - g_GetLastInputInfo = (GETLASTINPUTINFO) GetProcAddress(g_user32, "GetLastInputInfo"); - } - - /* If we couldn't find GetLastInputInfo then fall back onto the hooking scheme*/ - if(g_GetLastInputInfo == NULL) { - /* Set up the shared memory.*/ - lastTime = setup_shared_mem(); - if(lastTime == NULL) - return FALSE; - *lastTime = GetTickCount(); - - /* Set up the keyboard hook.*/ - keyHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0); - if(keyHook == NULL) { - UnmapViewOfFile(lastTime); - CloseHandle(hMapObject); - return FALSE; - } - - /* Set up the mouse hook.*/ - mouseHook = SetWindowsHookEx(WH_MOUSE, MouseProc, g_hInstance, 0); - if(mouseHook == NULL) { - UnhookWindowsHookEx(keyHook); - UnmapViewOfFile(lastTime); - CloseHandle(hMapObject); - return FALSE; - } - } - - return TRUE; -} - - -EXPORT void winpidgin_remove_idlehooks() { - if(g_user32 != NULL) - FreeLibrary(g_user32); - if(keyHook) - UnhookWindowsHookEx(keyHook); - if(mouseHook) - UnhookWindowsHookEx(mouseHook); - if(lastTime) - UnmapViewOfFile(lastTime); - if(hMapObject) - CloseHandle(hMapObject); -} - -/* suppress gcc "no previous prototype" warning */ -BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved); -BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { - switch(dwReason) { - case DLL_PROCESS_ATTACH: - g_hInstance = hInstance; - g_point.x = 0; - g_point.y = 0; - break; - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -}
--- a/pidgin/win32/IdleTracker/idletrack.h Tue Aug 17 17:23:13 2010 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -/* - * idletrack.h - */ -#include <windows.h> - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -DWORD winpidgin_get_lastactive(void); -BOOL winpidgin_set_idlehooks(void); -void winpidgin_remove_idlehooks(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */
--- a/pidgin/win32/gtkwin32dep.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/win32/gtkwin32dep.c Wed Sep 22 14:17:09 2010 +0900 @@ -43,7 +43,6 @@ #include "network.h" #include "resource.h" -#include "idletrack.h" #include "zlib.h" #include "untar.h" @@ -52,7 +51,9 @@ #include "gtkconv.h" #include "gtkconn.h" #include "util.h" +#ifdef USE_GTKSPELL #include "wspell.h" +#endif /* * GLOBALS @@ -377,15 +378,19 @@ void winpidgin_init(HINSTANCE hint) { FARPROC proc; + gchar *exchndl_dll_path; purple_debug_info("winpidgin", "winpidgin_init start\n"); exe_hInstance = hint; - proc = wpurple_find_and_loadproc("exchndl.dll", "SetLogFile"); + exchndl_dll_path = g_build_filename(wpurple_install_dir(), "exchndl.dll", NULL); + proc = wpurple_find_and_loadproc(exchndl_dll_path, "SetLogFile"); + g_free(exchndl_dll_path); + exchndl_dll_path = NULL; if (proc) { gchar *debug_dir, *locale_debug_dir; - + debug_dir = g_build_filename(purple_user_dir(), "pidgin.RPT", NULL); locale_debug_dir = g_locale_from_utf8(debug_dir, -1, NULL, NULL, NULL); @@ -397,11 +402,9 @@ g_free(locale_debug_dir); } - /* IdleTracker Initialization */ - if(!winpidgin_set_idlehooks()) - purple_debug_error("winpidgin", "Failed to initialize idle tracker\n"); - +#ifdef USE_GTKSPELL winpidgin_spell_init(); +#endif purple_debug_info("winpidgin", "GTK+ :%u.%u.%u\n", gtk_major_version, gtk_minor_version, gtk_micro_version); @@ -429,9 +432,6 @@ if(messagewin_hwnd) DestroyWindow(messagewin_hwnd); - /* Idle tracker cleanup */ - winpidgin_remove_idlehooks(); - } /* DLL initializer */ @@ -535,5 +535,18 @@ (winR.right - winR.left), (winR.bottom - winR.top), TRUE); } + } +DWORD winpidgin_get_lastactive() { + DWORD result = 0; + + LASTINPUTINFO lii; + memset(&lii, 0, sizeof(lii)); + lii.cbSize = sizeof(lii); + if (GetLastInputInfo(&lii)) + result = lii.dwTime; + + return result; +} +
--- a/pidgin/win32/gtkwin32dep.h Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/win32/gtkwin32dep.h Wed Sep 22 14:17:09 2010 +0900 @@ -39,6 +39,7 @@ void winpidgin_ensure_onscreen(GtkWidget *win); void winpidgin_conv_blink(PurpleConversation *conv, PurpleMessageFlags flags); void winpidgin_window_flash(GtkWindow *window, gboolean flash); +DWORD winpidgin_get_lastactive(void); /* init / cleanup */ void winpidgin_init(HINSTANCE);
--- a/pidgin/win32/nsis/pidgin-installer.nsi Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/win32/nsis/pidgin-installer.nsi Wed Sep 22 14:17:09 2010 +0900 @@ -268,7 +268,7 @@ DetailPrint "Downloading GTK+ Runtime ... ($R2)" NSISdl::download /TIMEOUT=10000 $R2 $R1 Pop $R0 - StrCmp $R0 "cancel" done + ;StrCmp $R0 "cancel" done StrCmp $R0 "success" +2 MessageBox MB_RETRYCANCEL "$(PIDGINGTKDOWNLOADERROR)" /SD IDCANCEL IDRETRY retry IDCANCEL done @@ -304,6 +304,7 @@ WriteRegStr HKLM "${HKLM_APP_PATHS_KEY}" "Path" "$INSTDIR\Gtk\bin" WriteRegStr HKLM ${PIDGIN_REG_KEY} "" "$INSTDIR" WriteRegStr HKLM ${PIDGIN_REG_KEY} "Version" "${PIDGIN_VERSION}" + WriteRegStr HKLM "${PIDGIN_UNINSTALL_KEY}" "DisplayIcon" "$INSTDIR\pidgin.exe" WriteRegStr HKLM "${PIDGIN_UNINSTALL_KEY}" "DisplayName" "Pidgin" WriteRegStr HKLM "${PIDGIN_UNINSTALL_KEY}" "DisplayVersion" "${PIDGIN_VERSION}" WriteRegStr HKLM "${PIDGIN_UNINSTALL_KEY}" "HelpLink" "http://developer.pidgin.im/wiki/Using Pidgin" @@ -317,6 +318,7 @@ pidgin_hkcu: WriteRegStr HKCU ${PIDGIN_REG_KEY} "" "$INSTDIR" WriteRegStr HKCU ${PIDGIN_REG_KEY} "Version" "${PIDGIN_VERSION}" + WriteRegStr HKCU "${PIDGIN_UNINSTALL_KEY}" "DisplayIcon" "$INSTDIR\pidgin.exe" WriteRegStr HKCU "${PIDGIN_UNINSTALL_KEY}" "DisplayName" "Pidgin" WriteRegStr HKCU "${PIDGIN_UNINSTALL_KEY}" "DisplayVersion" "${PIDGIN_VERSION}" WriteRegStr HKCU "${PIDGIN_UNINSTALL_KEY}" "HelpLink" "http://developer.pidgin.im/wiki/Using Pidgin" @@ -619,7 +621,6 @@ RMDir "$INSTDIR\spellcheck\lib" RMDir "$INSTDIR\spellcheck" Delete "$INSTDIR\freebl3.dll" - Delete "$INSTDIR\idletrack.dll" Delete "$INSTDIR\libjabber.dll" Delete "$INSTDIR\libnspr4.dll" Delete "$INSTDIR\libmeanwhile-1.dll"
--- a/pidgin/win32/winpidgin.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/win32/winpidgin.c Wed Sep 22 14:17:09 2010 +0900 @@ -605,9 +605,9 @@ char *lpszCmdLine, int nCmdShow) { wchar_t errbuf[512]; wchar_t pidgin_dir[MAX_PATH]; + wchar_t *pidgin_dir_start = NULL; wchar_t exe_name[MAX_PATH]; HMODULE hmod; - wchar_t *tmp; wchar_t *wtmp; int pidgin_argc; char **pidgin_argv; /* This is in utf-8 */ @@ -672,14 +672,14 @@ if (GetModuleFileNameW(NULL, pidgin_dir, MAX_PATH) != 0) { /* primitive dirname() */ - tmp = wcsrchr(pidgin_dir, L'\\'); + pidgin_dir_start = wcsrchr(pidgin_dir, L'\\'); - if (tmp) { + if (pidgin_dir_start) { HMODULE hmod; - tmp[0] = L'\0'; + pidgin_dir_start[0] = L'\0'; /* tmp++ will now point to the executable file name */ - wcscpy(exe_name, tmp + 1); + wcscpy(exe_name, pidgin_dir_start + 1); wcscat(pidgin_dir, L"\\exchndl.dll"); if ((hmod = LoadLibraryW(pidgin_dir))) { @@ -702,7 +702,8 @@ proc = GetProcAddress(hmod, "SetDebugInfoDir"); if (proc) { char *pidgin_dir_ansi = NULL; - tmp[0] = L'\0'; + /* Restore pidgin_dir to point to where the executable is */ + pidgin_dir_start[0] = L'\0'; i = WideCharToMultiByte(CP_ACP, 0, pidgin_dir, -1, NULL, 0, NULL, NULL); if (i != 0) { @@ -728,7 +729,8 @@ } - tmp[0] = L'\0'; + /* Restore pidgin_dir to point to where the executable is */ + pidgin_dir_start[0] = L'\0'; } } else { DWORD dw = GetLastError(); @@ -763,9 +765,14 @@ return 0; /* Now we are ready for Pidgin .. */ - if ((hmod = LoadLibraryW(L"pidgin.dll"))) + wcscat(pidgin_dir, L"\\pidgin.dll"); + if ((hmod = LoadLibraryW(pidgin_dir))) pidgin_main = (LPFNPIDGINMAIN) GetProcAddress(hmod, "pidgin_main"); + /* Restore pidgin_dir to point to where the executable is */ + if (pidgin_dir_start) + pidgin_dir_start[0] = L'\0'; + if (!pidgin_main) { DWORD dw = GetLastError(); BOOL mod_not_found = (dw == ERROR_MOD_NOT_FOUND || dw == ERROR_DLL_NOT_FOUND);
--- a/pidgin/win32/wspell.c Tue Aug 17 17:23:13 2010 +0900 +++ b/pidgin/win32/wspell.c Wed Sep 22 14:17:09 2010 +0900 @@ -22,6 +22,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA * */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#ifdef USE_GTKSPELL #include <windows.h> #include <string.h> #include <stdlib.h> @@ -73,28 +78,33 @@ static void load_gtkspell() { UINT old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS); gchar *tmp, *tmp2; + const char *path = g_getenv("PATH"); tmp = g_build_filename(wpurple_install_dir(), "spellcheck", NULL); - tmp2 = g_strdup_printf("%s%s%s", (path ? path : ""), + tmp2 = g_strdup_printf("%s%s%s", tmp, (path ? G_SEARCHPATH_SEPARATOR_S : ""), - tmp); + (path ? path : "")); g_free(tmp); g_setenv("PATH", tmp2, TRUE); + g_free(tmp2); + tmp = g_build_filename(wpurple_install_dir(), "spellcheck", GTKSPELL_DLL, NULL); /* Suppress error popups */ - wpidginspell_new_attach_proxy = (void*) wpurple_find_and_loadproc(GTKSPELL_DLL, "gtkspell_new_attach" ); + wpidginspell_new_attach_proxy = (void*) wpurple_find_and_loadproc(tmp, "gtkspell_new_attach" ); if (wpidginspell_new_attach_proxy) { - wpidginspell_get_from_text_view = (void*) wpurple_find_and_loadproc(GTKSPELL_DLL, "gtkspell_get_from_text_view"); - wpidginspell_detach = (void*) wpurple_find_and_loadproc(GTKSPELL_DLL, "gtkspell_detach"); - wpidginspell_set_language = (void*) wpurple_find_and_loadproc(GTKSPELL_DLL, "gtkspell_set_language"); - wpidginspell_recheck_all = (void*) wpurple_find_and_loadproc(GTKSPELL_DLL, "gtkspell_recheck_all"); + wpidginspell_get_from_text_view = (void*) wpurple_find_and_loadproc(tmp, "gtkspell_get_from_text_view"); + wpidginspell_detach = (void*) wpurple_find_and_loadproc(tmp, "gtkspell_detach"); + wpidginspell_set_language = (void*) wpurple_find_and_loadproc(tmp, "gtkspell_set_language"); + wpidginspell_recheck_all = (void*) wpurple_find_and_loadproc(tmp, "gtkspell_recheck_all"); } else { - purple_debug_warning("wspell", "Couldn't load gtkspell (%s) \n", GTKSPELL_DLL); + purple_debug_warning("wspell", "Couldn't load gtkspell (%s) \n", tmp); /*wpidginspell_new_attach = wgtkspell_new_attach;*/ } + g_free(tmp); SetErrorMode(old_error_mode); } void winpidgin_spell_init() { load_gtkspell(); } +#endif
--- a/po/af.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/af.po Wed Sep 22 14:17:09 2010 +0900 @@ -802,7 +802,7 @@ msgid "Waiting for transfer to begin" msgstr "Wag vir oordrag om te begin" -msgid "Canceled" +msgid "Cancelled" msgstr "Gekanselleer" msgid "Failed" @@ -15698,15 +15698,6 @@ #~ "afkomstig te wees. Dit kan beteken dat u nie tans aan die diens gekoppel " #~ "is wat u dink nie." -#~ msgid "You canceled the transfer of %s" -#~ msgstr "U het die oordrag van %s gekanselleer" - -#~ msgid "%s canceled the transfer of %s" -#~ msgstr "%s het die oordrag van %s gekanselleer" - -#~ msgid "%s canceled the file transfer" -#~ msgstr "%s het die lêeroordrag gekanselleer" - #~ msgid "Join/Part Hiding Configuration" #~ msgstr "Opstelling vir in- en uitgaanversteking" @@ -16292,7 +16283,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Kon nie %s vir skryf open nie!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "Lêeroordrag het misluk; ander kant het waarskynlik gekanselleer." #~ msgid "Could not connect for transfer."
--- a/po/am.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/am.po Wed Sep 22 14:17:09 2010 +0900 @@ -812,7 +812,7 @@ msgstr "" #, fuzzy -msgid "Canceled" +msgid "Cancelled" msgstr "ተወው" #, fuzzy
--- a/po/ar.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/ar.po Wed Sep 22 14:17:09 2010 +0900 @@ -791,7 +791,7 @@ msgid "Waiting for transfer to begin" msgstr "في انتظار بدء النقل" -msgid "Canceled" +msgid "Cancelled" msgstr "أُلغِيَ" msgid "Failed" @@ -16584,7 +16584,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "لايمكن فتح %s للكتابة!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "فشل ارسال الملف: من المحتمل أن المستقبِل ألغى العملية." #~ msgid "Could not connect for transfer."
--- a/po/as.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/as.po Wed Sep 22 14:17:09 2010 +0900 @@ -789,7 +789,7 @@ msgid "Waiting for transfer to begin" msgstr "বিনিময়ৰ আৰম্ভত অপেক্ষা কৰা হৈছে" -msgid "Canceled" +msgid "Cancelled" msgstr "বাতিল কৰা হৈছে" msgid "Failed"
--- a/po/az.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/az.po Wed Sep 22 14:17:09 2010 +0900 @@ -809,7 +809,7 @@ msgid "Waiting for transfer to begin" msgstr "" -msgid "Canceled" +msgid "Cancelled" msgstr "" msgid "Failed" @@ -16008,7 +16008,7 @@ #~ msgid "Invalid Groupname" #~ msgstr "Səhv istifadəçi adı." -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "Fayl transferi bacarılmadı, güman ki digər tərəfdən ləğv edildi." #~ msgid "Could not connect for transfer."
--- a/po/be@latin.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/be@latin.po Wed Sep 22 14:17:09 2010 +0900 @@ -801,7 +801,7 @@ msgid "Waiting for transfer to begin" msgstr "Čakańnie pačatku pieradačy" -msgid "Canceled" +msgid "Cancelled" msgstr "Anulavanaja" msgid "Failed" @@ -16704,7 +16704,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Niemahčyma adčynić %s dziela zapisu!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "Pamyłka pieradačy fajłu; aperacyja, mabyć, anulavanaja z taho boku." #~ msgid "Could not connect for transfer."
--- a/po/bg.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/bg.po Wed Sep 22 14:17:09 2010 +0900 @@ -820,7 +820,7 @@ msgid "Waiting for transfer to begin" msgstr "Изчакване пренасянето да започне" -msgid "Canceled" +msgid "Cancelled" msgstr "Отказан" msgid "Failed" @@ -16574,7 +16574,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "%s не може да бъде отворен за запис!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "" #~ "Неуспешен пренос на файла. Получателят вероятно е отказал получаването."
--- a/po/bn.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/bn.po Wed Sep 22 14:17:09 2010 +0900 @@ -843,7 +843,7 @@ msgid "Waiting for transfer to begin" msgstr "স্থানান্তর শুরু করার জন্য অপেক্ষা করা হচ্ছে" -msgid "Canceled" +msgid "Cancelled" msgstr "বাতিল করা হয়েছে" # mark6
--- a/po/bn_IN.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/bn_IN.po Wed Sep 22 14:17:09 2010 +0900 @@ -795,7 +795,7 @@ msgid "Waiting for transfer to begin" msgstr "পরিবহণ আরম্ভে অপেক্ষা চলছে" -msgid "Canceled" +msgid "Cancelled" msgstr "বাতিল করা হয়েছে" msgid "Failed"
--- a/po/bs.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/bs.po Wed Sep 22 14:17:09 2010 +0900 @@ -822,7 +822,7 @@ msgid "Waiting for transfer to begin" msgstr "Cekanje na pocetak transfera" -msgid "Canceled" +msgid "Cancelled" msgstr "Otkazano" msgid "Failed" @@ -17049,7 +17049,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Nije bilo moguce otvoriti %s za pisanje!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "Transfer datoteke je neuspio; druga strana je vjerovatno odustala." #~ msgid "Could not connect for transfer."
--- a/po/ca.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/ca.po Wed Sep 22 14:17:09 2010 +0900 @@ -834,7 +834,7 @@ msgid "Waiting for transfer to begin" msgstr "S'està esperant a iniciar la transferència" -msgid "Canceled" +msgid "Cancelled" msgstr "S'ha cancel·lat" msgid "Failed" @@ -16326,7 +16326,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "No s'ha pogut obrir %s per a escriure-hi." -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "" #~ "Ha fallat la transferència de fitxers. Probablement s'ha cancel·lat a " #~ "l'altra banda."
--- a/po/ca@valencia.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/ca@valencia.po Wed Sep 22 14:17:09 2010 +0900 @@ -834,7 +834,7 @@ msgid "Waiting for transfer to begin" msgstr "S'està esperant a iniciar la transferència" -msgid "Canceled" +msgid "Cancelled" msgstr "S'ha cancel·lat" msgid "Failed" @@ -16324,7 +16324,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "No s'ha pogut obrir %s per a escriure-hi." -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "" #~ "Ha fallat la transferència de fitxers. Probablement s'ha cancel·lat a " #~ "l'altra banda."
--- a/po/cs.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/cs.po Wed Sep 22 14:17:09 2010 +0900 @@ -793,7 +793,7 @@ msgid "Waiting for transfer to begin" msgstr "Čekám na začátek přenosu" -msgid "Canceled" +msgid "Cancelled" msgstr "Zrušeno" msgid "Failed" @@ -16042,7 +16042,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Nemohu otevřít %s pro zápis!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "Přenos souboru selhal; druhá strana jej pravděpodobně přerušila." #~ msgid "Could not connect for transfer."
--- a/po/da.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/da.po Wed Sep 22 14:17:09 2010 +0900 @@ -812,7 +812,7 @@ msgid "Waiting for transfer to begin" msgstr "Venter på at overførsel skal starte" -msgid "Canceled" +msgid "Cancelled" msgstr "Annulleret" msgid "Failed" @@ -16489,7 +16489,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Kunne ikke åbne %s til skrivning!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "Filoverførsel fejlede - den anden side har sikkert afbrudt." #~ msgid "Could not connect for transfer."
--- a/po/de.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/de.po Wed Sep 22 14:17:09 2010 +0900 @@ -11,9 +11,9 @@ msgstr "" "Project-Id-Version: de\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-08-01 00:18+0200\n" -"PO-Revision-Date: 2010-08-01 00:16+0200\n" -"Last-Translator: Jochen Kemnade <jochenkemnade@web.de>\n" +"POT-Creation-Date: 2010-09-02 19:45+0200\n" +"PO-Revision-Date: 2010-09-06 10:01+0200\n" +"Last-Translator: Björn Voigt <bjoern@cs.tu-berlin.de>\n" "Language-Team: Deutsch <de@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -813,7 +813,7 @@ msgid "Waiting for transfer to begin" msgstr "Warte auf den Beginn der Dateiübertragung" -msgid "Canceled" +msgid "Cancelled" msgstr "Abgebrochen" msgid "Failed" @@ -4723,7 +4723,7 @@ "role <moderator|participant|visitor|none> [nick1] [nick2] ...: Get the " "users with a role or set users' role with the room." msgstr "" -"role <owner|admin|member|outcast|none> [Spitzname1] [Spitzname2] ...: " +"role <moderator|participant|visitor|none> [Spitzname1] [Spitzname2] ...: " "Benutzer mit einer Rolle für den Raum erfragen oder Benutzern eine Rolle " "zuweisen." @@ -4772,11 +4772,17 @@ msgid "Domain" msgstr "Domain" -msgid "Require SSL/TLS" -msgstr "SSL/TLS voraussetzen" - -msgid "Force old (port 5223) SSL" -msgstr "Erzwinge altes SSL (Port 5223)" +msgid "Require encryption" +msgstr "Verschlüsselung fordern" + +msgid "Use encryption if available" +msgstr "Verschlüsselung benutzen, wenn verfügbar" + +msgid "Use old-style SSL" +msgstr "Alte SSL-Methode verwenden" + +msgid "Connection security" +msgstr "Verbindungssicherheit" msgid "Allow plaintext auth over unencrypted streams" msgstr "Erlaube Klartext-Authentifikation über einen unverschlüsselten Kanal" @@ -7218,96 +7224,6 @@ msgid "File %s is %s, which is larger than the maximum size of %s." msgstr "Datei %s (%s) ist größer als die maximale Größe von %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 "" -"(Es gab einen Fehler beim Empfangen dieser Nachricht. Der Buddy, mit dem " -"Sie sich unterhalten benutzt wahrscheinlich eine andere Kodierung als " -"erwartet. Wenn Sie wissen, welche Kodierung er benutzt, können Sie diese in " -"den erweiterten Konto-Optionen Ihres AIM/ICQ-Kontos angeben.)" - -#, 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 "" -"(Es gab einen Fehler beim Empfang dieser Nachricht. Entweder haben Sie und %" -"s unterschiedliche Kodierungen gesetzt oder %s hat einen fehlerhaften " -"Client.)" - -#. Label -msgid "Buddy Icon" -msgstr "Buddy-Icon" - -msgid "Voice" -msgstr "Stimme" - -msgid "AIM Direct IM" -msgstr "AIM direkte Nachricht" - -msgid "Get File" -msgstr "Datei abrufen" - -msgid "Games" -msgstr "Spiele" - -msgid "ICQ Xtraz" -msgstr "ICQ Xtraz" - -msgid "Add-Ins" -msgstr "Zusätze" - -msgid "Send Buddy List" -msgstr "Buddy-Liste senden" - -msgid "ICQ Direct Connect" -msgstr "ICQ direkte Verbindung" - -msgid "AP User" -msgstr "AP Benutzer" - -msgid "ICQ RTF" -msgstr "ICQ RTF" - -msgid "Nihilist" -msgstr "Nihilist" - -msgid "ICQ Server Relay" -msgstr "ICQ Server Relay" - -msgid "Old ICQ UTF8" -msgstr "Altes ICQ UTF-8" - -msgid "Trillian Encryption" -msgstr "Trillian-Verschlüsselung" - -msgid "ICQ UTF8" -msgstr "ICQ UTF-8" - -msgid "Hiptop" -msgstr "Hiptop" - -msgid "Security Enabled" -msgstr "Sicherheit aktiviert" - -msgid "Video Chat" -msgstr "Video-Chat" - -msgid "iChat AV" -msgstr "iChat AV" - -msgid "Live Video" -msgstr "Live-Video" - -msgid "Camera" -msgstr "Kamera" - -msgid "Screen Sharing" -msgstr "Gemeinsamer Bildschirm" - msgid "Free For Chat" msgstr "Bereit zum Chatten" @@ -7338,15 +7254,6 @@ msgid "At lunch" msgstr "Zur Mittagspause" -msgid "IP Address" -msgstr "IP-Adresse" - -msgid "Warning Level" -msgstr "Warnstufe" - -msgid "Buddy Comment" -msgstr "Buddy-Kommentar" - #, c-format msgid "Unable to connect to authentication server: %s" msgstr "Verbindung zum Authentifizierungsserver nicht möglich: %s" @@ -7446,17 +7353,6 @@ msgid "Unable to initialize connection" msgstr "Kann Verbindung nicht erstellen" -msgid "Please authorize me so I can add you to my buddy list." -msgstr "" -"Bitte autorisieren Sie mich, sodass ich Sie in meine Buddy-Liste aufnehmen " -"kann." - -msgid "No reason given." -msgstr "Kein Grund angegeben." - -msgid "Authorization Denied Message:" -msgstr "Nachricht für die Ablehnung der Autorisierung:" - #, c-format msgid "" "The user %u has denied your request to add them to your buddy list for the " @@ -7467,6 +7363,9 @@ "Liste hinzufügen zu dürfen, und zwar aus folgendem Grund:\n" "%s" +msgid "No reason given." +msgstr "Kein Grund angegeben." + msgid "ICQ authorization denied." msgstr "ICQ-Autorisierung verweigert." @@ -7582,60 +7481,13 @@ msgstr[1] "" "Sie haben %hu Nachrichten von %s aus unbekannten Gründen nicht erhalten." -#, c-format -msgid "User information not available: %s" -msgstr "Benutzerinformation nicht verfügbar: %s" - -msgid "Online Since" -msgstr "Online seit" - -msgid "Member Since" -msgstr "Mitglied seit" - -msgid "Capabilities" -msgstr "Fähigkeiten" - msgid "Your AIM connection may be lost." msgstr "Ihre AIM-Verbindung könnte unterbrochen sein." -#. The conversion failed! -msgid "" -"[Unable to display a message from this user because it contained invalid " -"characters.]" -msgstr "" -"[Kann die Nachricht von diesem Benutzer nicht anzeigen, da sie ungültige " -"Zeichen enthält.]" - #, c-format msgid "You have been disconnected from chat room %s." msgstr "Die Verbindung zum Raum %s wurde unterbrochen." -msgid "Mobile Phone" -msgstr "Handynummer" - -msgid "Personal Web Page" -msgstr "Persönliche Webseite" - -#. aim_userinfo_t -#. strip_html_tags -msgid "Additional Information" -msgstr "Zusätzliche Informationen" - -msgid "Zip Code" -msgstr "PLZ" - -msgid "Work Information" -msgstr "Information (Arbeit)" - -msgid "Division" -msgstr "Abteilung" - -msgid "Position" -msgstr "Position" - -msgid "Web Page" -msgstr "Webseite" - msgid "Pop-Up Message" msgstr "Pop-Up Nachricht" @@ -7922,8 +7774,8 @@ msgid "Change Address To:" msgstr "Ändere die Adresse zu:" -msgid "<i>you are not waiting for authorization</i>" -msgstr "<i>Sie warten derzeit auf keine Autorisierungen</i>" +msgid "you are not waiting for authorization" +msgstr "Sie warten derzeit auf keine Autorisierungen" msgid "You are awaiting authorization from the following buddies" msgstr "Sie warten auf Autorisierung von den folgenden Buddys" @@ -7978,9 +7830,6 @@ msgid "Search for Buddy by Email Address..." msgstr "Suche Buddys nach E-Mail-Adresse..." -msgid "Search for Buddy by Information" -msgstr "Suche Buddy nach Information" - msgid "Use clientLogin" msgstr "clientLogin benutzen" @@ -8268,8 +8117,8 @@ msgstr "Ihre Anfrage wurde abgelehnt." #, c-format -msgid "%u requires verification" -msgstr "%u erfordert Autorisierung" +msgid "%u requires verification: %s" +msgstr "%u erfordert Überprüfung: %s" msgid "Add buddy question" msgstr "Buddy-Frage hinzufügen" @@ -10146,6 +9995,9 @@ msgid "Computer" msgstr "Computer" +msgid "Mobile Phone" +msgstr "Handynummer" + msgid "PDA" msgstr "PDA" @@ -10580,6 +10432,9 @@ msgid "Write Error" msgstr "Schreibfehler" +msgid "IP Address" +msgstr "IP-Adresse" + msgid "Yahoo! Japan Profile" msgstr "Yahoo!-Japan-Profil" @@ -10621,6 +10476,9 @@ msgid "Cool Link 3" msgstr "Cooler Link 3" +msgid "Member Since" +msgstr "Mitglied seit" + msgid "Last Update" msgstr "Letzte Aktualisierung" @@ -11247,6 +11105,11 @@ "Listenfenster zu diesem Dialog zurückkehren und Konten hinzufügen, " "bearbeiten oder löschen" +#, 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 möchte Sie (%s) zu seiner oder ihrer Buddy-Liste hinzufügen%s%s" + #. Buddy List msgid "Background Color" msgstr "Hintergrundfarbe" @@ -11506,6 +11369,8 @@ msgid "Edit User Mood" msgstr "Benutzerstimmung ändern" +#. NOTE: Do not set any accelerator to Control+O. It is mapped by +#. gtk_blist_key_press_cb to "Get User Info" on the selected buddy. #. Buddies menu msgid "/_Buddies" msgstr "/_Buddys" @@ -13648,6 +13513,9 @@ msgid "_TURN server:" msgstr "_TURN-Server:" +msgid "_UDP Port:" +msgstr "_UDP-Port:" + msgid "Use_rname:" msgstr "_Benutzername:" @@ -14143,6 +14011,10 @@ "<b>Dateigröße:</b> %s\n" "<b>Bildgröße:</b> %dx%d" +#. Label +msgid "Buddy Icon" +msgstr "Buddy-Icon" + #, c-format msgid "The file '%s' is too large for %s. Please try a smaller image.\n" msgstr "" @@ -14228,7 +14100,7 @@ msgid "Small" msgstr "Klein" -msgid "Smaller versions of the default smilies" +msgid "Smaller versions of the default smileys" msgstr "Kleinere Versionen der Default-Smileys" msgid "Response Probability:" @@ -15079,6 +14951,9 @@ msgid "Half Operator" msgstr "Half-Operator" +msgid "Voice" +msgstr "Stimme" + msgid "Authorization dialog" msgstr "Autorisierungsdialog" @@ -15268,6 +15143,9 @@ msgid "Voice/Video Settings" msgstr "Sprach-/Video-Einstellungen" +msgid "Voice and Video Settings" +msgstr "Sprach- und Video-Einstellungen" + #. *< name #. *< version msgid "Configure your microphone and webcam." @@ -15397,7 +15275,7 @@ msgstr "" "Dieses Plugin ist nützlich zur Fehlersuche in XMPP-Servern oder -Clients." -#. $(^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"
--- a/po/dz.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/dz.po Wed Sep 22 14:17:09 2010 +0900 @@ -818,7 +818,7 @@ msgid "Waiting for transfer to begin" msgstr "གནས་སོར་འགོ་བཙུགས་ནིའི་དོན་ལུ་བསྒུག་དོ།" -msgid "Canceled" +msgid "Cancelled" msgstr "ཆ་མེད་བཏང་ཡི།" msgid "Failed" @@ -16889,7 +16889,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "བྲིས་ནིའི་དོན་ལུ %s ཁ་ཕྱེ་མ་ཚུགས།" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "ཡིག་སྣོད་གནས་སོར་འཐུས་ཤོར་བྱུང་ནུག ཕྱོགས་གཞན་མི་འདི་ཆ་མེད་བཏང་ཡི།" #~ msgid "Could not connect for transfer."
--- a/po/el.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/el.po Wed Sep 22 14:17:09 2010 +0900 @@ -804,7 +804,7 @@ msgid "Waiting for transfer to begin" msgstr "Αναμονή έναρξης μεταφοράς" -msgid "Canceled" +msgid "Cancelled" msgstr "Ακυρώθηκε" msgid "Failed" @@ -16284,7 +16284,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Αδύνατο το άνοιγμα του %s για εγγραφή!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "" #~ "Αποτυχία μεταφοράς αρχείου. Πιθανώς να ακυρώθηκε από την άλλη πλευρά."
--- a/po/en_AU.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/en_AU.po Wed Sep 22 14:17:09 2010 +0900 @@ -834,8 +834,8 @@ msgid "Waiting for transfer to begin" msgstr "Waiting for transfer to begin" -msgid "Canceled" -msgstr "Canceled" +msgid "Cancelled" +msgstr "Cancelled" msgid "Failed" msgstr "Failed" @@ -2128,14 +2128,14 @@ #, fuzzy, c-format msgid "You cancelled the transfer of %s" -msgstr "You canceled the transfer of %s" +msgstr "You cancelled the transfer of %s" msgid "File transfer cancelled" msgstr "File transfer cancelled" #, fuzzy, c-format msgid "%s cancelled the transfer of %s" -msgstr "%s canceled the transfer of %s" +msgstr "%s cancelled the transfer of %s" #, fuzzy, c-format msgid "%s cancelled the file transfer" @@ -9265,7 +9265,7 @@ #, fuzzy, c-format msgid "%d cancelled the transfer of %s" -msgstr "%s canceled the transfer of %s" +msgstr "%s cancelled the transfer of %s" #, fuzzy, c-format msgid "<b>Group Title:</b> %s<br>" @@ -9346,7 +9346,7 @@ #, fuzzy msgid "Place Closed" -msgstr "Canceled" +msgstr "Cancelled" msgid "Microphone" msgstr "" @@ -17062,8 +17062,8 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Could not open %s for writing!" -#~ msgid "File transfer failed; other side probably canceled." -#~ msgstr "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." +#~ msgstr "File transfer failed; other side probably cancelled." #~ msgid "Could not connect for transfer." #~ msgstr "Could not connect for transfer."
--- a/po/en_CA.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/en_CA.po Wed Sep 22 14:17:09 2010 +0900 @@ -834,7 +834,7 @@ msgid "Waiting for transfer to begin" msgstr "Waiting for transfer to begin" -msgid "Canceled" +msgid "Cancelled" msgstr "Cancelled" msgid "Failed" @@ -17050,7 +17050,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Could not open %s for writing!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "File transfer failed; other side probably cancelled." #~ msgid "Could not connect for transfer."
--- a/po/en_GB.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/en_GB.po Wed Sep 22 14:17:09 2010 +0900 @@ -793,7 +793,7 @@ msgid "Waiting for transfer to begin" msgstr "Waiting for transfer to begin" -msgid "Canceled" +msgid "Cancelled" msgstr "Cancelled" msgid "Failed"
--- a/po/eo.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/eo.po Wed Sep 22 14:17:09 2010 +0900 @@ -766,7 +766,7 @@ msgid "Waiting for transfer to begin" msgstr "Atendante la alŝutoeko" -msgid "Canceled" +msgid "Cancelled" msgstr "Rezignita" msgid "Failed"
--- a/po/es.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/es.po Wed Sep 22 14:17:09 2010 +0900 @@ -916,7 +916,7 @@ msgid "Waiting for transfer to begin" msgstr "Esperando el comienzo de la transferencia" -msgid "Canceled" +msgid "Cancelled" msgstr "Cancelado" msgid "Failed"
--- a/po/et.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/et.po Wed Sep 22 14:17:09 2010 +0900 @@ -795,7 +795,7 @@ msgid "Waiting for transfer to begin" msgstr "Oodatakse ülekande algust" -msgid "Canceled" +msgid "Cancelled" msgstr "Tühistatud" msgid "Failed" @@ -16081,7 +16081,7 @@ #~ msgid "Password Change Successful" #~ msgstr "Paroolimuutmine õnnestus" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "Tõrge ülekandmisel, ilmselt tühistas teine pool ülekande." #~ msgid "Could not connect for transfer."
--- a/po/eu.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/eu.po Wed Sep 22 14:17:09 2010 +0900 @@ -801,7 +801,7 @@ msgid "Waiting for transfer to begin" msgstr "Transferentzia hasteko zain" -msgid "Canceled" +msgid "Cancelled" msgstr "Bertan behera utzi da" msgid "Failed" @@ -16340,7 +16340,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Ezin izan da %s ireki idazteko!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "" #~ "Fitxategi-transferentziak huts egin du; beste aldekoak beharbada bertan " #~ "behera utziko zuen."
--- a/po/fa.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/fa.po Wed Sep 22 14:17:09 2010 +0900 @@ -808,7 +808,7 @@ msgid "Waiting for transfer to begin" msgstr "در حال انتظار برای آغاز انتقال" -msgid "Canceled" +msgid "Cancelled" msgstr "صرف نظر شد" msgid "Failed" @@ -16683,7 +16683,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "نمیتوان %s را برای نوشتن باز کرد!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "انتقال پرونده شکست خورد؛ احتمالاً طرف دیگر انصراف داده است." #~ msgid "Could not connect for transfer."
--- a/po/fi.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/fi.po Wed Sep 22 14:17:09 2010 +0900 @@ -802,7 +802,7 @@ msgid "Waiting for transfer to begin" msgstr "Odotetaan lähetyksen alkamista" -msgid "Canceled" +msgid "Cancelled" msgstr "Peruutettu" msgid "Failed" @@ -16262,7 +16262,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "%s:n avaaminen kirjoitusta varten epäonnistui!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "" #~ "Tiedostonsiirto epäonnistui. Toinen osapuoli luultavasti katkaisi siirron." @@ -17459,7 +17459,7 @@ #~ msgid "Your request to send file[%s] has been rejected by buddy[%d]" #~ msgstr "Pyyntösi lähettää tiedosto (%s) one evätty tuttavan (%d) toimesta" -#~ msgid "The sending process of file[%s] has been canceled by buddy[%d]" +#~ msgid "The sending process of file[%s] has been cancelled by buddy[%d]" #~ msgstr "Tiedoston (%s) lähetys on peruutettu tuttavan (%d) toimesta" #~ msgid "Blink tray icon for unread..."
--- a/po/fr.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/fr.po Wed Sep 22 14:17:09 2010 +0900 @@ -821,7 +821,7 @@ msgid "Waiting for transfer to begin" msgstr "En attente de début de transfert" -msgid "Canceled" +msgid "Cancelled" msgstr "Annulé" msgid "Failed" @@ -16009,7 +16009,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Impossible d'ouvrir %s pour l'écriture" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "" #~ "Échec du transfert de fichier. Annulation probable du correspondant."
--- a/po/ga.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/ga.po Wed Sep 22 14:17:09 2010 +0900 @@ -750,7 +750,7 @@ msgstr "" #, fuzzy -msgid "Canceled" +msgid "Cancelled" msgstr "Cealaithe" #, fuzzy
--- a/po/gl.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/gl.po Wed Sep 22 14:17:09 2010 +0900 @@ -807,7 +807,7 @@ msgid "Waiting for transfer to begin" msgstr "Agardando o comezo da transferencia" -msgid "Canceled" +msgid "Cancelled" msgstr "Cancelado" msgid "Failed"
--- a/po/gu.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/gu.po Wed Sep 22 14:17:09 2010 +0900 @@ -789,7 +789,7 @@ msgid "Waiting for transfer to begin" msgstr "પરિવહન શરૂ થવા માટે રાહ જોઈ રહ્યા છીએ" -msgid "Canceled" +msgid "Cancelled" msgstr "રદ થયેલ" msgid "Failed"
--- a/po/he.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/he.po Wed Sep 22 14:17:09 2010 +0900 @@ -781,7 +781,7 @@ msgid "Waiting for transfer to begin" msgstr "ממתין להעברה להתחיל" -msgid "Canceled" +msgid "Cancelled" msgstr "בוטל" msgid "Failed"
--- a/po/hi.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/hi.po Wed Sep 22 14:17:09 2010 +0900 @@ -780,7 +780,7 @@ msgid "Waiting for transfer to begin" msgstr "हस्तांतरण के शुरु होने की प्रतीक्षा करता है." -msgid "Canceled" +msgid "Cancelled" msgstr "रद्द" msgid "Failed"
--- a/po/hu.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/hu.po Wed Sep 22 14:17:09 2010 +0900 @@ -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 <kelemeng at gnome dot hu>\n" "Language-Team: Hungarian <gnome at fsf dot hu>\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 "" @@ -802,7 +804,7 @@ msgid "Waiting for transfer to begin" msgstr "Várakozás az átvitel indulására" -msgid "Canceled" +msgid "Cancelled" msgstr "Megszakítva" msgid "Failed" @@ -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 "<i>you are not waiting for authorization</i>" -msgstr "<i>Ön nem vár engedélyezésre</i>" +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.<BR><BR>" +"copyrighted by its contributors, a list of whom is also distributed with %" +"s. There is no warranty for %s.<BR><BR>" 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 @@ "<b>Fájlméret:</b> %s\n" "<b>Képméret:</b> %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"
--- a/po/hy.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/hy.po Wed Sep 22 14:17:09 2010 +0900 @@ -755,7 +755,7 @@ msgid "Waiting for transfer to begin" msgstr "" -msgid "Canceled" +msgid "Cancelled" msgstr "" msgid "Failed"
--- a/po/id.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/id.po Wed Sep 22 14:17:09 2010 +0900 @@ -815,7 +815,7 @@ msgid "Waiting for transfer to begin" msgstr "Menunggu transfer untuk mulai" -msgid "Canceled" +msgid "Cancelled" msgstr "Dibatalkan" msgid "Failed" @@ -16769,7 +16769,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "%s tidak dapat dibuka untuk penulisan!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "Transfer file gagal; sisi lainnya kemungkinan membatalkan." #~ msgid "Could not connect for transfer."
--- a/po/it.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/it.po Wed Sep 22 14:17:09 2010 +0900 @@ -808,7 +808,7 @@ msgid "Waiting for transfer to begin" msgstr "In attesa dell'inizio del trasferimento" -msgid "Canceled" +msgid "Cancelled" msgstr "Annullato" msgid "Failed"
--- a/po/ja.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/ja.po Wed Sep 22 14:17:09 2010 +0900 @@ -808,7 +808,7 @@ msgid "Waiting for transfer to begin" msgstr "転送開始を待っています" -msgid "Canceled" +msgid "Cancelled" msgstr "キャンセルしました" msgid "Failed" @@ -16759,7 +16759,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "書き込みモードで %s を開けません!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "" #~ "ファイル転送が失敗しました。おそらく向こう側がキャンセルしたのでしょう。"
--- a/po/ka.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/ka.po Wed Sep 22 14:17:09 2010 +0900 @@ -807,7 +807,7 @@ msgid "Waiting for transfer to begin" msgstr "ველოდები გადატანის დაწყებას" -msgid "Canceled" +msgid "Cancelled" msgstr "გაუქმებულია" #, fuzzy
--- a/po/km.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/km.po Wed Sep 22 14:17:09 2010 +0900 @@ -777,7 +777,7 @@ msgid "Waiting for transfer to begin" msgstr "រង់ចាំការផ្ទេរចាប់ផ្ដើម" -msgid "Canceled" +msgid "Cancelled" msgstr "បានបោះបង់" msgid "Failed"
--- a/po/kn.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/kn.po Wed Sep 22 14:17:09 2010 +0900 @@ -802,7 +802,7 @@ msgid "Waiting for transfer to begin" msgstr "ವರ್ಗಾವಣೆಯ ಪ್ರಾರಂಭಕ್ಕಾಗಿ ನಿರೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ" -msgid "Canceled" +msgid "Cancelled" msgstr "ರದ್ದಾಗಿದೆ" msgid "Failed" @@ -15930,7 +15930,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "ಬರೆಯುವದಕ್ಕಾಗಿ %s ತೆರೆಯಲು ಆಗಲಿಲ್ಲ" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "ಕಡತ ವರ್ಗಾವಣೆ ವಿಫಲ ; ಬಹುಶ: ಆಚೆಯವರು ರದ್ದು ಮಾಡಿದರು" #~ msgid "Could not connect for transfer."
--- a/po/ko.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/ko.po Wed Sep 22 14:17:09 2010 +0900 @@ -816,7 +816,7 @@ msgid "Waiting for transfer to begin" msgstr "전송 시작을 기다리고 있습니다." -msgid "Canceled" +msgid "Cancelled" msgstr "취소되었습니다." msgid "Failed" @@ -16691,7 +16691,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "쓰기 모드에서 %s 을(를) 열 수 없습니다!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "파일 전송에 실패했습니다. 아마도 상대측에서 취소한 것 같습니다." #~ msgid "Could not connect for transfer."
--- a/po/ku.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/ku.po Wed Sep 22 14:17:09 2010 +0900 @@ -828,7 +828,7 @@ msgid "Waiting for transfer to begin" msgstr "Li benda destpêkirina transferê ye" -msgid "Canceled" +msgid "Cancelled" msgstr "Hate Betalkirin" msgid "Failed"
--- a/po/lo.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/lo.po Wed Sep 22 14:17:09 2010 +0900 @@ -744,7 +744,7 @@ msgid "Waiting for transfer to begin" msgstr "" -msgid "Canceled" +msgid "Cancelled" msgstr "" msgid "Failed"
--- a/po/lt.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/lt.po Wed Sep 22 14:17:09 2010 +0900 @@ -826,7 +826,7 @@ msgid "Waiting for transfer to begin" msgstr "Laukiama perdavimo pradžios" -msgid "Canceled" +msgid "Cancelled" msgstr "Atšaukta" msgid "Failed"
--- a/po/mk.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/mk.po Wed Sep 22 14:17:09 2010 +0900 @@ -806,7 +806,7 @@ msgid "Waiting for transfer to begin" msgstr "Чекам да започне преносот" -msgid "Canceled" +msgid "Cancelled" msgstr "Откажано" msgid "Failed" @@ -16667,7 +16667,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Не можам да ја отворам %s за запишување!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "Размената на датотека не успеа. Другата страна веројатно откажа." #~ msgid "Could not connect for transfer."
--- a/po/ml.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/ml.po Wed Sep 22 14:17:09 2010 +0900 @@ -788,7 +788,7 @@ msgid "Waiting for transfer to begin" msgstr "ഇടപാടു് ആരംഭിക്കുന്നതിനായി കാത്തിരിക്കുന്നു" -msgid "Canceled" +msgid "Cancelled" msgstr "റദ്ദാക്കിയിരിക്കുന്നു" msgid "Failed"
--- a/po/mn.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/mn.po Wed Sep 22 14:17:09 2010 +0900 @@ -774,7 +774,7 @@ msgid "Waiting for transfer to begin" msgstr "Файл шилжүүлэлт эхлүүлэхийг хүлээж байна" -msgid "Canceled" +msgid "Cancelled" msgstr "Цуцлагдсан" msgid "Failed" @@ -15602,7 +15602,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Завсар хийхээр %sийг нээж чадсангүй!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "Файл дамжуулалт амжилттгүй боллоо." #~ msgid "Could not connect for transfer."
--- a/po/mr.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/mr.po Wed Sep 22 14:17:09 2010 +0900 @@ -779,7 +779,7 @@ msgid "Waiting for transfer to begin" msgstr "स्थानांतर सुरू करण्याची प्रतिक्षा करत आहे" -msgid "Canceled" +msgid "Cancelled" msgstr "रद्द केले" msgid "Failed"
--- a/po/ms_MY.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/ms_MY.po Wed Sep 22 14:17:09 2010 +0900 @@ -741,7 +741,7 @@ msgid "Waiting for transfer to begin" msgstr "" -msgid "Canceled" +msgid "Cancelled" msgstr "" msgid "Failed"
--- a/po/my_MM.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/my_MM.po Wed Sep 22 14:17:09 2010 +0900 @@ -834,7 +834,7 @@ msgid "Waiting for transfer to begin" msgstr "Waiting for transfer to begin" -msgid "Canceled" +msgid "Cancelled" msgstr "Cancelled" msgid "Failed" @@ -17057,7 +17057,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Could not open %s for writing!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "File transfer failed; other side probably cancelled." #~ msgid "Could not connect for transfer."
--- a/po/nb.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/nb.po Wed Sep 22 14:17:09 2010 +0900 @@ -803,7 +803,7 @@ msgid "Waiting for transfer to begin" msgstr "Venter på at overføringen skal starte" -msgid "Canceled" +msgid "Cancelled" msgstr "Avbrutt" msgid "Failed" @@ -16208,7 +16208,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Klarte ikke åpne %s for skriving!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "" #~ "Filoverføringen mislyktes - sannsynligvis avbrutt på den andre siden."
--- a/po/ne.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/ne.po Wed Sep 22 14:17:09 2010 +0900 @@ -824,7 +824,7 @@ msgid "Waiting for transfer to begin" msgstr "स्थानान्तरण सुरू गर्नकोलागि पर्खिरहेको" -msgid "Canceled" +msgid "Cancelled" msgstr "रद्द गरियो" msgid "Failed" @@ -17025,7 +17025,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "लेख्नका लागि %s खोल्न सकिदैन!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "फाइल स्थान्तरणमा असफल; अन्य साइड सम्भवत: रद्द गरियो ।" #~ msgid "Could not connect for transfer."
--- a/po/nl.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/nl.po Wed Sep 22 14:17:09 2010 +0900 @@ -804,7 +804,7 @@ msgid "Waiting for transfer to begin" msgstr "Wacht op starten van overdracht" -msgid "Canceled" +msgid "Cancelled" msgstr "Geannuleerd" msgid "Failed"
--- a/po/nn.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/nn.po Wed Sep 22 14:17:09 2010 +0900 @@ -797,7 +797,7 @@ msgid "Waiting for transfer to begin" msgstr "Ventar på at overføringa skal begynna" -msgid "Canceled" +msgid "Cancelled" msgstr "Avbroten" msgid "Failed"
--- a/po/oc.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/oc.po Wed Sep 22 14:17:09 2010 +0900 @@ -754,7 +754,7 @@ msgid "Waiting for transfer to begin" msgstr "" -msgid "Canceled" +msgid "Cancelled" msgstr "Anullat" msgid "Failed"
--- a/po/or.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/or.po Wed Sep 22 14:17:09 2010 +0900 @@ -799,7 +799,7 @@ msgid "Waiting for transfer to begin" msgstr "ସ୍ଥାନାନ୍ତରଣ ଆରମ୍ଭ ହେବାକୁ ଅପେକ୍ଷା କରୁଛି" -msgid "Canceled" +msgid "Cancelled" msgstr "ବାତିଲ କରାଗଲା" msgid "Failed"
--- a/po/pa.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/pa.po Wed Sep 22 14:17:09 2010 +0900 @@ -784,7 +784,7 @@ msgid "Waiting for transfer to begin" msgstr "ਭੇਜਣ ਸ਼ੁਰੂ ਕਰਨ ਦੀ ਉਡੀਕ ਜਾਰੀ" -msgid "Canceled" +msgid "Cancelled" msgstr "ਰੱਦ ਹੈ" msgid "Failed" @@ -15891,7 +15891,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "%s ਨੂੰ ਲਿਖਣ ਲਈ ਖੋਲਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "ਫਾਇਲ ਸੰਚਾਰ ਅਸਫਲ ਹੈ; ਦੂਜੇ ਪਾਸੇ ਤੋਂ ਰੱਦ ਕੀਤਾ ਗਿਆ ਹੈ।" #~ msgid "Could not connect for transfer."
--- a/po/pl.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/pl.po Wed Sep 22 14:17:09 2010 +0900 @@ -818,7 +818,7 @@ msgid "Waiting for transfer to begin" msgstr "Oczekiwanie na rozpoczęcie przesyłu" -msgid "Canceled" +msgid "Cancelled" msgstr "Anulowano" msgid "Failed"
--- a/po/ps.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/ps.po Wed Sep 22 14:17:09 2010 +0900 @@ -779,7 +779,7 @@ msgid "Waiting for transfer to begin" msgstr "" -msgid "Canceled" +msgid "Cancelled" msgstr "فسخ شوه" msgid "Failed"
--- a/po/pt.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/pt.po Wed Sep 22 14:17:09 2010 +0900 @@ -843,7 +843,7 @@ msgid "Waiting for transfer to begin" msgstr "Esperando que a transferência comece" -msgid "Canceled" +msgid "Cancelled" msgstr "Cancelado" msgid "Failed" @@ -17029,7 +17029,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Não foi possível abrir %s para escrita!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "" #~ "Tranferência de ficheiro falhou; o outro lado provavelmente cancelou-a."
--- a/po/pt_BR.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/pt_BR.po Wed Sep 22 14:17:09 2010 +0900 @@ -804,7 +804,7 @@ msgid "Waiting for transfer to begin" msgstr "Esperando o começo da transferência" -msgid "Canceled" +msgid "Cancelled" msgstr "Cancelada" msgid "Failed" @@ -16432,7 +16432,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Não foi possível abrir %s para escrita!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "" #~ "Transferência de arquivo falhou; o outro lado provavelmente cancelou-a."
--- a/po/ro.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/ro.po Wed Sep 22 14:17:09 2010 +0900 @@ -807,7 +807,7 @@ msgid "Waiting for transfer to begin" msgstr "Se așteaptă începerea transferului" -msgid "Canceled" +msgid "Cancelled" msgstr "Oprit" msgid "Failed"
--- a/po/ru.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/ru.po Wed Sep 22 14:17:09 2010 +0900 @@ -807,7 +807,7 @@ msgid "Waiting for transfer to begin" msgstr "Ожидание начала передачи" -msgid "Canceled" +msgid "Cancelled" msgstr "Отменено" msgid "Failed" @@ -16446,7 +16446,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Не удалось открыть %s для записи!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "" #~ "Не удалось произвести передачу файлов; вероятно, отменили на той стороне."
--- a/po/si.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/si.po Wed Sep 22 14:17:09 2010 +0900 @@ -757,7 +757,7 @@ msgid "Waiting for transfer to begin" msgstr "" -msgid "Canceled" +msgid "Cancelled" msgstr "අහෝසි කරන්න" msgid "Failed"
--- a/po/sk.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/sk.po Wed Sep 22 14:17:09 2010 +0900 @@ -803,7 +803,7 @@ msgid "Waiting for transfer to begin" msgstr "Čaká sa na začiatok prenosu" -msgid "Canceled" +msgid "Cancelled" msgstr "Zrušené" msgid "Failed" @@ -16124,7 +16124,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Nepodarilo sa otvoriť %s pre zápis!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "Prenos súboru zlyhal; druhá strana ho asi zrušila." #~ msgid "Could not connect for transfer."
--- a/po/sl.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/sl.po Wed Sep 22 14:17:09 2010 +0900 @@ -812,7 +812,7 @@ msgid "Waiting for transfer to begin" msgstr "Čakanje na začetek prenosa" -msgid "Canceled" +msgid "Cancelled" msgstr "Preklicano" msgid "Failed"
--- a/po/sq.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/sq.po Wed Sep 22 14:17:09 2010 +0900 @@ -814,7 +814,7 @@ msgid "Waiting for transfer to begin" msgstr "Po pritet të fillojë shpërngulja" -msgid "Canceled" +msgid "Cancelled" msgstr "Anuluar" msgid "Failed"
--- a/po/sr.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/sr.po Wed Sep 22 14:17:09 2010 +0900 @@ -791,7 +791,7 @@ msgid "Waiting for transfer to begin" msgstr "Чекам да пренос почне" -msgid "Canceled" +msgid "Cancelled" msgstr "Откажи" msgid "Failed" @@ -16453,7 +16453,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Не могу да отворим %s за упис!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "Неуспешан пренос датотеке; друга страна је вероватно отказала." #~ msgid "Could not connect for transfer."
--- a/po/sr@latin.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/sr@latin.po Wed Sep 22 14:17:09 2010 +0900 @@ -792,7 +792,7 @@ msgid "Waiting for transfer to begin" msgstr "Čekam da prenos počne" -msgid "Canceled" +msgid "Cancelled" msgstr "Otkaži" msgid "Failed" @@ -16471,7 +16471,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Ne mogu da otvorim %s za upis!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "Neuspešan prenos datoteke; druga strana je verovatno otkazala." #~ msgid "Could not connect for transfer."
--- a/po/sv.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/sv.po Wed Sep 22 14:17:09 2010 +0900 @@ -797,7 +797,7 @@ msgid "Waiting for transfer to begin" msgstr "Väntar på att överföringen ska inledas" -msgid "Canceled" +msgid "Cancelled" msgstr "Avbruten" msgid "Failed" @@ -16135,7 +16135,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Kunde inte öppna %s för läsning!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "" #~ "Filöverföringen misslyckades, antagligen eftersom andra sidan avbröt."
--- a/po/sw.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/sw.po Wed Sep 22 14:17:09 2010 +0900 @@ -784,7 +784,7 @@ msgid "Waiting for transfer to begin" msgstr "" -msgid "Canceled" +msgid "Cancelled" msgstr "Imeghairishwa" msgid "Failed"
--- a/po/ta.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/ta.po Wed Sep 22 14:17:09 2010 +0900 @@ -795,7 +795,7 @@ msgid "Waiting for transfer to begin" msgstr "பரிமாற்றம் ஆரம்பமாவதற்காக காத்திருக்கிறது" -msgid "Canceled" +msgid "Cancelled" msgstr "தவிர்க்கப்பட்டது" msgid "Failed" @@ -16101,7 +16101,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "%s யை எழுதுவதற்காக திறக்கமுடியவில்லை!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "கோப்பு அனுப்புதலில் பிழை; ஒருவேளை மறுபக்கத்தில் தவிர்த்திருக்கலாம்." #~ msgid "Could not connect for transfer."
--- a/po/te.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/te.po Wed Sep 22 14:17:09 2010 +0900 @@ -787,7 +787,7 @@ msgid "Waiting for transfer to begin" msgstr "ప్రారంభించడానికి బదిలీ కోసం నిరీక్షణ " -msgid "Canceled" +msgid "Cancelled" msgstr "రద్దుచేయి" msgid "Failed"
--- a/po/th.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/th.po Wed Sep 22 14:17:09 2010 +0900 @@ -804,7 +804,7 @@ msgid "Waiting for transfer to begin" msgstr "กำลังรอการรับส่งแฟ้ม" -msgid "Canceled" +msgid "Cancelled" msgstr "ยกเลิก" msgid "Failed"
--- a/po/tr.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/tr.po Wed Sep 22 14:17:09 2010 +0900 @@ -805,7 +805,7 @@ msgid "Waiting for transfer to begin" msgstr "Aktarımın başlaması bekleniyor" -msgid "Canceled" +msgid "Cancelled" msgstr "İptal Edildi" msgid "Failed" @@ -16367,7 +16367,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "%s yazma için açılamıyor!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "" #~ "Dosya transferi gerçekleştirilemedi; karşı taraf iptal etmiş olabilir."
--- a/po/uk.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/uk.po Wed Sep 22 14:17:09 2010 +0900 @@ -809,7 +809,7 @@ msgid "Waiting for transfer to begin" msgstr "Очікування початку передачі" -msgid "Canceled" +msgid "Cancelled" msgstr "Скасовано" msgid "Failed"
--- a/po/ur.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/ur.po Wed Sep 22 14:17:09 2010 +0900 @@ -815,7 +815,7 @@ msgid "Waiting for transfer to begin" msgstr "ٹرانسفر ہونے کے لئے انتظار کررہا ہے" -msgid "Canceled" +msgid "Cancelled" msgstr " منسوخ کیا گیا" msgid "Failed" @@ -16800,7 +16800,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "لکھنے کے لئے %s کھول نہیں سکا!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "فائل ٹرانسفر ناکام ہوا؛یا ممکن ہے دوسری حانب منسوخ ہوا ہے۔" #~ msgid "Could not connect for transfer."
--- a/po/vi.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/vi.po Wed Sep 22 14:17:09 2010 +0900 @@ -805,7 +805,7 @@ msgid "Waiting for transfer to begin" msgstr "Đợi bắt đầu truyền" -msgid "Canceled" +msgid "Cancelled" msgstr "Bị thôi" msgid "Failed"
--- a/po/xh.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/xh.po Wed Sep 22 14:17:09 2010 +0900 @@ -843,7 +843,7 @@ msgid "Waiting for transfer to begin" msgstr "Ulindele ukuba ukudlulisa kuqalise" -msgid "Canceled" +msgid "Cancelled" msgstr "IRhoxisiwe" msgid "Failed" @@ -17192,7 +17192,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "Akukwazekanga ukuvula i-%s malunga nokubhala!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "" #~ "Ukudluliswa kwefayili akuphumelelanga; mhlawumbi elinye icala licinyiwe."
--- a/po/zh_CN.po Tue Aug 17 17:23:13 2010 +0900 +++ b/po/zh_CN.po Wed Sep 22 14:17:09 2010 +0900 @@ -777,7 +777,7 @@ msgid "Waiting for transfer to begin" msgstr "正在等待传送开始" -msgid "Canceled" +msgid "Cancelled" msgstr "已取消" msgid "Failed" @@ -15530,7 +15530,7 @@ #~ msgid "Could not open %s for writing!" #~ msgstr "无法打开 %s 写入!" -#~ msgid "File transfer failed; other side probably canceled." +#~ msgid "File transfer failed; other side probably cancelled." #~ msgstr "文件传送失败;可能其中一端取消了传送。" #~ msgid "Could not connect for transfer."