Mercurial > pidgin.yaz
changeset 28876:cf9ea9f2c0bb
merge of '06b53ea832679e0dfb2e6d5d0c1b69e61f1bd38b'
and 'ea2f92f486297b27994d3652e14f799eb0964834'
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Wed, 04 Nov 2009 18:41:51 +0000 |
parents | 4575d8daba12 (diff) 8464e695c62b (current diff) |
children | a990da4540d3 86ff30fb8ae3 |
files | ChangeLog libpurple/protocols/jabber/JEPS |
diffstat | 54 files changed, 1059 insertions(+), 657 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Wed Nov 04 18:41:21 2009 +0000 +++ b/ChangeLog Wed Nov 04 18:41:51 2009 +0000 @@ -1,3 +1,4 @@ + Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul version 2.6.4 (??/??/20??): @@ -10,10 +11,20 @@ * Fix building the GnuTLS plugin with older versions of GnuTLS. * Fix DNS TXT query resolution. * Always rejoin open chats after an account reconnects. + AIM and ICQ: + * Better rate limit calculations and other improvements. (Aman Gupta) + * More detailed error messages when messages fail to send. (Aman Gupta) + * The simultaneous login account option is respected when using + the clientLogin authentication method. + MSN: * Don't forget display names for buddies. * Fix a random crash that might occur when idle. + * Fix more FQY 240 connection errors. + * Fix a crash that could occur when adding a buddy. + * Fix an occasional crash when sending message to an offline user. + * Fix a random crash that might occur when idle. * Fix a crash when logging in with some long non-ASCII passwords. (Shaun Lindsay) @@ -23,6 +34,9 @@ * Fix a crash when attempting to validate an invalid JID. * Resolve an issue when connecting to iChat Server when no resource is specified. + * Try to automatically find a STUN server by using an SRV lookup on the + account's domain, and use that for voice and video if found and the user + didn't set one manually in prefs. * Fix a crash when adding a buddy without an '@'. Yahoo:
--- a/autogen.sh Wed Nov 04 18:41:21 2009 +0000 +++ b/autogen.sh Wed Nov 04 18:41:51 2009 +0000 @@ -83,7 +83,7 @@ OUTPUT=`mktemp autogen-XXXXXX` - printf "%s" "running ${CMD} ${@}... " + printf "running %s %s... " ${CMD} "$*" ${CMD} ${@} >${OUTPUT} 2>&1 if [ $? != 0 ] ; then @@ -99,9 +99,17 @@ fi } +cleanup () { + rm -f autogen-?????? + echo + exit 2 +} + ############################################################################### # We really start here, yes, very sneaky! ############################################################################### +trap cleanup 2 + FIGLET=`which figlet 2> /dev/null` if [ x"${FIGLET}" != x"" ] ; then ${FIGLET} -f small ${PACKAGE} @@ -143,7 +151,7 @@ run_or_die ${INTLTOOLIZE} ${INTLTOOLIZE_FLAGS:-"-c -f --automake"} # This call to sed is needed to work around an annoying bug in intltool 0.40.6 # See http://developer.pidgin.im/ticket/9520 for details -run_or_die ${SED} "s:'\^\$\$lang\$\$':\^\$\$lang\$\$:g" -i po/Makefile.in.in +run_or_die ${SED} -i.bak -e "s:'\^\$\$lang\$\$':\^\$\$lang\$\$:g" po/Makefile.in.in run_or_die ${ACLOCAL} ${ACLOCAL_FLAGS:-"-I m4macros"} run_or_die ${AUTOHEADER} ${AUTOHEADER_FLAGS} run_or_die ${AUTOMAKE} ${AUTOMAKE_FLAGS:-"-a -c --gnu"}
--- a/finch/libgnt/gntentry.c Wed Nov 04 18:41:21 2009 +0000 +++ b/finch/libgnt/gntentry.c Wed Nov 04 18:41:51 2009 +0000 @@ -1044,8 +1044,11 @@ snprintf(entry->start, len + 1, "%s", text); entry->end = entry->start + len; - entry->scroll = entry->start + scroll; - entry->cursor = entry->end - cursor; + if ((entry->scroll = entry->start + scroll) > entry->end) + entry->scroll = entry->end; + + if ((entry->cursor = entry->end - cursor) > entry->end) + entry->cursor = entry->end; if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(entry), GNT_WIDGET_MAPPED)) entry_redraw(GNT_WIDGET(entry));
--- a/finch/libgnt/gnttextview.c Wed Nov 04 18:41:21 2009 +0000 +++ b/finch/libgnt/gnttextview.c Wed Nov 04 18:41:51 2009 +0000 @@ -67,6 +67,12 @@ static void reset_text_view(GntTextView *view); +static gboolean +text_view_contains(GntTextView *view, const char *str) +{ + return (str >= view->string->str && str < view->string->str + view->string->len); +} + static void gnt_text_view_draw(GntWidget *widget) { @@ -109,7 +115,7 @@ char back = *end; chtype fl = seg->flags; *end = '\0'; - if (select_start < view->string->str + seg->start && select_end > view->string->str + seg->end) { + if (select_start && select_start < view->string->str + seg->start && select_end > view->string->str + seg->end) { fl |= A_REVERSE; wattrset(widget->window, fl); wprintw(widget->window, "%s", (view->string->str + seg->start)); @@ -326,9 +332,10 @@ select_start = gnt_text_view_get_p(GNT_TEXT_VIEW(widget), x - widget->priv.x, y - widget->priv.y); g_timeout_add(500, too_slow, NULL); } else if (event == GNT_MOUSE_UP) { - if (select_start) { + GntTextView *view = GNT_TEXT_VIEW(widget); + if (text_view_contains(view, select_start)) { GString *clip; - select_end = gnt_text_view_get_p(GNT_TEXT_VIEW(widget), x - widget->priv.x, y - widget->priv.y); + select_end = gnt_text_view_get_p(view, x - widget->priv.x, y - widget->priv.y); if (select_end < select_start) { gchar *t = select_start; select_start = select_end; @@ -336,7 +343,7 @@ } if (select_start == select_end) { if (double_click) { - clip = select_word_text(GNT_TEXT_VIEW(widget), select_start); + clip = select_word_text(view, select_start); double_click = FALSE; } else { double_click = TRUE;
--- a/libpurple/Makefile.am Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/Makefile.am Wed Nov 04 18:41:51 2009 +0000 @@ -32,7 +32,7 @@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = purple.pc -SUBDIRS = $(GCONF_DIR) plugins protocols tests . example +SUBDIRS = $(GCONF_DIR) plugins protocols . tests example purple_coresources = \ account.c \
--- a/libpurple/account.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/account.c Wed Nov 04 18:41:51 2009 +0000 @@ -1050,6 +1050,16 @@ if(account->system_log) purple_log_free(account->system_log); + while (account->deny) { + g_free(account->deny->data); + account->deny = g_slist_delete_link(account->deny, account->deny); + } + + while (account->permit) { + g_free(account->permit->data); + account->permit = g_slist_delete_link(account->permit, account->permit); + } + priv = PURPLE_ACCOUNT_GET_PRIVATE(account); PURPLE_DBUS_UNREGISTER_POINTER(priv->current_error); if (priv->current_error) {
--- a/libpurple/cipher.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/cipher.c Wed Nov 04 18:41:51 2009 +0000 @@ -50,10 +50,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#include <glib.h> -#include <string.h> -#include <stdio.h> - #include "internal.h" #include "cipher.h" #include "dbus-maybe.h"
--- a/libpurple/dnsquery.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/dnsquery.c Wed Nov 04 18:41:51 2009 +0000 @@ -172,6 +172,7 @@ return FALSE; } +#ifdef USE_IDN static gboolean dns_str_is_ascii(const char *name) { @@ -183,6 +184,7 @@ return TRUE; } +#endif #if defined(PURPLE_DNSQUERY_USE_FORK) @@ -293,12 +295,11 @@ rc = purple_network_convert_idn_to_ascii(dns_params.hostname, &hostname); if (rc != 0) { write_to_parent(child_out, &rc, sizeof(rc)); - close(child_out); if (show_debug) fprintf(stderr, "dns[%d] Error: IDN conversion returned " "%d\n", getpid(), rc); dns_params.hostname[0] = '\0'; - continue; + break; } } else /* intentional to execute the g_strdup */ #endif @@ -323,14 +324,13 @@ rc = getaddrinfo(hostname, servname, &hints, &res); write_to_parent(child_out, &rc, sizeof(rc)); if (rc != 0) { - close(child_out); if (show_debug) printf("dns[%d] Error: getaddrinfo returned %d\n", getpid(), rc); dns_params.hostname[0] = '\0'; g_free(hostname); hostname = NULL; - continue; + break; } tmp = res; while (res) {
--- a/libpurple/dnssrv.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/dnssrv.c Wed Nov 04 18:41:51 2009 +0000 @@ -248,6 +248,7 @@ return list; } +#ifdef USE_IDN static gboolean dns_str_is_ascii(const char *name) { @@ -259,8 +260,60 @@ return TRUE; } +#endif #ifndef _WIN32 +static void +write_to_parent(int in, int out, gconstpointer data, gsize size) +{ + const guchar *buf = data; + gssize w; + + do { + w = write(out, buf, size); + if (w > 0) { + buf += w; + size -= w; + } else if (w < 0 && errno == EINTR) { + /* Let's try some more; */ + w = 1; + } + } while (size > 0 && w > 0); + + if (size != 0) { + /* An error occurred */ + close(out); + close(in); + _exit(0); + } +} + +/* Read size bytes to data. Dies if an error occurs. */ +static void +read_from_parent(int in, int out, gpointer data, gsize size) +{ + guchar *buf = data; + gssize r; + + do { + r = read(in, data, size); + if (r > 0) { + buf += r; + size -= r; + } else if (r < 0 && errno == EINTR) { + /* Let's try some more; */ + r = 1; + } + } while (size > 0 && r > 0); + + if (size != 0) { + /* An error occurred */ + close(out); + close(in); + _exit(0); + } +} + G_GNUC_NORETURN static void resolve(int in, int out) @@ -279,16 +332,12 @@ purple_restore_default_signal_handlers(); #endif - if (read(in, &query, sizeof(query)) <= 0) { - close(out); - close(in); - _exit(0); - } + read_from_parent(in, out, &query, sizeof(query)); size = res_query( query.query, C_IN, query.type, (u_char*)&answer, sizeof( answer)); if (size == -1) { - write(out, &(query.type), sizeof(query.type)); - write(out, &size, sizeof(int)); + write_to_parent(in, out, &(query.type), sizeof(query.type)); + write_to_parent(in, out, &size, sizeof(size)); close(out); close(in); _exit(0); @@ -353,19 +402,17 @@ if (query.type == T_SRV) ret = purple_srv_sort(ret); - /* TODO: Check return value */ - write(out, &(query.type), sizeof(query.type)); - write(out, &size, sizeof(size)); + write_to_parent(in, out, &(query.type), sizeof(query.type)); + write_to_parent(in, out, &size, sizeof(size)); while (ret != NULL) { - /* TODO: Check return value */ if (query.type == T_SRV) - write(out, ret->data, sizeof(PurpleSrvResponse)); + write_to_parent(in, out, ret->data, sizeof(PurpleSrvResponse)); if (query.type == T_TXT) { PurpleTxtResponse *response = ret->data; gsize l = strlen(response->content) + 1 /* null byte */; - write(out, &l, sizeof(l)); - write(out, response->content, l); + write_to_parent(in, out, &l, sizeof(l)); + write_to_parent(in, out, response->content, l); } g_free(ret->data);
--- a/libpurple/plugins/perl/Makefile.mingw Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/plugins/perl/Makefile.mingw Wed Nov 04 18:41:51 2009 +0000 @@ -7,10 +7,12 @@ PIDGIN_TREE_TOP := ../../.. include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak +DEFINES := $(subst -DWIN32_LEAN_AND_MEAN,,$(DEFINES)) + TARGET = perl # Perl headers with /* /* */ type comments.. Turn off warnings. -CFLAGS += -Wno-comment +GCCWARNINGS += -Wno-comment ## ## INCLUDE PATHS
--- a/libpurple/plugins/perl/common/Makefile.mingw Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/plugins/perl/common/Makefile.mingw Wed Nov 04 18:41:51 2009 +0000 @@ -5,9 +5,12 @@ # PIDGIN_TREE_TOP := ../../../.. -GCCWARNINGS := -Wno-comment -Waggregate-return -Wcast-align -Wdeclaration-after-statement -Werror-implicit-function-declaration -Wextra -Wno-sign-compare -Wno-unused-parameter -Winit-self -Wmissing-declarations -Wmissing-prototypes -Wpointer-arith -Wundef -Wno-unused include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak +GCCWARNINGS += -Wno-comment -Wno-unused -Wno-nested-externs + +DEFINES := $(subst -DWIN32_LEAN_AND_MEAN,,$(DEFINES)) + TARGET = Purple AUTOSPLIT = lib/auto/Purple/autosplit.ix EXTUTILS ?= C:/perl/lib/ExtUtils
--- a/libpurple/plugins/perl/perl-handlers.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/plugins/perl/perl-handlers.c Wed Nov 04 18:41:51 2009 +0000 @@ -649,6 +649,7 @@ static void destroy_cmd_handler(PurplePerlCmdHandler *handler) { + purple_cmd_unregister(handler->id); cmd_handlers = g_slist_remove(cmd_handlers, handler); if (handler->callback != NULL) @@ -705,7 +706,6 @@ return; } - purple_cmd_unregister(id); destroy_cmd_handler(handler); }
--- a/libpurple/protocols/jabber/JEPS Wed Nov 04 18:41:21 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -0045: IN PROGRESS - Multi-User Chat -0047: IN PROGRESS - In-Band Bytestreams -0060: NEED - Pub-Sub -0071: AWAITING FINAL SPEC - XHTML-IM -0073: NEED - Basic IM Protocol Suite -0080: NEED (Do we?) - Geographic Location Information -0084: NEED - User Avatars in Jabber -0085: NEED - Chat State Notifications -0089: WATCH - Generic Alerts -0093: NEED - Roster Item Exchange -0100: NEED - Gateway Interaction (Transports) -0115: WATCH - Client Capabilities -0117: NEED - Intermediate IM Protocol Suite -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/XEPS Wed Nov 04 18:41:51 2009 +0000 @@ -0,0 +1,4 @@ +0060: NEED + Pub-Sub +0080: NEED (Do we?) + Geographic Location Information
--- a/libpurple/protocols/jabber/caps.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/jabber/caps.c Wed Nov 04 18:41:51 2009 +0000 @@ -975,7 +975,7 @@ g_free(js->caps_hash); js->caps_hash = jabber_caps_calculate_hash(&info, "sha1"); g_list_free(info.identities); - g_list_free(features); + g_list_free(info.features); } const gchar* jabber_caps_get_own_hash(JabberStream *js)
--- a/libpurple/protocols/jabber/chat.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/jabber/chat.c Wed Nov 04 18:41:51 2009 +0000 @@ -692,11 +692,11 @@ } -void jabber_chat_change_nick(JabberChat *chat, const char *nick) +gboolean jabber_chat_change_nick(JabberChat *chat, const char *nick) { xmlnode *presence; char *full_jid; - PurplePresence *gpresence; + PurpleAccount *account; PurpleStatus *status; JabberBuddyState state; char *msg; @@ -706,11 +706,11 @@ purple_conv_chat_write(PURPLE_CONV_CHAT(chat->conv), "", _("Nick changing not supported in non-MUC chatrooms"), PURPLE_MESSAGE_SYSTEM, time(NULL)); - return; + return FALSE; } - gpresence = purple_account_get_presence(chat->js->gc->account); - status = purple_presence_get_active_status(gpresence); + account = purple_connection_get_account(chat->js->gc); + status = purple_account_get_active_status(account); purple_status_to_jabber(status, &state, &msg, &priority); @@ -722,6 +722,8 @@ jabber_send(chat->js, presence); xmlnode_free(presence); + + return TRUE; } void jabber_chat_part(JabberChat *chat, const char *msg)
--- a/libpurple/protocols/jabber/chat.h Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/jabber/chat.h Wed Nov 04 18:41:51 2009 +0000 @@ -89,7 +89,7 @@ void jabber_chat_register(JabberChat *chat); void jabber_chat_change_topic(JabberChat *chat, const char *topic); void jabber_chat_set_topic(PurpleConnection *gc, int id, const char *topic); -void jabber_chat_change_nick(JabberChat *chat, const char *nick); +gboolean jabber_chat_change_nick(JabberChat *chat, const char *nick); void jabber_chat_part(JabberChat *chat, const char *msg); void jabber_chat_track_handle(JabberChat *chat, const char *handle, const char *jid, const char *affiliation, const char *role);
--- a/libpurple/protocols/jabber/disco.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/jabber/disco.c Wed Nov 04 18:41:51 2009 +0000 @@ -421,6 +421,76 @@ } +/* should probably share this code with google.c, or maybe from 2.7.0 + introduce an abstracted hostname -> IP function in dns.c */ +static void +jabber_disco_stun_lookup_cb(GSList *hosts, gpointer data, + const char *error_message) +{ + JabberStream *js = (JabberStream *) data; + + if (error_message) { + purple_debug_error("jabber", "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 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_disco_stun_srv_resolve_cb(PurpleSrvResponse *resp, int results, gpointer data) +{ + JabberStream *js = (JabberStream *) data; + + purple_debug_info("jabber", "got %d SRV responses for STUN.\n", results); + js->srv_query_data = NULL; + + if (results > 0) { + purple_debug_info("jabber", "looking up IP for %s:%d\n", + resp[0].hostname, resp[0].port); + js->stun_query = + purple_dnsquery_a(resp[0].hostname, resp[0].port, + jabber_disco_stun_lookup_cb, js); + } +} + + static void jabber_disco_server_info_result_cb(JabberStream *js, const char *from, JabberIqType type, const char *id, @@ -471,7 +541,10 @@ /* autodiscover stun and relays */ jabber_google_send_jingle_info(js); } else { - /* TODO: add external service discovery here... */ + js->srv_query_data = + purple_srv_resolve("stun", "udp", js->user->domain, + jabber_disco_stun_srv_resolve_cb, js); + /* TODO: add TURN support later... */ } }
--- a/libpurple/protocols/jabber/google.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/jabber/google.c Wed Nov 04 18:41:51 2009 +0000 @@ -994,8 +994,9 @@ const char *grt = xmlnode_get_attrib_with_namespace(item, "t", "google:roster"); const char *subscription = xmlnode_get_attrib(item, "subscription"); + const char *ask = xmlnode_get_attrib(item, "ask"); - if (!subscription || !strcmp(subscription, "none")) { + 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. */
--- a/libpurple/protocols/jabber/jabber.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/jabber/jabber.c Wed Nov 04 18:41:51 2009 +0000 @@ -1825,7 +1825,7 @@ JabberFeature *feature = jabber_features->data; g_free(feature->namespace); g_free(feature); - jabber_features = g_list_remove_link(jabber_features, jabber_features); + jabber_features = g_list_delete_link(jabber_features, jabber_features); } } @@ -1862,7 +1862,7 @@ g_free(id->lang); g_free(id->name); g_free(id); - jabber_identities = g_list_remove_link(jabber_identities, jabber_identities); + jabber_identities = g_list_delete_link(jabber_identities, jabber_identities); } } @@ -2606,8 +2606,15 @@ if(!chat || !args || !args[0]) return PURPLE_CMD_RET_FAILED; - jabber_chat_change_nick(chat, args[0]); - return PURPLE_CMD_RET_OK; + if (!jabber_resourceprep_validate(args[0])) { + *error = g_strdup(_("Invalid nickname")); + return PURPLE_CMD_RET_FAILED; + } + + if (jabber_chat_change_nick(chat, args[0])) + return PURPLE_CMD_RET_OK; + else + return PURPLE_CMD_RET_FAILED; } static PurpleCmdRet jabber_cmd_chat_part(PurpleConversation *conv,
--- a/libpurple/protocols/jabber/jingle/jingle.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/jabber/jingle/jingle.c Wed Nov 04 18:41:51 2009 +0000 @@ -442,15 +442,15 @@ if (num_params > 0) { params = g_new0(GParameter, num_params); - purple_debug_info("jabber", - "setting param stun-ip for stream using Google auto-config: %s\n", - js->stun_ip); + 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 Google auto-config: %d\n", - js->stun_port); + "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);
--- a/libpurple/protocols/jabber/roster.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/jabber/roster.c Wed Nov 04 18:41:51 2009 +0000 @@ -72,7 +72,7 @@ const char *alias, GSList *groups) { GSList *buddies, *l; - GSList *pool = NULL; + PurpleAccount *account = purple_connection_get_account(js->gc); buddies = purple_find_buddies(js->gc->account, jid); @@ -117,25 +117,14 @@ groups = g_slist_delete_link(groups, l); } else { /* This buddy isn't in the group on the server anymore */ - pool = g_slist_prepend(pool, b); + purple_debug_info("jabber", "jabber_roster_parse(): Removing %s " + "from group '%s' on the local list\n", + purple_buddy_get_name(b), + purple_group_get_name(g)); + purple_blist_remove_buddy(b); } } - if (pool) { - GString *tmp = g_string_new(NULL); - GSList *list = pool; - for ( ; list; list = list->next) { - tmp = g_string_append(tmp, - purple_group_get_name(purple_buddy_get_group(list->data))); - if (list->next) - tmp = g_string_append(tmp, ", "); - } - - purple_debug_info("jabber", "jabber_roster_parse(): Removing %s from " - "groups: %s\n", jid, tmp->str); - g_string_free(tmp, TRUE); - } - if (groups) { char *tmp = roster_groups_join(groups); purple_debug_info("jabber", "jabber_roster_parse(): Adding %s to " @@ -145,17 +134,7 @@ while(groups) { PurpleGroup *g = purple_find_group(groups->data); - PurpleBuddy *b = NULL; - - /* If there are buddies we would otherwise delete, move them to - * the new group (instead of deleting them below) - */ - if (pool) { - b = pool->data; - pool = g_slist_delete_link(pool, pool); - } else { - b = purple_buddy_new(js->gc->account, jid, alias); - } + PurpleBuddy *b = purple_buddy_new(account, jid, alias); if(!g) { g = purple_group_new(groups->data); @@ -169,14 +148,6 @@ groups = g_slist_delete_link(groups, groups); } - /* Remove this person from all the groups they're no longer in on the - * server */ - while (pool) { - PurpleBuddy *b = pool->data; - purple_blist_remove_buddy(b); - pool = g_slist_delete_link(pool, pool); - } - g_slist_free(buddies); }
--- a/libpurple/protocols/msn/contact.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/msn/contact.c Wed Nov 04 18:41:51 2009 +0000 @@ -362,7 +362,7 @@ char *display_text; passport = xmlnode_get_data(xmlnode_get_child(member, node)); - if (!purple_email_is_valid(passport)) { + if (!msn_email_is_valid(passport)) { g_free(passport); return; } @@ -765,7 +765,7 @@ if (passport == NULL) continue; - if (!purple_email_is_valid(passport)) + if (!msn_email_is_valid(passport)) continue; if ((displayName = xmlnode_get_child(contactInfo, "displayName"))) @@ -1232,8 +1232,13 @@ if (user->invite_message) { char *tmp; body = g_markup_escape_text(user->invite_message, -1); - tmp = g_markup_escape_text(purple_connection_get_display_name(session->account->gc), -1); + + /* Ignore the cast, we treat it as const anyway. */ + tmp = (char *)purple_connection_get_display_name(session->account->gc); + tmp = tmp ? g_markup_escape_text(tmp, -1) : g_strdup(""); + invite = g_strdup_printf(MSN_CONTACT_INVITE_MESSAGE_XML, body, tmp); + g_free(body); g_free(tmp);
--- a/libpurple/protocols/msn/msn.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/msn/msn.c Wed Nov 04 18:41:51 2009 +0000 @@ -118,6 +118,29 @@ return buf; } +gboolean +msn_email_is_valid(const char *passport) +{ + if (purple_email_is_valid(passport)) { + /* Special characters aren't allowed in domains, so only go to '@' */ + while (*passport != '@') { + if (*passport == '/') + return FALSE; + else if (*passport == '?') + return FALSE; + else if (*passport == '=') + return FALSE; + /* MSN also doesn't like colons, but that's checked already */ + + passport++; + } + + return TRUE; + } + + return FALSE; +} + static gboolean msn_send_attention(PurpleConnection *gc, const char *username, guint type) { @@ -611,9 +634,14 @@ MsnSession *session = gc->proto_data; if (session) { MsnUser *user = msn_userlist_find_user(session->userlist, who); - if (user) + if (user) { /* Include these too: MSN_CLIENT_CAP_MSNMOBILE|MSN_CLIENT_CAP_MSNDIRECT ? */ - ret = (user->clientid & MSN_CLIENT_CAP_WEBMSGR) == 0; + if ((user->clientid & MSN_CLIENT_CAP_WEBMSGR) || + user->networkid == MSN_NETWORK_YAHOO) + ret = FALSE; + else + ret = TRUE; + } } else ret = FALSE; } @@ -1511,7 +1539,7 @@ bname = purple_buddy_get_name(buddy); - if (!purple_email_is_valid(bname)) { + if (!msn_email_is_valid(bname)) { gchar *buf; buf = g_strdup_printf(_("Unable to add the buddy %s because the username is invalid. Usernames must be valid email addresses."), bname); if (!purple_conv_present_error(bname, purple_connection_get_account(gc), buf))
--- a/libpurple/protocols/msn/msn.h Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/msn/msn.h Wed Nov 04 18:41:51 2009 +0000 @@ -133,6 +133,7 @@ ((MSN_CLIENT_ID_VERSION << 24) | \ (MSN_CLIENT_ID_CAPABILITIES)) +gboolean msn_email_is_valid(const char *passport); void msn_act_id(PurpleConnection *gc, const char *entry); void msn_send_privacy(PurpleConnection *gc); void msn_send_im_message(MsnSession *session, MsnMessage *msg);
--- a/libpurple/protocols/msn/notification.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/msn/notification.c Wed Nov 04 18:41:51 2009 +0000 @@ -670,7 +670,7 @@ "User %s is on both Allow and Block list; " "removing from Allow list.\n", user->passport); - msn_userlist_rem_buddy_from_list(session->userlist, user->passport, MSN_LIST_AL); + msn_user_unset_op(user, MSN_LIST_AL_OP); } if (user->networkid != MSN_NETWORK_UNKNOWN) { @@ -840,17 +840,48 @@ MsnSession *session; PurpleAccount *account; PurpleConnection *gc; - char *adl = g_strndup(payload, len); - char *reason = g_strdup_printf(_("Unknown error (%d): %s"), - GPOINTER_TO_INT(cmd->payload_cbdata), adl); - g_free(adl); + int error = GPOINTER_TO_INT(cmd->payload_cbdata); session = cmdproc->session; account = session->account; gc = purple_account_get_connection(account); - purple_notify_error(gc, NULL, _("Unable to add user"), reason); - g_free(reason); + if (error == 241) { + /* khc: some googling suggests that error 241 means the buddy is somehow + in the local list, but not the server list, and that we should add + those buddies to the addressbook. For now I will just notify the user + about the raw payload, because I am lazy */ + xmlnode *adl = xmlnode_from_str(payload, len); + GString *emails = g_string_new(NULL); + + xmlnode *domain = xmlnode_get_child(adl, "d"); + while (domain) { + const char *domain_str = xmlnode_get_attrib(domain, "n"); + xmlnode *contact = xmlnode_get_child(domain, "c"); + while (contact) { + g_string_append_printf(emails, "%s@%s\n", + xmlnode_get_attrib(contact, "n"), domain_str); + contact = xmlnode_get_next_twin(contact); + } + domain = xmlnode_get_next_twin(domain); + } + + purple_notify_error(gc, NULL, + _("The following users are missing from your addressbook"), + emails->str); + g_string_free(emails, TRUE); + xmlnode_free(adl); + } + else + { + char *adl = g_strndup(payload, len); + char *reason = g_strdup_printf(_("Unknown error (%d): %s"), + error, adl); + g_free(adl); + + purple_notify_error(gc, NULL, _("Unable to add user"), reason); + g_free(reason); + } } static void @@ -878,50 +909,49 @@ } static void -adl_241_error_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, - size_t len) +rml_error_parse(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len) { - /* khc: some googling suggests that error 241 means the buddy is somehow - in the local list, but not the server list, and that we should add - those buddies to the addressbook. For now I will just notify the user - about the raw payload, because I am lazy */ MsnSession *session; PurpleAccount *account; PurpleConnection *gc; - xmlnode *adl; - xmlnode *domain; - GString *emails; + char *adl, *reason; + int error = GPOINTER_TO_INT(cmd->payload_cbdata); session = cmdproc->session; account = session->account; gc = purple_account_get_connection(account); - adl = xmlnode_from_str(payload, len); - emails = g_string_new(NULL); + adl = g_strndup(payload, len); + reason = g_strdup_printf(_("Unknown error (%d): %s"), + error, adl); + g_free(adl); - domain = xmlnode_get_child(adl, "d"); - while (domain) { - const char *domain_str = xmlnode_get_attrib(domain, "n"); - xmlnode *contact = xmlnode_get_child(domain, "c"); - while (contact) { - g_string_append_printf(emails, "%s@%s\n", - xmlnode_get_attrib(contact, "n"), domain_str); - contact = xmlnode_get_next_twin(contact); - } - domain = xmlnode_get_next_twin(domain); - } - - purple_notify_error(gc, NULL, - _("The following users are missing from your addressbook"), emails->str); - g_string_free(emails, TRUE); - xmlnode_free(adl); + purple_notify_error(gc, NULL, _("Unable to remove user"), reason); + g_free(reason); } static void -adl_241_error_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +rml_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) { - cmdproc->last_cmd->payload_cb = adl_241_error_cmd_post; - cmd->payload_len = atoi(cmd->params[1]); + MsnSession *session; + PurpleAccount *account; + PurpleConnection *gc; + MsnCommand *cmd = cmdproc->last_cmd; + + session = cmdproc->session; + account = session->account; + gc = purple_account_get_connection(account); + + purple_debug_error("msn", "RML error\n"); + if (cmd->param_count > 1) { + cmd->payload_cb = rml_error_parse; + cmd->payload_len = atoi(cmd->params[1]); + cmd->payload_cbdata = GINT_TO_POINTER(error); + } else { + char *reason = g_strdup_printf(_("Unknown error (%d)"), error); + purple_notify_error(gc, NULL, _("Unable to remove user"), reason); + g_free(reason); + } } static void @@ -1068,7 +1098,17 @@ /* Where'd this come from? */ return; - if (cmd->param_count == 7) { + if (cmd->param_count == 8) { + /* Yahoo! Buddy, looks like */ + networkid = atoi(cmd->params[3]); + friendly = g_strdup(purple_url_decode(cmd->params[4])); + clientid = strtoul(cmd->params[5], NULL, 10); + + /* cmd->params[7] seems to be a URL to a Yahoo! icon: + https://sec.yimg.com/i/us/nt/b/purpley.1.0.png + ... and it's purple, HAH! + */ + } else if (cmd->param_count == 7) { /* MSNP14+ with Display Picture object */ networkid = atoi(cmd->params[3]); friendly = g_strdup(purple_url_decode(cmd->params[4])); @@ -2095,9 +2135,8 @@ msn_table_add_cmd(cbs_table, "fallback", "XFR", xfr_cmd); - msn_table_add_cmd(cbs_table, NULL, "241", adl_241_error_cmd); - msn_table_add_error(cbs_table, "ADL", adl_error); + msn_table_add_error(cbs_table, "RML", rml_error); msn_table_add_error(cbs_table, "FQY", fqy_error); msn_table_add_error(cbs_table, "USR", usr_error);
--- a/libpurple/protocols/msn/oim.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/msn/oim.c Wed Nov 04 18:41:51 2009 +0000 @@ -153,7 +153,7 @@ gpointer cb_data; } MsnOimRequestData; -static void msn_oim_request_helper(MsnOimRequestData *data); +static gboolean msn_oim_request_helper(MsnOimRequestData *data); static void msn_oim_request_cb(MsnSoapMessage *request, MsnSoapMessage *response, @@ -202,7 +202,7 @@ g_free(data); } -static void +static gboolean msn_oim_request_helper(MsnOimRequestData *data) { MsnSession *session = data->oim->session; @@ -224,13 +224,13 @@ const char *msn_p; token = msn_nexus_get_token(session->nexus, MSN_AUTH_MESSENGER_WEB); - g_return_if_fail(token != NULL); + g_return_val_if_fail(token != NULL, FALSE); msn_t = g_hash_table_lookup(token, "t"); msn_p = g_hash_table_lookup(token, "p"); - g_return_if_fail(msn_t != NULL); - g_return_if_fail(msn_p != NULL); + g_return_val_if_fail(msn_t != NULL, FALSE); + g_return_val_if_fail(msn_p != NULL, FALSE); passport = xmlnode_get_child(data->body, "Header/PassportCookie"); xml_t = xmlnode_get_child(passport, "t"); @@ -248,6 +248,8 @@ msn_soap_message_new(data->action, xmlnode_copy(data->body)), data->host, data->url, FALSE, msn_oim_request_cb, data); + + return FALSE; }
--- a/libpurple/protocols/msn/userlist.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/msn/userlist.c Wed Nov 04 18:41:51 2009 +0000 @@ -539,7 +539,7 @@ purple_debug_info("msn", "Add user: %s to group: %s\n", who, new_group_name); - if (!purple_email_is_valid(who)) + if (!msn_email_is_valid(who)) { /* only notify the user about problems adding to the friends list * maybe we should do something else for other lists, but it probably
--- a/libpurple/protocols/oscar/family_feedbag.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/oscar/family_feedbag.c Wed Nov 04 18:41:51 2009 +0000 @@ -389,11 +389,10 @@ /** * Locally find the presence flag item, and return the setting. The returned setting is a - * bitmask of the user flags that you are visible to. See the AIM_FLAG_* #defines - * in oscar.h + * bitmask of the preferences. See the AIM_SSI_PRESENCE_FLAG_* #defines in oscar.h. * * @param list A pointer to the current list of items. - * @return Return the current visibility mask. + * @return Return the current set of preferences. */ guint32 aim_ssi_getpresence(struct aim_ssi_item *list) { @@ -1130,9 +1129,11 @@ * should show up as idle or not, etc. * * @param od The oscar odion. - * @param presence I think it's a bitmask, but I only know what one of the bits is: - * 0x00000002 - Hide wireless? + * @param presence A bitmask of the first 32 entries [0-31] from + * http://dev.aol.com/aim/oscar/#FEEDBAG__BUDDY_PREFS + * 0x00000002 - Hide "eBuddy group" (whatever that is) * 0x00000400 - Allow others to see your idle time + * 0x00020000 - Don't show Recent Buddies * @return Return 0 if no errors, otherwise return the error number. */ int aim_ssi_setpresence(OscarData *od, guint32 presence) {
--- a/libpurple/protocols/oscar/family_icbm.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/oscar/family_icbm.c Wed Nov 04 18:41:51 2009 +0000 @@ -151,6 +151,55 @@ return AIM_CLIENTTYPE_UNKNOWN; } +/* + * Subtype 0x0001 - Error + */ +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, errcode = 0; + char *bn; + GSList *tlvlist; + + if (!(snac2 = aim_remsnac(od, snac->id))) { + purple_debug_misc("oscar", "icbm error: received response from unknown request!\n"); + return 0; + } + + if (snac2->family != SNAC_FAMILY_ICBM) { + purple_debug_misc("oscar", "icbm error: received response from invalid request! %d\n", snac2->family); + g_free(snac2->data); + g_free(snac2); + return 0; + } + + if (!(bn = snac2->data)) { + purple_debug_misc("oscar", "icbm error: received response from request without a buddy name!\n"); + g_free(snac2); + return 0; + } + + reason = byte_stream_get16(bs); + + tlvlist = aim_tlvlist_read(bs); + if (aim_tlv_gettlv(tlvlist, 0x0008, 1)) + errcode = aim_tlv_get16(tlvlist, 0x0008, 1); + aim_tlvlist_free(tlvlist); + + /* Notify the user that the message wasn't delivered */ + if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) + ret = userfunc(od, conn, frame, reason, errcode, bn); + + if (snac2) + g_free(snac2->data); + g_free(snac2); + + return ret; +} + /** * Subtype 0x0002 - Set ICBM parameters. * @@ -2789,7 +2838,9 @@ static int snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { - if (snac->subtype == 0x0005) + if (snac->subtype == 0x0001) + 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);
--- a/libpurple/protocols/oscar/family_oservice.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/oscar/family_oservice.c Wed Nov 04 18:41:51 2009 +0000 @@ -319,7 +319,10 @@ for (i = 0; i < numclasses; i++) { struct rateclass *rateclass; + guint32 delta; + struct timeval now; + gettimeofday(&now, NULL); rateclass = g_new0(struct rateclass, 1); rateclass->classid = byte_stream_get16(bs); @@ -339,11 +342,24 @@ * the new version hardcoded here. */ if (mod->version >= 3) - byte_stream_getrawbuf(bs, rateclass->unknown, sizeof(rateclass->unknown)); + { + rateclass->delta = byte_stream_get32(bs); + rateclass->dropping_snacs = byte_stream_get8(bs); + + delta = rateclass->delta; + + rateclass->last.tv_sec = now.tv_sec - delta / 1000; + delta %= 1000; + rateclass->last.tv_usec = now.tv_usec - delta * 1000; + } + else + { + rateclass->delta = rateclass->dropping_snacs = 0; + rateclass->last.tv_sec = now.tv_sec; + rateclass->last.tv_usec = now.tv_usec; + } rateclass->members = g_hash_table_new(g_direct_hash, g_direct_equal); - rateclass->last.tv_sec = 0; - rateclass->last.tv_usec = 0; conn->rateclasses = g_slist_prepend(conn->rateclasses, rateclass); } conn->rateclasses = g_slist_reverse(conn->rateclasses); @@ -383,8 +399,7 @@ */ /* - * Last step in the conn init procedure is to acknowledge that we - * agree to these draconian limitations. + * Subscribe to rate change information for all rate classes. */ aim_srv_rates_addparam(od, conn); @@ -451,7 +466,10 @@ aim_rxcallback_t userfunc; guint16 code, classid; struct rateclass *rateclass; + guint32 delta; + struct timeval now; + gettimeofday(&now, NULL); code = byte_stream_get16(bs); classid = byte_stream_get16(bs); @@ -468,8 +486,29 @@ rateclass->current = byte_stream_get32(bs); rateclass->max = byte_stream_get32(bs); - if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) - ret = userfunc(od, conn, frame, code, classid, rateclass->windowsize, rateclass->clear, rateclass->alert, rateclass->limit, rateclass->disconnect, rateclass->current, rateclass->max); + if (mod->version >= 3) + { + rateclass->delta = byte_stream_get32(bs); + rateclass->dropping_snacs = byte_stream_get8(bs); + + delta = rateclass->delta; + + rateclass->last.tv_sec = now.tv_sec - delta / 1000; + delta %= 1000; + rateclass->last.tv_usec = now.tv_usec - delta * 1000; + } + else + { + rateclass->delta = rateclass->dropping_snacs = 0; + rateclass->last.tv_sec = now.tv_sec; + rateclass->last.tv_usec = now.tv_usec; + } + + if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) { + /* Can't pass in guint8 via ... varargs, so we use an unsigned int */ + unsigned int dropping_snacs = rateclass->dropping_snacs; + ret = userfunc(od, conn, frame, code, classid, rateclass->windowsize, rateclass->clear, rateclass->alert, rateclass->limit, rateclass->disconnect, rateclass->current, rateclass->max, rateclass->delta, dropping_snacs); + } return ret; }
--- a/libpurple/protocols/oscar/flap_connection.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/oscar/flap_connection.c Wed Nov 04 18:41:51 2009 +0000 @@ -73,7 +73,7 @@ } void -flap_connection_send_version_with_cookie_and_clientinfo(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy, ClientInfo *ci) +flap_connection_send_version_with_cookie_and_clientinfo(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy, ClientInfo *ci, gboolean allow_multiple_logins) { FlapFrame *frame; GSList *tlvlist = NULL; @@ -94,7 +94,7 @@ aim_tlvlist_add_16(&tlvlist, 0x0018, (guint16)ci->minor); aim_tlvlist_add_16(&tlvlist, 0x0019, (guint16)ci->point); aim_tlvlist_add_16(&tlvlist, 0x001a, (guint16)ci->build); - aim_tlvlist_add_8(&tlvlist, 0x004a, 0x01); + aim_tlvlist_add_8(&tlvlist, 0x004a, (allow_multiple_logins ? 0x01 : 0x03)); aim_tlvlist_write(&frame->data, &tlvlist); @@ -131,11 +131,13 @@ rateclass_get_new_current(FlapConnection *conn, struct rateclass *rateclass, struct timeval *now) { unsigned long timediff; /* In milliseconds */ + guint32 current; timediff = (now->tv_sec - rateclass->last.tv_sec) * 1000 + (now->tv_usec - rateclass->last.tv_usec) / 1000; + current = ((rateclass->current * (rateclass->windowsize - 1)) + timediff) / rateclass->windowsize; - /* This formula is taken from the joscar API docs. Preesh. */ - return MIN(((rateclass->current * (rateclass->windowsize - 1)) + timediff) / rateclass->windowsize, rateclass->max); + /* This formula is taken from http://dev.aol.com/aim/oscar/#RATELIMIT */ + return MIN(current, rateclass->max); } /* @@ -161,8 +163,7 @@ new_current = rateclass_get_new_current(conn, rateclass, &now); - /* (Add 100ms padding to account for inaccuracies in the calculation) */ - if (new_current < rateclass->alert + 100) + if (rateclass->dropping_snacs || new_current <= rateclass->alert) /* Not ready to send this SNAC yet--keep waiting. */ return FALSE; @@ -245,10 +246,9 @@ gettimeofday(&now, NULL); new_current = rateclass_get_new_current(conn, rateclass, &now); - /* (Add 100ms padding to account for inaccuracies in the calculation) */ - if (new_current < rateclass->alert + 100) + if (rateclass->dropping_snacs || new_current <= rateclass->alert) { - purple_debug_info("oscar", "Current rate for conn %p would be %u, but we alert at %u; enqueueing\n", conn, new_current, (rateclass->alert + 100)); + purple_debug_info("oscar", "Current rate for conn %p would be %u, but we alert at %u; enqueueing\n", conn, new_current, rateclass->alert); enqueue = TRUE; }
--- a/libpurple/protocols/oscar/oscar.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/oscar/oscar.c Wed Nov 04 18:41:51 2009 +0000 @@ -144,6 +144,26 @@ }; static const int msgerrreasonlen = G_N_ELEMENTS(msgerrreason); +static const char * const errcodereason[] = { + N_("Invalid error"), + N_("Not logged in"), + N_("Cannot receive IM due to parental controls"), + N_("Cannot send SMS without accepting terms"), + N_("Cannot send SMS"), /* SMS_WITHOUT_DISCLAIMER is weird */ + N_("Cannot send SMS to this country"), + N_("Unknown error"), /* Undocumented */ + N_("Unknown error"), /* Undocumented */ + N_("Cannot send SMS to unknown country"), + N_("Bot accounts cannot initiate IMs"), + N_("Bot account cannot IM this user"), + N_("Bot account reached IM limit"), + N_("Bot account reached daily IM limit"), + N_("Bot account reached monthly IM limit"), + N_("Unable to receive offline messages"), + N_("Offline message store full") +}; +static const int errcodereasonlen = G_N_ELEMENTS(errcodereason); + /* All the libfaim->purple callback functions */ /* Only used when connecting with the old-style BUCP login */ @@ -1168,7 +1188,8 @@ ClientInfo icqinfo = CLIENTINFO_PURPLE_ICQ; flap_connection_send_version_with_cookie_and_clientinfo(od, conn, conn->cookielen, conn->cookie, - od->icq ? &icqinfo : &aiminfo); + od->icq ? &icqinfo : &aiminfo, + purple_account_get_bool(account, "allow_multiple_logins", OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS)); } else { flap_connection_send_version_with_cookie(od, conn, conn->cookielen, conn->cookie); @@ -1394,9 +1415,9 @@ presence = aim_ssi_getpresence(od->ssi.local); if (report_idle) - aim_ssi_setpresence(od, presence | 0x400); + aim_ssi_setpresence(od, presence | AIM_SSI_PRESENCE_FLAG_SHOWIDLE); else - aim_ssi_setpresence(od, presence & ~0x400); + aim_ssi_setpresence(od, presence & ~AIM_SSI_PRESENCE_FLAG_SHOWIDLE); } /** @@ -1877,7 +1898,7 @@ break; case 0x18: /* username connecting too frequently */ - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer.")); + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("Your username has been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer.")); break; case 0x1c: { @@ -1889,7 +1910,7 @@ } case 0x1d: /* IP address connecting too frequently */ - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("You have been connecting and disconnecting too frequently. Wait a minute and try again. If you continue to try, you will need to wait even longer.")); + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("Your IP address has been connecting and disconnecting too frequently. Wait a minute and try again. If you continue to try, you will need to wait even longer.")); break; default: purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Unknown reason")); @@ -2876,7 +2897,7 @@ if (text) { /* Read the number of contacts that we were sent */ errno = 0; - num = strtoul(text[0], NULL, 10); + num = text[0] ? strtoul(text[0], NULL, 10) : 0; if (num > 0 && errno == 0) { for (i=0; i<num; i++) { @@ -3217,17 +3238,18 @@ PurpleXfer *xfer; #endif va_list ap; - guint16 reason; - char *data, *buf; + guint16 reason, errcode; + char *data, *reason_str, *buf; va_start(ap, fr); reason = (guint16)va_arg(ap, unsigned int); + errcode = (guint16)va_arg(ap, unsigned int); data = va_arg(ap, char *); va_end(ap); purple_debug_error("oscar", - "Message error with data %s and reason %hu\n", - (data != NULL ? data : ""), reason); + "Message error with data %s and reason %hu and errcode %hu\n", + (data != NULL ? data : ""), reason, errcode); if ((data == NULL) || (*data == '\0')) /* We can't do anything if data is empty */ @@ -3242,14 +3264,27 @@ #endif /* Data is assumed to be the destination bn */ - buf = g_strdup_printf(_("Unable to send message: %s"), (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason.")); + + reason_str = g_strdup((reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason")); + if (errcode != 0 && errcode < errcodereasonlen) + buf = g_strdup_printf(_("Unable to send message: %s (%s)"), reason_str, + _(errcodereason[errcode])); + else + buf = g_strdup_printf(_("Unable to send message: %s"), reason_str); + if (!purple_conv_present_error(data, purple_connection_get_account(gc), buf)) { g_free(buf); - buf = g_strdup_printf(_("Unable to send message to %s:"), data ? data : "(unknown)"); - purple_notify_error(od->gc, NULL, buf, - (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason.")); + if (errcode != 0 && errcode < errcodereasonlen) + buf = g_strdup_printf(_("Unable to send message to %s: %s (%s)"), + data ? data : "(unknown)", reason_str, + _(errcodereason[errcode])); + else + buf = g_strdup_printf(_("Unable to send message to %s: %s"), + data ? data : "(unknown)", reason_str); + purple_notify_error(od->gc, NULL, buf, reason_str); } g_free(buf); + g_free(reason_str); return 1; } @@ -3740,7 +3775,8 @@ }; va_list ap; guint16 code, rateclass; - guint32 windowsize, clear, alert, limit, disconnect, currentavg, maxavg; + guint32 windowsize, clear, alert, limit, disconnect, currentavg, maxavg, delta; + guint8 dropping_snacs; va_start(ap, fr); code = (guint16)va_arg(ap, unsigned int); @@ -3752,23 +3788,28 @@ disconnect = va_arg(ap, guint32); currentavg = va_arg(ap, guint32); maxavg = va_arg(ap, guint32); + delta = va_arg(ap, guint32); + dropping_snacs = (guint8)va_arg(ap, unsigned int); va_end(ap); purple_debug_misc("oscar", "rate %s (param ID 0x%04hx): curavg = %u, maxavg = %u, alert at %u, " - "clear warning at %u, limit at %u, disconnect at %u (window size = %u)\n", + "clear warning at %u, limit at %u, disconnect at %u, delta is %u, dropping is %u (window size = %u)\n", (code < 5) ? codes[code] : codes[0], rateclass, currentavg, maxavg, alert, clear, limit, disconnect, - windowsize); + delta, + dropping_snacs, + windowsize + ); if (code == AIM_RATE_CODE_LIMIT) { purple_debug_warning("oscar", _("The last action you attempted could not be " "performed because you are over the rate limit. " - "Please wait 10 seconds and try again.")); + "Please wait 10 seconds and try again.\n")); } return 1; @@ -5264,9 +5305,9 @@ report_idle = strcmp(idle_reporting_pref, "none") != 0; if (report_idle) - aim_ssi_setpresence(od, tmp | 0x400); + aim_ssi_setpresence(od, tmp | AIM_SSI_PRESENCE_FLAG_SHOWIDLE); else - aim_ssi_setpresence(od, tmp & ~0x400); + aim_ssi_setpresence(od, tmp & ~AIM_SSI_PRESENCE_FLAG_SHOWIDLE); } @@ -5276,7 +5317,7 @@ for (curitem=od->ssi.local; curitem; curitem=curitem->next) { if ((curitem->name == NULL) || (g_utf8_validate(curitem->name, -1, NULL))) switch (curitem->type) { - case 0x0000: { /* Buddy */ + case AIM_SSI_TYPE_BUDDY: { /* Buddy */ if (curitem->name) { struct aim_ssi_item *groupitem; char *gname, *gname_utf8, *alias, *alias_utf8; @@ -5342,7 +5383,7 @@ } } break; - case 0x0001: { /* Group */ + case AIM_SSI_TYPE_GROUP: { /* Group */ char *gname; char *gname_utf8; @@ -5362,7 +5403,7 @@ g_free(gname_utf8); } break; - case 0x0002: { /* Permit buddy */ + case AIM_SSI_TYPE_PERMIT: { /* Permit buddy */ if (curitem->name) { /* if (!find_permdeny_by_name(gc->permit, curitem->name)) { AAA */ GSList *list; @@ -5375,7 +5416,7 @@ } } break; - case 0x0003: { /* Deny buddy */ + 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); @@ -5387,7 +5428,7 @@ } } break; - case 0x0004: { /* Permit/deny setting */ + case AIM_SSI_TYPE_PDINFO: { /* Permit/deny setting */ /* * We don't inherit the permit/deny setting from the server * for ICQ because, for ICQ, this setting controls who can @@ -5405,7 +5446,7 @@ } } break; - case 0x0005: { /* Presence setting */ + case AIM_SSI_TYPE_PRESENCEPREFS: { /* Presence setting */ /* We don't want to change Purple's setting because it applies to all accounts */ } break; } /* End of switch on curitem->type */
--- a/libpurple/protocols/oscar/oscar.h Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/oscar/oscar.h Wed Nov 04 18:41:51 2009 +0000 @@ -661,7 +661,7 @@ void flap_connection_send(FlapConnection *conn, FlapFrame *frame); 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); +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_keepalive(OscarData *od, FlapConnection *conn); @@ -1240,7 +1240,7 @@ #define AIM_SSI_ACK_INVALIDNAME 0x000d #define AIM_SSI_ACK_AUTHREQUIRED 0x000e -/* These flags are set in the 0x00c9 TLV of SSI teyp 0x0005 */ +/* 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 @@ -1685,7 +1685,8 @@ guint32 disconnect; guint32 current; guint32 max; - guint8 unknown[5]; /* only present in versions >= 3 */ + guint32 delta; + guint8 dropping_snacs; GHashTable *members; /* Key is family and subtype, value is TRUE. */ struct timeval last; /**< The time when we last sent a SNAC of this rate class. */
--- a/libpurple/protocols/silc/Makefile.mingw Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/silc/Makefile.mingw Wed Nov 04 18:41:51 2009 +0000 @@ -7,6 +7,8 @@ PIDGIN_TREE_TOP := ../../.. include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak +DEFINES := $(subst -DWIN32_LEAN_AND_MEAN,,$(DEFINES)) + TARGET = libsilc NEEDED_DLLS = $(SILC_TOOLKIT)/bin/libsilc-1-1-2.dll \ $(SILC_TOOLKIT)/bin/libsilcclient-1-1-2.dll @@ -79,7 +81,7 @@ $(OBJECTS): $(PURPLE_CONFIG_H) $(TARGET).dll: $(PURPLE_DLL).a $(OBJECTS) - $(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -Wl,--image-base,0x64000000 -o $(TARGET).dll + $(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -Wl,--image-base,0x74000000 -o $(TARGET).dll ## ## CLEAN RULES
--- a/libpurple/protocols/silc10/Makefile.mingw Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/silc10/Makefile.mingw Wed Nov 04 18:41:51 2009 +0000 @@ -7,6 +7,8 @@ PIDGIN_TREE_TOP := ../../.. include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak +DEFINES := $(subst -DWIN32_LEAN_AND_MEAN,,$(DEFINES)) + TARGET = libsilc NEEDED_DLLS = $(SILC_TOOLKIT)/lib/silc.dll \ $(SILC_TOOLKIT)/lib/silcclient.dll
--- a/libpurple/protocols/yahoo/libyahoo.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/yahoo/libyahoo.c Wed Nov 04 18:41:51 2009 +0000 @@ -249,7 +249,7 @@ yahoo_roomlist_get_list, yahoo_roomlist_cancel, yahoo_roomlist_expand_category, - NULL, /* can_receive_file */ + yahoo_can_receive_file, /* can_receive_file */ yahoo_send_file, yahoo_new_xfer, yahoo_offline_message, /* offline_message */
--- a/libpurple/protocols/yahoo/libymsg.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/yahoo/libymsg.c Wed Nov 04 18:41:51 2009 +0000 @@ -154,6 +154,7 @@ gboolean unicode = FALSE; char *message = NULL; YahooFederation fed = YAHOO_FEDERATION_NONE; + char *fedname = NULL; if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) { if (!purple_account_get_remember_password(account)) @@ -194,18 +195,20 @@ break; if (p->key == 241) { fed = strtol(p->value, NULL, 10); + g_free(fedname); switch (fed) { case YAHOO_FEDERATION_MSN: - name = g_strconcat("msn/", name, NULL); + name = fedname = g_strconcat("msn/", name, NULL); break; case YAHOO_FEDERATION_OCS: - name = g_strconcat("ocs/", name, NULL); + name = fedname = g_strconcat("ocs/", name, NULL); break; case YAHOO_FEDERATION_IBM: - name = g_strconcat("ibm/", name, NULL); + name = fedname = g_strconcat("ibm/", name, NULL); break; case YAHOO_FEDERATION_NONE: default: + fedname = NULL; break; } break; @@ -390,6 +393,7 @@ yahoo_update_status(gc, name, f); } + g_free(fedname); } static void yahoo_do_group_check(PurpleAccount *account, GHashTable *ht, const char *name, const char *group) @@ -879,6 +883,7 @@ char *id; char *msg; YahooFederation fed; + char *fed_from; }; static void yahoo_process_sms_message(PurpleConnection *gc, struct yahoo_packet *pkt) @@ -950,9 +955,6 @@ GSList *l = pkt->hash; GSList *list = NULL; struct _yahoo_im *im = NULL; - const char *imv = NULL; - gint val_11 = 0; - char *fed_from = NULL; account = purple_connection_get_account(gc); @@ -963,10 +965,11 @@ if (pair->key == 4 || pair->key == 1) { im = g_new0(struct _yahoo_im, 1); list = g_slist_append(list, im); - im->from = fed_from = pair->value; + im->from = pair->value; im->time = time(NULL); im->utf8 = TRUE; im->fed = YAHOO_FEDERATION_NONE; + im->fed_from = g_strdup(im->from); } if (im && pair->key == 5) im->active_id = pair->value; @@ -985,32 +988,75 @@ } if (im && pair->key == 241) { im->fed = strtol(pair->value, NULL, 10); + g_free(im->fed_from); switch (im->fed) { case YAHOO_FEDERATION_MSN: - fed_from = g_strconcat("msn/",im->from, NULL); + im->fed_from = g_strconcat("msn/",im->from, NULL); break; case YAHOO_FEDERATION_OCS: - fed_from = g_strconcat("ocs/",im->from, NULL); + im->fed_from = g_strconcat("ocs/",im->from, NULL); break; case YAHOO_FEDERATION_IBM: - fed_from = g_strconcat("ibm/",im->from, NULL); + im->fed_from = g_strconcat("ibm/",im->from, NULL); break; case YAHOO_FEDERATION_NONE: default: + im->fed_from = g_strdup(im->from); break; } - purple_debug_info("yahoo", "Message from federated (%d) buddy %s.\n", im->fed, fed_from); + purple_debug_info("yahoo", "Message from federated (%d) buddy %s.\n", im->fed, im->fed_from); } /* peer session id */ - if (pair->key == 11) { - if (im) - val_11 = strtol(pair->value, NULL, 10); + if (im && (pair->key == 11)) { + /* disconnect the peer if connected through p2p and sends wrong value for session id */ + if( (im->fed == YAHOO_FEDERATION_NONE) && (pkt_type == YAHOO_PKT_TYPE_P2P) + && (yd->session_id != strtol(pair->value, NULL, 10)) ) + { + purple_debug_warning("yahoo","p2p: %s sent us message with wrong session id. Disconnecting p2p connection to peer\n", im->fed_from); + /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */ + g_hash_table_remove(yd->peers, im->fed_from); + g_free(im->fed_from); + g_free(im); + return; /* Not sure whether we should process remaining IMs in this packet */ + } } /* IMV key */ - if (pair->key == 63) + if (im && pair->key == 63) { - imv = pair->value; + /* Check for the Doodle IMV, no IMvironment for federated buddies */ + if (im->from != NULL && im->fed == YAHOO_FEDERATION_NONE) + { + g_hash_table_replace(yd->imvironments, g_strdup(im->from), g_strdup(pair->value)); + + if (strstr(pair->value, "doodle;") != NULL) + { + PurpleWhiteboard *wb; + + if (!purple_privacy_check(account, im->from)) { + purple_debug_info("yahoo", "Doodle request from %s dropped.\n", + im->from); + g_free(im->fed_from); + g_free(im); + return; + } + /* I'm not sure the following ever happens -DAA */ + wb = purple_whiteboard_get_session(account, im->from); + + /* If a Doodle session doesn't exist between this user */ + if(wb == NULL) + { + doodle_session *ds; + wb = purple_whiteboard_create(account, im->from, + DOODLE_STATE_REQUESTED); + ds = wb->proto_data; + ds->imv_key = g_strdup(pair->value); + + yahoo_doodle_command_send_request(gc, im->from, pair->value); + yahoo_doodle_command_send_ready(gc, im->from, pair->value); + } + } + } } if (pair->key == 429) if (im) @@ -1022,63 +1068,19 @@ _("Your Yahoo! message did not get sent."), NULL); } - /* disconnect the peer if connected through p2p and sends wrong value for session id */ - if( (pkt_type == YAHOO_PKT_TYPE_P2P) && (val_11 != yd->session_id) ) { - purple_debug_warning("yahoo","p2p: %s sent us message with wrong session id. Disconnecting p2p connection to peer\n", im ? fed_from : "(im was null)"); - /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */ - if (im) { - g_hash_table_remove(yd->peers, fed_from); - g_free(im); - } - return; - } - - /* TODO: It seems that this check should be per IM, not global */ - /* Check for the Doodle IMV */ - /* no doodle with federated buddies -- assumption??? */ - if (im != NULL && imv!= NULL && im->from != NULL) - { - g_hash_table_replace(yd->imvironments, g_strdup(im->from), g_strdup(imv)); - - if (strstr(imv, "doodle;") != NULL) - { - PurpleWhiteboard *wb; - - if (!purple_privacy_check(account, im->from)) { - purple_debug_info("yahoo", "Doodle request from %s dropped.\n", im->from); - return; - } - - /* I'm not sure the following ever happens -DAA */ - - wb = purple_whiteboard_get_session(account, im->from); - - /* If a Doodle session doesn't exist between this user */ - if(wb == NULL) - { - doodle_session *ds; - wb = purple_whiteboard_create(account, im->from, DOODLE_STATE_REQUESTED); - ds = wb->proto_data; - ds->imv_key = g_strdup(imv); - - yahoo_doodle_command_send_request(gc, im->from, imv); - yahoo_doodle_command_send_ready(gc, im->from, imv); - } - } - } - for (l = list; l; l = l->next) { YahooFriend *f; char *m, *m2; im = l->data; - if (!fed_from || !im->msg) { + if (!im->fed_from || !im->msg) { + g_free(im->fed_from); g_free(im); continue; } - if (!purple_privacy_check(account, fed_from)) { - purple_debug_info("yahoo", "Message from %s dropped.\n", fed_from); + if (!purple_privacy_check(account, im->fed_from)) { + purple_debug_info("yahoo", "Message from %s dropped.\n", im->fed_from); return; } @@ -1116,10 +1118,11 @@ if (!strcmp(m, "<ding>")) { char *username; - username = g_markup_escape_text(fed_from, -1); + username = g_markup_escape_text(im->fed_from, -1); purple_prpl_got_attention(gc, username, YAHOO_BUZZ); g_free(username); g_free(m); + g_free(im->fed_from); g_free(im); continue; } @@ -1127,7 +1130,7 @@ m2 = yahoo_codes_to_html(m); g_free(m); - serv_got_im(gc, fed_from, m2, 0, im->time); + serv_got_im(gc, im->fed_from, m2, 0, im->time); g_free(m2); /* Official clients don't share buddy images with federated buddies */ @@ -1140,9 +1143,7 @@ } } - if(im->fed != YAHOO_FEDERATION_NONE) - g_free(fed_from); - + g_free(im->fed_from); g_free(im); } @@ -3998,7 +3999,7 @@ } - if (f && f->status != YAHOO_STATUS_OFFLINE) { + if (f && f->status != YAHOO_STATUS_OFFLINE && f->fed == YAHOO_FEDERATION_NONE) { if (!yd->wm) { act = purple_menu_action_new(_("Join in Chat"), PURPLE_CALLBACK(yahoo_chat_goto_menu), @@ -4038,10 +4039,12 @@ build_presence_submenu(f, gc)); m = g_list_append(m, act); - act = purple_menu_action_new(_("Start Doodling"), - PURPLE_CALLBACK(yahoo_doodle_blist_node), - NULL, NULL); - m = g_list_append(m, act); + if (f->fed == YAHOO_FEDERATION_NONE) { + act = purple_menu_action_new(_("Start Doodling"), + PURPLE_CALLBACK(yahoo_doodle_blist_node), + NULL, NULL); + m = g_list_append(m, act); + } act = purple_menu_action_new(_("Set User Info..."), PURPLE_CALLBACK(yahoo_userinfo_blist_node), @@ -4366,17 +4369,7 @@ } } - if (who[3] == '/') { - if (!g_ascii_strncasecmp(who, "msn/", 4)) { - fed = YAHOO_FEDERATION_MSN; - } - else if (!g_ascii_strncasecmp(who, "ocs/", 4)) { - fed = YAHOO_FEDERATION_OCS; - } - else if (!g_ascii_strncasecmp(who, "ibm/", 4)) { - fed = YAHOO_FEDERATION_IBM; - } - } + fed = yahoo_get_federation_from_name(who); if (who[0] == '+') { /* we have an sms to be sent */ @@ -4508,17 +4501,7 @@ YahooFederation fed = YAHOO_FEDERATION_NONE; struct yahoo_packet *pkt = NULL; - if (who[3] == '/') { - if (!g_ascii_strncasecmp(who, "msn/", 4)) { - fed = YAHOO_FEDERATION_MSN; - } - else if (!g_ascii_strncasecmp(who, "ocs/", 4)) { - fed = YAHOO_FEDERATION_OCS; - } - else if (!g_ascii_strncasecmp(who, "ibm/", 4)) { - fed = YAHOO_FEDERATION_IBM; - } - } + fed = yahoo_get_federation_from_name(who); /* Don't do anything if sms is being typed */ if( strncmp(who, "+", 1) == 0 ) @@ -4810,18 +4793,9 @@ return; f = yahoo_friend_find(gc, bname); - if (bname[3] == '/') { + fed = yahoo_get_federation_from_name(bname); + if (fed != YAHOO_FEDERATION_NONE) fed_bname += 4; - if (!g_ascii_strncasecmp(bname, "msn/", 4)) { - fed = YAHOO_FEDERATION_MSN; - } - else if (!g_ascii_strncasecmp(bname, "ocs/", 4)) { - fed = YAHOO_FEDERATION_OCS; - } - else if (!g_ascii_strncasecmp(bname, "ibm/", 4)) { - fed = YAHOO_FEDERATION_IBM; - } - } g = purple_buddy_get_group(buddy); if (g) @@ -4933,18 +4907,8 @@ if (!who || who[0] == '\0') return; - if (who[3] == '/') { - if (!g_ascii_strncasecmp(who, "msn/", 4)) { - fed = YAHOO_FEDERATION_MSN; - } - else if (!g_ascii_strncasecmp(who, "ocs/", 4)) { - fed = YAHOO_FEDERATION_OCS; - } - else if (!g_ascii_strncasecmp(who, "ibm/", 4)) { - fed = YAHOO_FEDERATION_IBM; - } - } - + fed = yahoo_get_federation_from_name(who); + pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id); if(fed) @@ -4965,17 +4929,8 @@ if (!who || who[0] == '\0') return; - if (who[3] == '/') { - if (!g_ascii_strncasecmp(who, "msn/", 4)) { - fed = YAHOO_FEDERATION_MSN; - } - else if (!g_ascii_strncasecmp(who, "ocs/", 4)) { - fed = YAHOO_FEDERATION_OCS; - } - else if (!g_ascii_strncasecmp(who, "ibm/", 4)) { - fed = YAHOO_FEDERATION_IBM; - } - } + fed = yahoo_get_federation_from_name(who); + pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id); if(fed)
--- a/libpurple/protocols/yahoo/libymsg.h Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/yahoo/libymsg.h Wed Nov 04 18:41:51 2009 +0000 @@ -346,6 +346,7 @@ char *yahoo_convert_to_numeric(const char *str); +YahooFederation yahoo_get_federation_from_name(const char *who); /* yahoo_profile.c */ void yahoo_get_info(PurpleConnection *gc, const char *name);
--- a/libpurple/protocols/yahoo/util.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/yahoo/util.c Wed Nov 04 18:41:51 2009 +0000 @@ -916,3 +916,18 @@ return g_string_free(dest, FALSE); } + +YahooFederation yahoo_get_federation_from_name(const char *who) +{ + YahooFederation fed = YAHOO_FEDERATION_NONE; + if (who[3] == '/') { + if (!g_ascii_strncasecmp(who, "msn", 3)) + fed = YAHOO_FEDERATION_MSN; + else if (!g_ascii_strncasecmp(who, "ocs", 3)) + fed = YAHOO_FEDERATION_OCS; + else if (!g_ascii_strncasecmp(who, "ibm", 3)) + fed = YAHOO_FEDERATION_IBM; + } + return fed; +} +
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo_filexfer.c Wed Nov 04 18:41:51 2009 +0000 @@ -1070,6 +1070,13 @@ yahoo_packet_send_and_free(pkt, yd); } +gboolean yahoo_can_receive_file(PurpleConnection *gc, const char *who) +{ + if (!who || yahoo_get_federation_from_name(who) != YAHOO_FEDERATION_NONE) + return FALSE; + return TRUE; +} + void yahoo_send_file(PurpleConnection *gc, const char *who, const char *file) { struct yahoo_xfer_data *xfer_data;
--- a/libpurple/protocols/yahoo/yahoo_filexfer.h Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo_filexfer.h Wed Nov 04 18:41:51 2009 +0000 @@ -43,6 +43,18 @@ PurpleXfer *yahoo_new_xfer(PurpleConnection *gc, const char *who); /** + * Returns TRUE if the buddy can receive file, FALSE otherwise. + * Federated users cannot receive files. So this will return FALSE only + * for them. + * + * @param gc The connection + * @param who The name of the remote user + * + * @return TRUE or FALSE + */ +gboolean yahoo_can_receive_file(PurpleConnection *gc, const char *who); + +/** * Send a file. * * @param gc The PurpleConnection handle.
--- a/libpurple/theme-loader.c Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/theme-loader.c Wed Nov 04 18:41:51 2009 +0000 @@ -100,6 +100,7 @@ PurpleThemeLoaderPrivate *priv = PURPLE_THEME_LOADER_GET_PRIVATE(loader); g_free(priv->type); + g_free(priv); parent_class->finalize(obj); }
--- a/libpurple/win32/global.mak Wed Nov 04 18:41:21 2009 +0000 +++ b/libpurple/win32/global.mak Wed Nov 04 18:41:51 2009 +0000 @@ -85,7 +85,7 @@ DEFINES += -DHAVE_CYRUS_SASL endif -DEFINES += -DHAVE_CONFIG_H +DEFINES += -DHAVE_CONFIG_H -DWIN32_LEAN_AND_MEAN # Use -g flag when building debug version of Pidgin (including plugins). # Use -fnative-struct instead of -mms-bitfields when using mingw 1.1
--- a/pidgin/Makefile.mingw Wed Nov 04 18:41:21 2009 +0000 +++ b/pidgin/Makefile.mingw Wed Nov 04 18:41:51 2009 +0000 @@ -7,6 +7,8 @@ PIDGIN_TREE_TOP := .. include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak +DEFINES := $(subst -DWIN32_LEAN_AND_MEAN,,$(DEFINES)) + NEEDED_DLLS = $(GTKSPELL_TOP)/gtkspell/libgtkspell.dll ## @@ -55,12 +57,12 @@ ## PIDGIN_C_SRC = \ gtkaccount.c \ - gtkblist.c \ + gtkblist-theme-loader.c \ gtkblist-theme.c \ - gtkblist-theme-loader.c \ - gtkcertmgr.c \ + gtkblist.c \ gtkcellrendererexpander.c \ gtkcellrendererprogress.c \ + gtkcertmgr.c \ gtkconn.c \ gtkconv.c \ gtkdebug.c \ @@ -70,8 +72,8 @@ gtkeventloop.c \ gtkexpander.c \ gtkft.c \ + gtkicon-theme-loader.c \ gtkicon-theme.c \ - gtkicon-theme-loader.c \ gtkidle.c \ gtkimhtml.c \ gtkimhtmltoolbar.c \
--- a/pidgin/gtkblist.c Wed Nov 04 18:41:21 2009 +0000 +++ b/pidgin/gtkblist.c Wed Nov 04 18:41:51 2009 +0000 @@ -4184,6 +4184,12 @@ } } + if (hidden_conv) { + char *tmp = nametext; + nametext = g_strdup_printf("<b>%s</b>", tmp); + g_free(tmp); + } + /* Put it all together */ if ((!aliased || biglist) && (statustext || idletime)) { /* using <span size='smaller'> breaks the status, so it must be seperated into <small><span>*/
--- a/pidgin/gtkimhtml.c Wed Nov 04 18:41:21 2009 +0000 +++ b/pidgin/gtkimhtml.c Wed Nov 04 18:41:51 2009 +0000 @@ -5053,7 +5053,7 @@ It will be destroyed when 'anchor' is destroyed. */ anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_plaintext", text, g_free); - g_object_set_data(G_OBJECT(anchor), "gtkimhtml_tiptext", text); + g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_tiptext", g_strdup(text), g_free); g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", g_strdup(smiley), g_free); /* This catches the expose events generated by animated @@ -5075,7 +5075,8 @@ gtk_container_add(GTK_CONTAINER(ebox), img); gtk_widget_show(img); g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_plaintext", text, g_free); - g_object_set_data(G_OBJECT(anchor), "gtkimhtml_tiptext", text); + g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_tiptext", + g_strdup(text), g_free); g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", g_strdup(smiley), g_free); gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), ebox, anchor); }
--- a/pidgin/gtkmain.c Wed Nov 04 18:41:21 2009 +0000 +++ b/pidgin/gtkmain.c Wed Nov 04 18:41:51 2009 +0000 @@ -744,7 +744,7 @@ } #if GLIB_CHECK_VERSION(2,2,0) - g_set_application_name(_("Pidgin")); + g_set_application_name(PIDGIN_NAME); #endif /* glib-2.0 >= 2.2.0 */ #ifdef _WIN32
--- a/pidgin/gtkprefs.c Wed Nov 04 18:41:21 2009 +0000 +++ b/pidgin/gtkprefs.c Wed Nov 04 18:41:51 2009 +0000 @@ -77,6 +77,7 @@ static GtkListStore *smiley_theme_store = NULL; static GtkTreeSelection *smiley_theme_sel = NULL; static GtkWidget *prefs_proxy_frame = NULL; +static GtkWidget *prefs_proxy_subframe = NULL; static GtkWidget *prefs = NULL; static GtkWidget *debugbutton = NULL; @@ -624,7 +625,8 @@ _("The default Pidgin status icon theme")); gtk_list_store_set(prefs_status_icon_themes, &iter, 0, pixbuf, 1, tmp, 2, "", -1); g_free(tmp); - g_object_unref(G_OBJECT(pixbuf)); + if (pixbuf) + g_object_unref(G_OBJECT(pixbuf)); purple_theme_manager_for_each_theme(prefs_themes_sort); pref_sound_generate_markup(); @@ -1886,23 +1888,27 @@ pidgin_prefs_checkbox(_("_Enable automatic router port forwarding"), "/purple/network/map_ports", vbox); - ports_checkbox = pidgin_prefs_checkbox(_("_Manually specify range of ports to listen on"), - "/purple/network/ports_range_use", vbox); - - spin_button = pidgin_prefs_labeled_spin_button(vbox, _("_Start port:"), + hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); + + ports_checkbox = pidgin_prefs_checkbox(_("_Manually specify range of ports to listen on:"), + "/purple/network/ports_range_use", hbox); + + spin_button = pidgin_prefs_labeled_spin_button(hbox, _("_Start:"), "/purple/network/ports_range_start", 0, 65535, sg); if (!purple_prefs_get_bool("/purple/network/ports_range_use")) gtk_widget_set_sensitive(GTK_WIDGET(spin_button), FALSE); g_signal_connect(G_OBJECT(ports_checkbox), "clicked", G_CALLBACK(pidgin_toggle_sensitive), spin_button); - spin_button = pidgin_prefs_labeled_spin_button(vbox, _("_End port:"), + spin_button = pidgin_prefs_labeled_spin_button(hbox, _("_End:"), "/purple/network/ports_range_end", 0, 65535, sg); if (!purple_prefs_get_bool("/purple/network/ports_range_use")) gtk_widget_set_sensitive(GTK_WIDGET(spin_button), FALSE); g_signal_connect(G_OBJECT(ports_checkbox), "clicked", G_CALLBACK(pidgin_toggle_sensitive), spin_button); + pidgin_add_widget_to_vbox(GTK_BOX(vbox), NULL, NULL, hbox, TRUE, NULL); + g_object_unref(sg); /* TURN server */ @@ -1921,9 +1927,9 @@ pidgin_prefs_labeled_spin_button(hbox, _("_Port:"), "/purple/network/turn_port", 0, 65535, NULL); - hbox = pidgin_prefs_labeled_entry(vbox, _("_Username:"), + hbox = pidgin_prefs_labeled_entry(vbox, _("Use_rname:"), "/purple/network/turn_username", sg); - pidgin_prefs_labeled_password(hbox, _("_Password:"), + pidgin_prefs_labeled_password(hbox, _("Pass_word:"), "/purple/network/turn_password", NULL); if (purple_running_gnome()) { @@ -1967,9 +1973,15 @@ gtk_widget_show(browser_button); } else { vbox = pidgin_make_frame(ret, _("Proxy Server")); - prefs_proxy_frame = gtk_vbox_new(FALSE, 0); - - pidgin_prefs_dropdown(vbox, _("Proxy _type:"), PURPLE_PREF_STRING, + prefs_proxy_frame = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); + prefs_proxy_subframe = gtk_vbox_new(FALSE, 0); + + /* This is a global option that affects SOCKS4 usage even with account-specific proxy settings */ + pidgin_prefs_checkbox(_("Use remote _DNS with SOCKS4 proxies"), + "/purple/proxy/socks4_remotedns", prefs_proxy_frame); + gtk_box_pack_start(GTK_BOX(vbox), prefs_proxy_frame, 0, 0, 0); + + pidgin_prefs_dropdown(prefs_proxy_frame, _("Proxy t_ype:"), PURPLE_PREF_STRING, "/purple/proxy/type", _("No proxy"), "none", "SOCKS 4", "socks4", @@ -1977,21 +1989,17 @@ "HTTP", "http", _("Use Environmental Settings"), "envvar", NULL); - gtk_box_pack_start(GTK_BOX(vbox), prefs_proxy_frame, 0, 0, 0); + gtk_box_pack_start(GTK_BOX(prefs_proxy_frame), prefs_proxy_subframe, 0, 0, 0); proxy_info = purple_global_proxy_get_info(); purple_prefs_connect_callback(prefs, "/purple/proxy/type", - proxy_changed_cb, prefs_proxy_frame); - - /* This is a global option that affects SOCKS4 usage even with account-specific proxy settings */ - pidgin_prefs_checkbox(_("Use remote DNS with SOCKS4 proxies"), - "/purple/proxy/socks4_remotedns", prefs_proxy_frame); + proxy_changed_cb, prefs_proxy_subframe); table = gtk_table_new(4, 2, FALSE); gtk_container_set_border_width(GTK_CONTAINER(table), 0); gtk_table_set_col_spacings(GTK_TABLE(table), 5); gtk_table_set_row_spacings(GTK_TABLE(table), 10); - gtk_container_add(GTK_CONTAINER(prefs_proxy_frame), table); + gtk_container_add(GTK_CONTAINER(prefs_proxy_subframe), table); label = gtk_label_new_with_mnemonic(_("_Host:")); @@ -2012,11 +2020,11 @@ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); pidgin_set_accessible_label (entry, label); - label = gtk_label_new_with_mnemonic(_("_Port:")); + label = gtk_label_new_with_mnemonic(_("P_ort:")); gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1, GTK_FILL, 0, 0, 0); - entry = gtk_entry_new(); + entry = gtk_spin_button_new_with_range(0, 65535, 1); gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry); gtk_table_attach(GTK_TABLE(table), entry, 3, 4, 0, 1, GTK_FILL, 0, 0, 0); g_signal_connect(G_OBJECT(entry), "changed", @@ -2031,7 +2039,7 @@ } pidgin_set_accessible_label (entry, label); - label = gtk_label_new_with_mnemonic(_("_User:")); + label = gtk_label_new_with_mnemonic(_("User_name:")); gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
--- a/pidgin/gtkrequest.c Wed Nov 04 18:41:21 2009 +0000 +++ b/pidgin/gtkrequest.c Wed Nov 04 18:41:51 2009 +0000 @@ -81,6 +81,33 @@ } PidginRequestData; static void +pidgin_widget_decorate_account(GtkWidget *cont, PurpleAccount *account) +{ + GtkWidget *image; + GdkPixbuf *pixbuf; + GtkTooltips *tips; + + if (!account) + return; + + pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL); + image = gtk_image_new_from_pixbuf(pixbuf); + g_object_unref(G_OBJECT(pixbuf)); + + tips = gtk_tooltips_new(); + gtk_tooltips_set_tip(tips, image, purple_account_get_username(account), NULL); + + if (GTK_IS_DIALOG(cont)) { + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(cont)->action_area), image, FALSE, TRUE, 0); + gtk_box_reorder_child(GTK_BOX(GTK_DIALOG(cont)->action_area), image, 0); + } else if (GTK_IS_HBOX(cont)) { + gtk_misc_set_alignment(GTK_MISC(image), 0, 0); + gtk_box_pack_end(GTK_BOX(cont), image, FALSE, TRUE, 0); + } + gtk_widget_show(image); +} + +static void generic_response_start(PidginRequestData *data) { g_return_if_fail(data != NULL); @@ -347,6 +374,8 @@ gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0); + pidgin_widget_decorate_account(hbox, account); + /* Descriptive label */ primary_esc = (primary != NULL) ? g_markup_escape_text(primary, -1) : NULL; secondary_esc = (secondary != NULL) ? g_markup_escape_text(secondary, -1) : NULL; @@ -515,6 +544,8 @@ gtk_misc_set_alignment(GTK_MISC(img), 0, 0); gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0); + pidgin_widget_decorate_account(hbox, account); + /* Vertical box */ vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER); gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); @@ -639,6 +670,8 @@ vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER); gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); + pidgin_widget_decorate_account(hbox, account); + /* Descriptive label */ primary_esc = (primary != NULL) ? g_markup_escape_text(primary, -1) : NULL; secondary_esc = (secondary != NULL) ? g_markup_escape_text(secondary, -1) : NULL; @@ -1144,6 +1177,8 @@ GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_window_set_default(GTK_WINDOW(win), button); + pidgin_widget_decorate_account(hbox, account); + /* Setup the vbox */ vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER); gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
--- a/pidgin/gtkstatusbox.c Wed Nov 04 18:41:21 2009 +0000 +++ b/pidgin/gtkstatusbox.c Wed Nov 04 18:41:51 2009 +0000 @@ -79,8 +79,8 @@ static void pidgin_status_box_pulse_typing(PidginStatusBox *status_box); static void pidgin_status_box_refresh(PidginStatusBox *status_box); -static void status_menu_refresh_iter(PidginStatusBox *status_box); -static void pidgin_status_box_regenerate(PidginStatusBox *status_box); +static void status_menu_refresh_iter(PidginStatusBox *status_box, gboolean status_changed); +static void pidgin_status_box_regenerate(PidginStatusBox *status_box, gboolean status_changed); static void pidgin_status_box_changed(PidginStatusBox *box); static void pidgin_status_box_size_request (GtkWidget *widget, GtkRequisition *requisition); static void pidgin_status_box_size_allocate (GtkWidget *widget, GtkAllocation *allocation); @@ -304,7 +304,7 @@ if (status_box->account == account) update_to_reflect_account_status(status_box, account, newstatus); else if (status_box->token_status_account == account) - status_menu_refresh_iter(status_box); + status_menu_refresh_iter(status_box, TRUE); } static gboolean @@ -312,6 +312,7 @@ { if (event->button == 3) { GtkWidget *menu_item; + const char *path; if (box->icon_box_menu) gtk_widget_destroy(box->icon_box_menu); @@ -325,7 +326,8 @@ menu_item = pidgin_new_item_from_stock(box->icon_box_menu, _("Remove"), GTK_STOCK_REMOVE, G_CALLBACK(remove_buddy_icon_cb), box, 0, 0, NULL); - if (purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon") == NULL) + if (!(path = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon")) + || !*path) gtk_widget_set_sensitive(menu_item, FALSE); gtk_menu_popup(GTK_MENU(box->icon_box_menu), NULL, NULL, NULL, NULL, @@ -559,7 +561,7 @@ else statusbox->token_status_account = check_active_accounts_for_identical_statuses(); - pidgin_status_box_regenerate(statusbox); + pidgin_status_box_regenerate(statusbox, TRUE); break; default: @@ -821,7 +823,7 @@ * keyboard signals instead of the changed signal? */ static void -status_menu_refresh_iter(PidginStatusBox *status_box) +status_menu_refresh_iter(PidginStatusBox *status_box, gboolean status_changed) { PurpleSavedStatus *saved_status; PurpleStatusPrimitive primitive; @@ -912,18 +914,15 @@ } else status_box->active_row = NULL; - message = purple_savedstatus_get_message(saved_status); - if (!purple_savedstatus_is_transient(saved_status) || !message || !*message) - { - status_box->imhtml_visible = FALSE; - gtk_widget_hide_all(status_box->vbox); - } - else - { - status_box->imhtml_visible = TRUE; - gtk_widget_show_all(status_box->vbox); + if (status_changed) { + message = purple_savedstatus_get_message(saved_status); /* + * If we are going to hide the imhtml, don't retain the + * message because showing the old message later is + * confusing. If we are going to set the message to a pre-set, + * then we need to do this anyway + * * Suppress the "changed" signal because the status * was changed programmatically. */ @@ -931,12 +930,24 @@ gtk_imhtml_clear(GTK_IMHTML(status_box->imhtml)); gtk_imhtml_clear_formatting(GTK_IMHTML(status_box->imhtml)); - gtk_imhtml_append_text(GTK_IMHTML(status_box->imhtml), message, 0); + + if (!purple_savedstatus_is_transient(saved_status) || !message || !*message) + { + status_box->imhtml_visible = FALSE; + gtk_widget_hide_all(status_box->vbox); + } + else + { + status_box->imhtml_visible = TRUE; + gtk_widget_show_all(status_box->vbox); + + gtk_imhtml_append_text(GTK_IMHTML(status_box->imhtml), message, 0); + } + gtk_widget_set_sensitive(GTK_WIDGET(status_box->imhtml), TRUE); + update_size(status_box); } - update_size(status_box); - /* Stop suppressing the "changed" signal. */ gtk_widget_set_sensitive(GTK_WIDGET(status_box), TRUE); } @@ -996,50 +1007,50 @@ * statuses and a token account if they do */ static PurpleAccount* check_active_accounts_for_identical_statuses(void) { - PurpleAccount *acct = NULL, *acct2; - GList *tmp, *tmp2, *active_accts = purple_accounts_get_all_active(); - GList *s, *s1, *s2; - - for (tmp = active_accts; tmp; tmp = tmp->next) { - acct = tmp->data; - s = purple_account_get_status_types(acct); - for (tmp2 = tmp->next; tmp2; tmp2 = tmp2->next) { - acct2 = tmp2->data; - - /* Only actually look at the statuses if the accounts use the same prpl */ - if (strcmp(purple_account_get_protocol_id(acct), purple_account_get_protocol_id(acct2))) { - acct = NULL; - break; - } - - s2 = purple_account_get_status_types(acct2); - - s1 = s; - while (s1 && s2) { - PurpleStatusType *st1 = s1->data, *st2 = s2->data; - /* TODO: Are these enough to consider the statuses identical? */ - if (purple_status_type_get_primitive(st1) != purple_status_type_get_primitive(st2) - || strcmp(purple_status_type_get_id(st1), purple_status_type_get_id(st2)) - || strcmp(purple_status_type_get_name(st1), purple_status_type_get_name(st2))) { - acct = NULL; - break; - } - - s1 = s1->next; - s2 = s2->next; - } - - if (s1 != s2) {/* Will both be NULL if matched */ - acct = NULL; + GList *iter, *active_accts = purple_accounts_get_all_active(); + PurpleAccount *acct1 = NULL; + const char *prpl1 = NULL; + + if (active_accts) { + acct1 = active_accts->data; + prpl1 = purple_account_get_protocol_id(acct1); + } else { + /* there's no enabled account */ + return NULL; + } + + /* start at the second account */ + for (iter = active_accts->next; iter; iter = iter->next) { + PurpleAccount *acct2 = iter->data; + GList *s1, *s2; + + if (!g_str_equal(prpl1, purple_account_get_protocol_id(acct2))) { + acct1 = NULL; + break; + } + + for (s1 = purple_account_get_status_types(acct1), + s2 = purple_account_get_status_types(acct2); s1 && s2; + s1 = s1->next, s2 = s2->next) { + PurpleStatusType *st1 = s1->data, *st2 = s2->data; + /* TODO: Are these enough to consider the statuses identical? */ + if (purple_status_type_get_primitive(st1) != purple_status_type_get_primitive(st2) + || strcmp(purple_status_type_get_id(st1), purple_status_type_get_id(st2)) + || strcmp(purple_status_type_get_name(st1), purple_status_type_get_name(st2))) { + acct1 = NULL; break; } } - if (!acct) + + if (s1 != s2) {/* Will both be NULL if matched */ + acct1 = NULL; break; + } } + g_list_free(active_accts); - return acct; + return acct1; } static void @@ -1068,7 +1079,7 @@ } static void -pidgin_status_box_regenerate(PidginStatusBox *status_box) +pidgin_status_box_regenerate(PidginStatusBox *status_box, gboolean status_changed) { GtkIconSize icon_size; @@ -1104,7 +1115,7 @@ pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_CUSTOM, NULL, _("New status..."), NULL, NULL); pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_SAVED, NULL, _("Saved statuses..."), NULL, NULL); - status_menu_refresh_iter(status_box); + status_menu_refresh_iter(status_box, status_changed); pidgin_status_box_refresh(status_box); } else { @@ -1156,7 +1167,7 @@ update_to_reflect_account_status(status_box, status_box->account, purple_account_get_active_status(status_box->account)); else { - status_menu_refresh_iter(status_box); + status_menu_refresh_iter(status_box, TRUE); pidgin_status_box_refresh(status_box); } return TRUE; @@ -1229,7 +1240,7 @@ /* Regenerate the list if it has changed */ if (initial_token_acct != status_box->token_status_account) { - pidgin_status_box_regenerate(status_box); + pidgin_status_box_regenerate(status_box, TRUE); } } @@ -1238,13 +1249,14 @@ current_savedstatus_changed_cb(PurpleSavedStatus *now, PurpleSavedStatus *old, PidginStatusBox *status_box) { /* Make sure our current status is added to the list of popular statuses */ - pidgin_status_box_regenerate(status_box); + pidgin_status_box_regenerate(status_box, TRUE); } static void saved_status_updated_cb(PurpleSavedStatus *status, PidginStatusBox *status_box) { - pidgin_status_box_regenerate(status_box); + pidgin_status_box_regenerate(status_box, + purple_savedstatus_get_current() == status); } static void @@ -1919,7 +1931,7 @@ status_box->token_status_account = check_active_accounts_for_identical_statuses(); cache_pixbufs(status_box); - pidgin_status_box_regenerate(status_box); + pidgin_status_box_regenerate(status_box, TRUE); purple_signal_connect(purple_savedstatuses_get_handle(), "savedstatus-changed", status_box, @@ -2324,18 +2336,6 @@ pidgin_status_box_refresh(status_box); } -static gboolean -message_changed(const char *one, const char *two) -{ - if (one == NULL && two == NULL) - return FALSE; - - if (one == NULL || two == NULL) - return TRUE; - - return (g_utf8_collate(one, two) != 0); -} - static void activate_currently_selected_status(PidginStatusBox *status_box) { @@ -2386,6 +2386,7 @@ if (status_box->account == NULL) { PurpleStatusType *acct_status_type = NULL; + const char *id = NULL; /* id of acct_status_type */ PurpleStatusPrimitive primitive = GPOINTER_TO_INT(data); /* Global */ /* Save the newly selected status to prefs.xml and status.xml */ @@ -2394,7 +2395,6 @@ if (status_box->token_status_account) { gint active; PurpleStatus *status; - const char *id = NULL; GtkTreePath *path = gtk_tree_row_reference_get_path(status_box->active_row); active = gtk_tree_path_get_indices(path)[0]; @@ -2402,37 +2402,35 @@ status = purple_account_get_active_status(status_box->token_status_account); - acct_status_type = find_status_type_by_index(status_box->token_status_account, active); + acct_status_type = find_status_type_by_index(status_box->token_status_account, active); id = purple_status_type_get_id(acct_status_type); - if (strncmp(id, purple_status_get_id(status), strlen(id)) == 0) + if (g_str_equal(id, purple_status_get_id(status)) && + purple_strequal(message, purple_status_get_attr_string(status, "message"))) { /* Selected status and previous status is the same */ - if (!message_changed(message, purple_status_get_attr_string(status, "message"))) - { - PurpleSavedStatus *ss = purple_savedstatus_get_current(); - /* Make sure that statusbox displays the correct thing. - * It can get messed up if the previous selection was a - * saved status that wasn't supported by this account */ - if ((purple_savedstatus_get_type(ss) == primitive) - && purple_savedstatus_is_transient(ss) - && purple_savedstatus_has_substatuses(ss)) - changed = FALSE; - } + PurpleSavedStatus *ss = purple_savedstatus_get_current(); + /* Make sure that statusbox displays the correct thing. + * It can get messed up if the previous selection was a + * saved status that wasn't supported by this account */ + if ((purple_savedstatus_get_type(ss) == primitive) + && purple_savedstatus_is_transient(ss) + && purple_savedstatus_has_substatuses(ss)) + changed = FALSE; } } else { saved_status = purple_savedstatus_get_current(); if (purple_savedstatus_get_type(saved_status) == primitive && - !purple_savedstatus_has_substatuses(saved_status)) + !purple_savedstatus_has_substatuses(saved_status) && + purple_strequal(purple_savedstatus_get_message(saved_status), message)) { - if (!message_changed(purple_savedstatus_get_message(saved_status), message)) - changed = FALSE; + changed = FALSE; } } if (changed) { - /* Manually find the appropriate transient acct */ + /* Manually find the appropriate transient status */ if (status_box->token_status_account) { GList *iter = purple_savedstatuses_get_all(); GList *tmp, *active_accts = purple_accounts_get_all_active(); @@ -2440,27 +2438,31 @@ for (; iter != NULL; iter = iter->next) { PurpleSavedStatus *ss = iter->data; const char *ss_msg = purple_savedstatus_get_message(ss); + /* find a known transient status that is the same as the + * new selected one */ if ((purple_savedstatus_get_type(ss) == primitive) && purple_savedstatus_is_transient(ss) && purple_savedstatus_has_substatuses(ss) && /* Must have substatuses */ - !message_changed(ss_msg, message)) + purple_strequal(ss_msg, message)) { gboolean found = FALSE; - /* The currently enabled accounts must have substatuses for all the active accts */ + /* this status must have substatuses for all the active accts */ for(tmp = active_accts; tmp != NULL; tmp = tmp->next) { PurpleAccount *acct = tmp->data; PurpleSavedStatusSub *sub = purple_savedstatus_get_substatus(ss, acct); if (sub) { const PurpleStatusType *sub_type = purple_savedstatus_substatus_get_type(sub); const char *subtype_status_id = purple_status_type_get_id(sub_type); - if (subtype_status_id && !strcmp(subtype_status_id, - purple_status_type_get_id(acct_status_type))) + if (purple_strequal(subtype_status_id, id)) { found = TRUE; + break; + } } } - if (!found) - continue; - saved_status = ss; - break; + + if (found) { + saved_status = ss; + break; + } } } @@ -2503,11 +2505,11 @@ status_type = find_status_type_by_index(status_box->account, active); id = purple_status_type_get_id(status_type); - if (strncmp(id, purple_status_get_id(status), strlen(id)) == 0) + if (g_str_equal(id, purple_status_get_id(status)) && + purple_strequal(message, purple_status_get_attr_string(status, "message"))) { /* Selected status and previous status is the same */ - if (!message_changed(message, purple_status_get_attr_string(status, "message"))) - changed = FALSE; + changed = FALSE; } if (changed) @@ -2597,7 +2599,7 @@ if (status_box->typing == 0) { /* Nothing has changed, so we don't need to do anything */ - status_menu_refresh_iter(status_box); + status_menu_refresh_iter(status_box, FALSE); return; } @@ -2655,14 +2657,14 @@ pidgin_status_editor_show(FALSE, purple_savedstatus_is_transient(saved_status) ? saved_status : NULL); - status_menu_refresh_iter(status_box); + status_menu_refresh_iter(status_box, FALSE); return; } if (type == PIDGIN_STATUS_BOX_TYPE_SAVED) { pidgin_status_window_show(); - status_menu_refresh_iter(status_box); + status_menu_refresh_iter(status_box, FALSE); return; } }
--- a/pidgin/plugins/perl/common/Makefile.mingw Wed Nov 04 18:41:21 2009 +0000 +++ b/pidgin/plugins/perl/common/Makefile.mingw Wed Nov 04 18:41:51 2009 +0000 @@ -5,9 +5,12 @@ # PIDGIN_TREE_TOP := ../../../.. -GCCWARNINGS := -Wno-comment -Waggregate-return -Wcast-align -Wdeclaration-after-statement -Werror-implicit-function-declaration -Wextra -Wno-sign-compare -Wno-unused-parameter -Winit-self -Wmissing-declarations -Wmissing-prototypes -Wpointer-arith -Wundef -Wno-unused include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak +GCCWARNINGS += -Wno-comment -Wno-unused -Wno-nested-externs + +DEFINES := $(subst -DWIN32_LEAN_AND_MEAN,,$(DEFINES)) + TARGET = Pidgin EXTUTILS ?= C:/perl/lib/ExtUtils
--- a/pidgin/plugins/win32/winprefs/Makefile.mingw Wed Nov 04 18:41:21 2009 +0000 +++ b/pidgin/plugins/win32/winprefs/Makefile.mingw Wed Nov 04 18:41:51 2009 +0000 @@ -8,6 +8,7 @@ include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak TARGET = winprefs +DEFINES := $(subst -DWIN32_LEAN_AND_MEAN,,$(DEFINES)) DEFINES += -DWINVER=0x500 ##
--- a/po/ca.po Wed Nov 04 18:41:21 2009 +0000 +++ b/po/ca.po Wed Nov 04 18:41:51 2009 +0000 @@ -33,8 +33,8 @@ msgstr "" "Project-Id-Version: Pidgin\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-09-07 18:26-0700\n" -"PO-Revision-Date: 2009-07-26 17:23+0200\n" +"POT-Creation-Date: 2009-10-25 17:57+0100\n" +"PO-Revision-Date: 2009-10-26 09:20+0100\n" "Last-Translator: Josep Puigdemont i Casamajó <josep.puigdemont@gmail.com>\n" "Language-Team: Catalan <tradgnome@softcatala.net>\n" "MIME-Version: 1.0\n" @@ -576,13 +576,6 @@ msgid "Re-enable Account" msgstr "Rehabilita el compte" -msgid "" -"The account has disconnected and you are no longer in this chat. You will be " -"automatically rejoined in the chat when the account reconnects." -msgstr "" -"El compte s'ha desconnectat i ja no sou al xat. Quan es torni a connectar el " -"compte entrareu de nou automàticament al xat." - msgid "No such command." msgstr "No existeix l'ordre." @@ -625,6 +618,13 @@ msgid "You have left this chat." msgstr "Heu sortit d'aquest xat" +msgid "" +"The account has disconnected and you are no longer in this chat. You will be " +"automatically rejoined in the chat when the account reconnects." +msgstr "" +"El compte s'ha desconnectat i ja no sou al xat. Quan es torni a connectar el " +"compte entrareu de nou automàticament al xat." + msgid "Logging started. Future messages in this conversation will be logged." msgstr "" "S'ha iniciat el registre. Es registraran els propers missatges d'aquesta " @@ -661,6 +661,9 @@ msgid "Enable Sounds" msgstr "Habilita els sons" +msgid "You are not connected." +msgstr "No esteu connectat." + msgid "<AUTO-REPLY> " msgstr "<RESPOSTA-AUTOMÀTICA> " @@ -670,8 +673,8 @@ msgstr[0] "Llista d'%d usuari:\n" msgstr[1] "Llista de %d usuaris:\n" -msgid "Supported debug options are: version" -msgstr "Les opcions de depuració disponibles són: version" +msgid "Supported debug options are: plugins version" +msgstr "Les opcions de depuració disponibles són: plugins version" msgid "No such command (in this context)." msgstr "L'ordre no existeix (en aquest context)." @@ -977,6 +980,9 @@ msgid "(none)" msgstr "(cap)" +#. XXX: The following expects that finch_notify_message gets called. This +#. * may not always happen, e.g. when another plugin sets its own +#. * notify_message. So tread carefully. msgid "URI" msgstr "URI" @@ -1554,9 +1560,15 @@ "\n" "S'està aconseguint un TinyURL..." -#, fuzzy +#, c-format +msgid "TinyURL for above: %s" +msgstr "Fes un TinyURL d'això d'aquí dalt: %s" + +msgid "Please wait while TinyURL fetches a shorter URL ..." +msgstr "Espreu mentre TinyURL obté una URL més curta..." + msgid "Only create TinyURL for URLs of this length or greater" -msgstr "Crea TinyURL per a URL així de llargues o més" +msgstr "Només crea TinyURL per a URL així de llargues o més" msgid "TinyURL (or other) address prefix" msgstr "Prefix de l'adreça TinyURL (o altra)" @@ -1567,10 +1579,9 @@ msgid "TinyURL plugin" msgstr "Connector TinyURL" -#, fuzzy msgid "When receiving a message with URL(s), use TinyURL for easier copying" msgstr "" -"Quan rebeu missagtes amb URL, feu servir TinyURL per a copiar més fàcilment" +"En rebre missagtes amb URL, s'empra TinyURL perquè sigui més fàcil copiar" msgid "Online" msgstr "En línia" @@ -1676,27 +1687,25 @@ msgid "buddy list" msgstr "llista d'amics" -#, fuzzy msgid "The certificate is self-signed and cannot be automatically checked." -msgstr "" -"No es pot comprovar el certificat que presenta «%s» atès que està auto-signat." - -#, fuzzy -msgid "The root certificate this one claims to be issued by is unknown." -msgstr "El Pidgin no coneix el certificat arrel d'aquest certificat." - -#, fuzzy +msgstr "No es pot comprovar el certificat atès que està auto-signat." + +msgid "" +"The certificate is not trusted because no certificate that can verify it is " +"currently trusted." +msgstr "" +"No es pot confiar en el certificat atès que no hi hi ha cap altre certificat " +"de confiança que el pugui verificar." + msgid "The certificate is not valid yet." -msgstr "La cadena de certificació que presenta %s no és vàlida." - -#, fuzzy +msgstr "El certificat encara no és vàlid." + msgid "The certificate has expired and should not be considered valid." -msgstr "La cadena de certificació que presenta %s no és vàlida." +msgstr "El certificat ha expirat i no s'hauria de considerar vàlid." #. Translators: "domain" refers to a DNS domain (e.g. talk.google.com) -#, fuzzy msgid "The certificate presented is not issued to this domain." -msgstr "La cadena de certificació que presenta %s no és vàlida." +msgstr "El certificat que s'ha presentat no ha estat emès per a aquest domini." msgid "" "You have no database of root certificates, so this certificate cannot be " @@ -1705,17 +1714,14 @@ "Aquest certificat no es pot validar perquè no teniu cap base de dades de " "certificats arrel." -#, fuzzy msgid "The certificate chain presented is invalid." -msgstr "La cadena de certificació que presenta %s no és vàlida." - -#, fuzzy +msgstr "La cadena de certificació que s'ha presentat no és vàlida." + msgid "The certificate has been revoked." -msgstr "Ha finalitzat la trucada." - -#, fuzzy +msgstr "El certificat ha estat revocat." + msgid "An unknown certificate error occurred." -msgstr "Hi ha hagut un error de connexió desconegut: %s." +msgstr "S'ha produït un error desconegut en el certificat." msgid "(DOES NOT MATCH)" msgstr "(NO COINCIDEIX)" @@ -1760,26 +1766,25 @@ msgid "_View Certificate..." msgstr "_Mostra el certificat..." -#, fuzzy, c-format +#, c-format msgid "The certificate for %s could not be validated." -msgstr "La cadena de certificació que presenta %s no és vàlida." +msgstr "No s'ha pogut validar el certificat de %s." # Títol de finestra (josep) #. TODO: Probably wrong. msgid "SSL Certificate Error" msgstr "Error en el certificat SSL" -#, fuzzy msgid "Unable to validate certificate" -msgstr "No s'ha pogut autenticar: %s" - -#, fuzzy, c-format +msgstr "No s'ha pogut certificar" + +#, c-format msgid "" "The certificate claims to be from \"%s\" instead. This could mean that you " "are not connecting to the service you believe you are." msgstr "" -"El certificat de «%s» sembla indicar que és de «%s». Això podria voler dir que " -"us esteu connectant a un servei diferent del que us penseu." +"El certificat indica que és de «%s». Això podria voler dir que us esteu " +"connectant a un servei diferent del que us penseu." #. Make messages #, c-format @@ -1927,6 +1932,10 @@ msgstr "El procés resoledor ha acabat sense respondre la nostra sol·licitud" #, c-format +msgid "Error converting %s to punycode: %d" +msgstr "S'ha produït un error en convertir %s a punycode: %d" + +#, c-format msgid "Thread creation failure: %s" msgstr "S'ha produït un error en crear un fil: %s" @@ -2020,18 +2029,18 @@ msgid "File transfer complete" msgstr "S'ha completat la transferència del fitxer" -#, fuzzy, c-format +#, c-format msgid "You cancelled the transfer of %s" msgstr "Heu cancel·lat la transferència de %s" msgid "File transfer cancelled" msgstr "S'ha cancel·lat la transferència del fitxer" -#, fuzzy, c-format +#, c-format msgid "%s cancelled the transfer of %s" msgstr "%s ha cancel·lat la transferència de %s" -#, fuzzy, c-format +#, c-format msgid "%s cancelled the file transfer" msgstr "%s ha cancel·lat la transferència del fitxer" @@ -2224,28 +2233,30 @@ "No codecs found. Install some GStreamer codecs found in GStreamer plugins " "packages." msgstr "" +"No s'ha trobat cap còdec. Instal·leu els còdecs del GStreamer que podeu " +"trobar en els paquests de connectors del GStreamer." msgid "" "No codecs left. Your codec preferences in fs-codecs.conf are too strict." msgstr "" - -#, fuzzy +"No hi ha cap més còdec. Les preferències dels còdecs al fitxer fs-codecs." +"conf són massa estrictes." + msgid "A non-recoverable Farsight2 error has occurred." -msgstr "Hi ha hagut un error de connexió desconegut: %s." - -#, fuzzy -msgid "Conference error." -msgstr "Conferència tancada" - -msgid "Error with your microphone." -msgstr "" - -msgid "Error with your webcam." -msgstr "" - -#, fuzzy, c-format +msgstr "S'ha produït un error no recuperable del Farsight2." + +msgid "Conference error" +msgstr "Error en la conferència" + +msgid "Error with your microphone" +msgstr "S'ha produït un error amb el micròfon" + +msgid "Error with your webcam" +msgstr "S'ha produït un error amb la càmera web" + +#, c-format msgid "Error creating session: %s" -msgstr "S'ha produït un error en crear la connexió" +msgstr "S'ha produït un error en crear la sessió: %s" msgid "Error creating conference." msgstr "S'ha produït un error en crear la conferència." @@ -2511,16 +2522,15 @@ msgid "Test plugin IPC support, as a server. This registers the IPC commands." msgstr "Connector de proves per a servidor d'IPC, que registra les ordres IPC." -#, fuzzy msgid "Hide Joins/Parts" -msgstr "Oculta els errors en entrar" +msgstr "Oculta en entrar/sortir" #. Translators: Followed by an input request a number of people msgid "For rooms with more than this many people" -msgstr "" +msgstr "Per sales amb més persones que" msgid "If user has not spoken in this many minutes" -msgstr "" +msgstr "Si l'usuari no ha parlat en" msgid "Apply hiding rules to buddies" msgstr "Aplica les normes d'ocultació als amics" @@ -3973,11 +3983,11 @@ msgid "Logo" msgstr "Logotip" -#, fuzzy, c-format +#, c-format msgid "" "%s will no longer be able to see your status updates. Do you want to " "continue?" -msgstr "Esteu segur que voleu suprimir %s de la llista d'amics?" +msgstr "%s no podrà veure l'actualització del vostre estat. Voleu continuar?" msgid "Cancel Presence Notification" msgstr "Cancel·la la notificació de presència" @@ -3996,6 +4006,9 @@ msgid "Unsubscribe" msgstr "Cancel·la la subscripció" +msgid "Initiate _Chat" +msgstr "Inicia un _xat" + msgid "Log In" msgstr "Connecta" @@ -4580,7 +4593,7 @@ msgid "configure: Configure a chat room." msgstr "configure: configura la sala de xat." -msgid "part [room]: Leave the room." +msgid "part [message]: Leave the room." msgstr "part [sala]: surt de la sala." msgid "register: Register with a chat room." @@ -4599,13 +4612,12 @@ "affiliate <owner|admin|member|outcast|none> [sobrenom1] " "[sobrenom2] ...: obtén els usuaris amb una afiliació, o els l'estableix." -#, fuzzy msgid "" "role <moderator|participant|visitor|none> [nick1] [nick2] ...: Get the " "users with a role or set users' role with the room." msgstr "" -"role <usuari> <moderator|participant|visitor|none> [sobrenom1] " -"[sobrenom2] ...: obtén els usuaris amb el rol especificat, o els l'estableix." +"role <moderator|participant|visitor|none> [sobrenom1] [sobrenom2] ...: " +"obtén els usuaris amb el rol especificat, o els l'estableix." msgid "invite <user> [message]: Invite a user to the room." msgstr "invite <usuari> [sala]: convida un usuari a la sala." @@ -5025,7 +5037,6 @@ msgid "Not expected" msgstr "Inesperat" -#, fuzzy msgid "Friendly name is changing too rapidly" msgstr "El nom amistós canvia massa de pressa" @@ -5245,19 +5256,16 @@ msgid "Send to Mobile" msgstr "Envia a un mòbil" -msgid "Initiate _Chat" -msgstr "Inicia un _xat" - msgid "SSL support is needed for MSN. Please install a supported SSL library." msgstr "L'MSN necessita SSL, instal·leu alguna biblioteca d'SSL permesa." #, c-format msgid "" "Unable to add the buddy %s because the username is invalid. Usernames must " -"be a valid email address." +"be valid email addresses." msgstr "" "No s'ha pogut afegir l'amic %s perquè el nom d'usuari no és vàlid. Els noms " -"d'usuari han de ser adreces de correu vàlides." +"d'usuari han de ser adreces de correu electròniques vàlides." msgid "Unable to Add" msgstr "No s'ha pogut afegir" @@ -5597,10 +5605,10 @@ "%s ha sol·licitat poder veure la vostra càmera web, però això encara no està " "implementat." -#, fuzzy, c-format +#, c-format msgid "%s invited you to view his/her webcam, but this is not yet supported." msgstr "" -"%s ha sol·licitat poder veure la vostra càmera web, però això encara no està " +"%s us ha convidat a veure la seva càmera web, però això encara no està " "implementat." msgid "Away From Computer" @@ -6354,9 +6362,9 @@ msgstr "Port en el servidor" #. Note to translators: %s in this string is a URL -#, fuzzy, c-format +#, c-format msgid "Received unexpected response from %s" -msgstr "S'ha rebut una resposta inesperada de " +msgstr "S'ha rebut una resposta inesperada de %s" #. username connecting too frequently msgid "" @@ -6369,9 +6377,9 @@ #. Note to translators: The first %s is a URL, the second is an #. error message. -#, fuzzy, c-format +#, c-format msgid "Error requesting %s: %s" -msgstr "S'ha produït en sol·licitar " +msgstr "S'ha produït un error en sol·licitar %s: %s" msgid "AOL does not allow your screen name to authenticate here" msgstr "AOL no permet que us autentiqueu amb aquest nom d'usuari aquí" @@ -7149,9 +7157,8 @@ msgid "C_onnect" msgstr "C_onnecta" -#, fuzzy msgid "You closed the connection." -msgstr "El servidor ha tancat la connexió" +msgstr "Heu tancat la connexió." msgid "Get AIM Info" msgstr "Obtén informació de AIM" @@ -7163,9 +7170,8 @@ msgid "Get Status Msg" msgstr "Aconsegueix el missatge d'estat" -#, fuzzy msgid "End Direct IM Session" -msgstr "S'ha establert una connexió directa de MI" +msgstr "Finalitzar la sessió de MI directa" msgid "Direct IM" msgstr "MI directa" @@ -8007,7 +8013,7 @@ msgid "File Send" msgstr "S'ha enviat el fitxer" -#, fuzzy, c-format +#, c-format msgid "%d cancelled the transfer of %s" msgstr "%d ha cancel·lat la transferència de %s" @@ -9545,7 +9551,7 @@ msgstr "Bloca invitacions a conferències i sales de xat" msgid "Use account proxy for SSL connections" -msgstr "" +msgstr "Empra un compte per al servidor intermediàri per a connexions SSL" msgid "Chat room list URL" msgstr "URL de la llista de sales de xat" @@ -9653,26 +9659,26 @@ msgid "Ignore buddy?" msgstr "Voleu ignorar l'amic?" -#, fuzzy msgid "Invalid username or password" -msgstr "El sobrenom o la contrasenya no són correctes" - -#, fuzzy +msgstr "El sobrenom o la contrasenya no són vàlides" + msgid "" "Your account has been locked due to too many failed login attempts. Please " "try logging into the Yahoo! website." msgstr "" -"El compte està blocat perquè s'ha intentat entrar massa cops. Això es pot " -"solucionar entrant al web de Yahoo!" +"S'ha blocat el vostre compte perquè s'ha intentat entrar massa cops. Entreu " +"al web de Yahoo! per solucionar això." #, c-format msgid "Unknown error 52. Reconnecting should fix this." -msgstr "" +msgstr "Error desconegut 52. Es pot sol·lucionar connectant de nou." msgid "" "Error 1013: The username you have entered is invalid. The most common cause " "of this error is entering your email address instead of your Yahoo! ID." msgstr "" +"Error 1013: el nom d'usuari no és vàlid. Pot ser que hagueu introduït la " +"vostra adreça de correu en lloc del nom d'usuari de Yahoo!" #, c-format msgid "Unknown error number %d. Logging into the Yahoo! website may fix this." @@ -9764,6 +9770,16 @@ msgid "Open Inbox" msgstr "Obre la safata d'entrada" +msgid "Can't send SMS. Unable to obtain mobile carrier." +msgstr "" +"No es poden enviar SMS, no s'ha pogut obtenir l'operador de telefonia mòbil." + +msgid "Can't send SMS. Unknown mobile carrier." +msgstr "No es poden enviar SMS, no es coneix l'operador de telefona mòbil." + +msgid "Getting mobile carrier to send the SMS." +msgstr "S'està obtenint l'operador de telefonia mòbil per a poder enviar SMS." + #. Write a local message to this conversation showing that a request for a #. * Doodle session has been made #. @@ -10456,7 +10472,6 @@ msgid "Layout" msgstr "Format" -#, fuzzy msgid "The layout of icons, name, and status of the buddy list" msgstr "El format de les icones, el nom, i l'estat de la llista d'amics" @@ -10513,9 +10528,8 @@ #. Note to translators: These two strings refer to the font and color #. of a buddy list buddy when it is online -#, fuzzy msgid "Online Text" -msgstr "Text en línia" +msgstr "Text en estar en línia" msgid "The text information for when a buddy is online" msgstr "Text informatiu per quan un amic estigui en línia" @@ -10523,18 +10537,16 @@ #. Note to translators: These two strings refer to the font and color #. of a buddy list buddy when it is away msgid "Away Text" -msgstr "Text d'absència" +msgstr "Text en estar absent" msgid "The text information for when a buddy is away" msgstr "Text informatiu per quan un amic estigui absent" #. Note to translators: These two strings refer to the font and color #. of a buddy list buddy when it is offline -#, fuzzy msgid "Offline Text" -msgstr "Text de fora de línia" - -#, fuzzy +msgstr "Text fora de línia" + msgid "The text information for when a buddy is offline" msgstr "Text informatiu per quan un amic estigui fora de línia" @@ -10559,7 +10571,6 @@ msgid "Message (Nick Said) Text" msgstr "Text del missatge (on s'hi ha dit el sobrenom)" -#, fuzzy msgid "" "The text information for when a chat has an unread message that mentions " "your nickname" @@ -11005,9 +11016,8 @@ msgid "_Group:" msgstr "_Grup:" -#, fuzzy msgid "Auto_join when account connects." -msgstr "_Entra automàticament quant el compte estigui connectat." +msgstr "_Entra automàticament quant es connecti el compte." msgid "_Remain in chat after window is closed." msgstr "Co_ntinua al xat quan la finestra es tanqui." @@ -11121,9 +11131,8 @@ msgid "/Conversation/New Instant _Message..." msgstr "/Conversa/_Missatge instantani nou..." -#, fuzzy msgid "/Conversation/Join a _Chat..." -msgstr "/Conversa/Con_vida..." +msgstr "/Conversa/Entra a un _xat..." msgid "/Conversation/_Find..." msgstr "/Conversa/_Cerca..." @@ -11514,7 +11523,7 @@ msgstr "Estonià" msgid "Basque" -msgstr "" +msgstr "Basc" msgid "Persian" msgstr "Persa" @@ -11728,6 +11737,13 @@ "primary language is <b>English</b>. You are welcome to post in another " "language, but the responses may be less helpful.<br/><br/>" msgstr "" +"<font size=\"4\">Ajuda d'altres usuaris del Pidgin:</font> <a href=\"mailto:" +"support@pidgin.im\">support@pidgin.im</a><br/>Aquesta és una llista de " +"correu <b>pública</b>. (<a href=\"http://pidgin.im/pipermail/support/" +"\">arxiu</a>)<br/>No us podem ajudar amb connectors d'altres proveïdors.<br/" +">En aquesta llista s'hi empra principalment l'<b>anglès</b>. Podeu escriure-" +"hi en un altre idioma, però és possible que les respostes no siguin de gaire " +"ajuda.<br/><br/>" #, c-format msgid "" @@ -12299,45 +12315,48 @@ "Usage: %s [OPTION]...\n" "\n" msgstr "" - -#, fuzzy +"Forma d'ús: %s [OPCIÓ]...\n" +"\n" + msgid "DIR" -msgstr "IRC" +msgstr "DIR" msgid "use DIR for config files" -msgstr "" +msgstr "empra DIR per a fitxers de configuració" msgid "print debugging messages to stdout" -msgstr "" +msgstr "escriu missatges de depuració a la sortida estàndard" msgid "force online, regardless of network status" -msgstr "" +msgstr "força estar en línia, independentment de l'estat de la xarxa" msgid "display this help and exit" -msgstr "" +msgstr "mostra aquesta ajuda i surt" # FIXME: entrades/registres? -#, fuzzy msgid "allow multiple instances" -msgstr "Permet diverses entrades simultànies" +msgstr "permet diverses instàncies" msgid "don't automatically login" -msgstr "" +msgstr "no entra als comptes" msgid "NAME" -msgstr "" +msgstr "NOM" msgid "" "enable specified account(s) (optional argument NAME\n" " specifies account(s) to use, separated by commas.\n" " Without this only the first account will be enabled)." msgstr "" +"habilita els comptes especificats (l'argument opcional NAME especifica\n" +" els comptes a emprar, separats per comes. Sense això\n" +" només s'habilitarà el primer compte)." msgid "X display to use" -msgstr "" +msgstr "pantalla d'X a emprar" msgid "display the current version and exit" -msgstr "" +msgstr "mostra la versió actual i surt" # FIXME: backtrace -> traça (bug-buddy) ? #, c-format @@ -12394,7 +12413,7 @@ msgstr "%s vol iniciar una sessió de vídeo." msgid "Incoming Call" -msgstr "" +msgstr "Trucada entrant" msgid "_Pause" msgstr "_Pausa" @@ -12576,50 +12595,54 @@ msgid "Pounce Target" msgstr "Objectiu de l'avís" -#, c-format msgid "Started typing" msgstr "Hagi començat a escriure" -#, c-format msgid "Paused while typing" msgstr "S'aturi mentre tecleja" -#, c-format msgid "Signed on" msgstr "Es connecti" -#, c-format msgid "Returned from being idle" msgstr "Torna a estar actiu" -#, c-format msgid "Returned from being away" msgstr "Torni a estar present" -#, c-format msgid "Stopped typing" msgstr "Pari d'escriure" -#, c-format msgid "Signed off" msgstr "Es desconnecti" -#, c-format msgid "Became idle" msgstr "Passi a inactiu" -#, c-format msgid "Went away" msgstr "En estar absent" -#, c-format msgid "Sent a message" msgstr "Envia un missatge" -#, c-format msgid "Unknown.... Please report this!" msgstr "Esdeveniment d'avís desconegut, informeu-nos-en." +msgid "(Custom)" +msgstr "(Personalitzat)" + +msgid "(Default)" +msgstr "(Predeterminat)" + +msgid "The default Pidgin sound theme" +msgstr "El tema de sons predeterminat del pidgin" + +msgid "The default Pidgin buddy list theme" +msgstr "El tema per a la llista d'amics predeterminat del Pidgin" + +msgid "The default Pidgin status icon theme" +msgstr "El tema de les icones d'estat predeterminat del Pidgin" + msgid "Theme failed to unpack." msgstr "No s'ha pogut desempaquetar el tema." @@ -12764,14 +12787,16 @@ msgid "Cannot start browser configuration program." msgstr "No s'ha pogut iniciar el programa de configuració del navegador." -#, fuzzy msgid "Disabled" -msgstr "_Inhabilita" +msgstr "Inhabilitat" #, c-format msgid "Use _automatically detected IP address: %s" msgstr "Empra l'_adreça IP detectada automàticament: %s" +msgid "ST_UN server:" +msgstr "Servidor ST_UN:" + msgid "<span style=\"italic\">Example: stunserver.org</span>" msgstr "<span style=\"italic\">Exemple: stunserver.org</span>" @@ -12797,9 +12822,8 @@ msgid "Relay Server (TURN)" msgstr "Servidor repetidor (TURN)" -#, fuzzy msgid "_TURN server:" -msgstr "Servidor ST_UN:" +msgstr "Servidor _TURN:" msgid "Proxy Server & Browser" msgstr "Servidor intermediari i navegador" @@ -14372,35 +14396,29 @@ "Aquest connector permet a l'usuari personalitzar els formats de les marques " "horàries de les converses i dels registres." -#, fuzzy msgid "Audio" -msgstr "Auto" - -#, fuzzy +msgstr "Àudio" + msgid "Video" msgstr " Vídeo" msgid "Output" -msgstr "" - -#, fuzzy +msgstr "Sortida" + msgid "_Plugin" -msgstr "Connectors" - -#, fuzzy +msgstr "_Connectors" + msgid "_Device" -msgstr "Dispositiu" +msgstr "_Dispositiu" msgid "Input" -msgstr "" - -#, fuzzy +msgstr "Entrada" + msgid "P_lugin" -msgstr "Connectors" - -#, fuzzy +msgstr "C_onnectors" + msgid "D_evice" -msgstr "Dispositiu" +msgstr "D_ispositiu" #. *< magic #. *< major version @@ -14411,18 +14429,19 @@ #. *< dependencies #. *< priority #. *< id -#, fuzzy msgid "Voice/Video Settings" -msgstr "Edita els paràmetres" +msgstr "Configuració del so/vídeo" #. *< name #. *< version msgid "Configure your microphone and webcam." -msgstr "" +msgstr "Configureu el micròfon i la càmera web." #. *< summary msgid "Configure microphone and webcam settings for voice/video calls." msgstr "" +"Configureu els paràmetres del micròfon i la càmera web per a trucades de veu/" +"vídeo." msgid "Opacity:" msgstr "Opacitat:" @@ -14481,9 +14500,6 @@ "\n" "* Nota: aquest connector requereix Windows 2000 o superior." -msgid "GTK+ Runtime Version" -msgstr "Versió del mòdul d'execució de GTK+" - #. Autostart msgid "Startup" msgstr "Inicialització" @@ -14492,6 +14508,10 @@ msgid "_Start %s on Windows startup" msgstr "_Inicia el %s en iniciar Windows" +# FIXME: entrades/registres? +msgid "Allow multiple instances" +msgstr "Permet diverses instàncies" + msgid "_Dockable Buddy List" msgstr "Llista _d'amics acoblable" @@ -14553,6 +14573,9 @@ msgid "This plugin is useful for debbuging XMPP servers or clients." msgstr "Aquest connector és útil per a depurar servidors i clients XMPP." +#~ msgid "GTK+ Runtime Version" +#~ msgstr "Versió del mòdul d'execució de GTK+" + #~ msgid "Calling ... " #~ msgstr "S'està trucant..." @@ -14796,9 +14819,6 @@ #~ msgid "Could not write" #~ msgstr "No s'ha pogut escriure" -#~ msgid "Could not connect" -#~ msgstr "No s'ha pogut connectar" - #~ msgid "Could not create listen socket" #~ msgstr "No s'ha pogut crear el sòcol per a escoltar"