# HG changeset patch # User Yoshiki Yazawa # Date 1273041754 -32400 # Node ID 77aba27f64da340c7f962e5e771197e064c358b3 # Parent 28dd2b7331fd03e1e196a437a8b8cb8c7aff6b3a# Parent 711cd774ea84f19712de6bde49f07dcfcb8a0e6c merged from im.pidgin.pidgin. removed our modification to jabber file transfer for now. diff -r 28dd2b7331fd -r 77aba27f64da COPYRIGHT --- a/COPYRIGHT Wed Apr 28 19:22:17 2010 +0900 +++ b/COPYRIGHT Wed May 05 15:42:34 2010 +0900 @@ -330,6 +330,7 @@ Andrei Mozzhuhin Christian Muise MXit Lifestyle (Pty) Ltd. +Alexander Nartov Richard Nelson Dennis Nezic Matthew A. Nicholson diff -r 28dd2b7331fd -r 77aba27f64da ChangeLog --- a/ChangeLog Wed Apr 28 19:22:17 2010 +0900 +++ b/ChangeLog Wed May 05 15:42:34 2010 +0900 @@ -4,8 +4,8 @@ General: * Changed GTK+ minimum version requirement to 2.10.0. * Changed GLib minimum version requirement to 2.12.0. - * Using the --disable-nls argument to configre now works properly. You - will no longer be forced to have intltool to configure and build. + * Using the --disable-nls argument to configure now works properly. + You will no longer be forced to have intltool to configure and build. * Fix two related crashes in the GnuTLS and NSS plugins when they suffer internal errors immediately upon attempting to establish an SSL connection. @@ -50,7 +50,9 @@ * The 'Message Timestamp Formats' plugin allows forcing 12-hour timestamps. (Jonathan Maltz) * Fix pastes from Chrome (rich-text pastes and probably URLs - having garbage appended to them) + having garbage appended to them). + * Show file transfer thumbnails for images on supporting protocols + (currently only supported on MSN). Bonjour: * Added support for IPv6. (Thanks to T_X for testing) @@ -72,10 +74,13 @@ authentication fails due to an incorrect password. (This is the same behavior as the legacy authentication method) * Support sending and receiving HTML-formatted messages for ICQ. + * Use the proper URL for "View web profile" link for ICQ buddies. + (Alexander Nartov) MSN: * Support for version 9 of the MSN protocol has been removed. This version is no longer supported on the servers. + * Support file transfer thumbnails (previews) for images. XMPP: * Direct messages to a specific resource only upon receipt of a message @@ -93,6 +98,11 @@ minutes). This fixes an issue with Openfire disconnecting a libpurple-baesd client that has just been quiet for about 6 minutes. + * Only support Google Talk's JID Domain Discovery extension + (allowing a user to log in with "@gmail.com" or "@googlemail.com" + interchangeably) for those two domains. This change was made + due to interoperability issues with some BOSH Connection Managers + and namespaced attributes. Yahoo/Yahoo JAPAN: * Attempt to better handle transparent proxies interfering with diff -r 28dd2b7331fd -r 77aba27f64da ChangeLog.API --- a/ChangeLog.API Wed Apr 28 19:22:17 2010 +0900 +++ b/ChangeLog.API Wed May 05 15:42:34 2010 +0900 @@ -9,14 +9,26 @@ * account-connection-error * purple_account_get_name_for_display * purple_account_get_privacy_type + * purple_account_get_public_alias * purple_account_set_privacy_type + * purple_account_set_public_alias + * buddy-caps-changed blist signal + * Added media_caps to the PurpleBuddy struct * purple_buddy_get_media_caps * purple_buddy_set_media_caps + * purple_certificates_import for importing multiple + certificates from a single file (and corresponding + import_certificates member of PurpleCertificateScheme struct) + * autojoin connection signal * purple_contact_get_group + * sent-attention conversation signal + * got-attention conversation signal + * ui-caps-changed media manager signal * purple_media_candidate_copy * purple_media_codec_copy * purple_media_manager_get_backend_type * purple_media_manager_set_backend_type + * PurpleMood struct in status.h * purple_network_get_all_local_system_ips, which returns all local IPs on the system. On systems with the getifaddrs() function, this will return both IPv4 and IPv6 addresses @@ -29,20 +41,16 @@ only supported if the getaddrinfo() function is available at build-time (not the case on Windows, currently). * purple_prpl_got_media_caps + * purple_request_action_with_icon + * purple_request_action_with_icon_varg * purple_socket_get_family * purple_socket_speaks_ipv4 * purple_unescape_text * purple_uuid_random - * media_caps to the PurpleBuddy struct - * buddy-caps-changed blist signal - * ui-caps-changed media manager signal - * sent-attention conversation signal - * got-attention conversation signal - * PurpleMood struct in status.h - * purple_certificates_import for importing multiple - certificates from a single file (and corresponding - import_certificates member of PurpleCertificateScheme struct) - * autojoin connection signal + * purple_xfer_get_thumbnail + * purple_xfer_get_thumbnail_mimetype + * purple_xfer_set_thumbnail + * purple_xfer_prepare_thumbnail Pidgin: Added: diff -r 28dd2b7331fd -r 77aba27f64da libpurple/account.c --- a/libpurple/account.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/account.c Wed May 05 15:42:34 2010 +0900 @@ -1782,6 +1782,92 @@ schedule_accounts_save(); } +struct public_alias_closure +{ + PurpleAccount *account; + gpointer failure_cb; +}; + +static gboolean +set_public_alias_unsupported(gpointer data) +{ + struct public_alias_closure *closure = data; + PurpleSetPublicAliasFailureCallback failure_cb = closure->failure_cb; + + failure_cb(closure->account, + _("This protocol does not support setting a public alias.")); + g_free(closure); + + return FALSE; +} + +void +purple_account_set_public_alias(PurpleAccount *account, + const char *alias, PurpleSetPublicAliasSuccessCallback success_cb, + PurpleSetPublicAliasFailureCallback failure_cb) +{ + PurpleConnection *gc; + PurplePlugin *prpl = NULL; + PurplePluginProtocolInfo *prpl_info = NULL; + + g_return_if_fail(account != NULL); + g_return_if_fail(purple_account_is_connected(account)); + + gc = purple_account_get_connection(account); + prpl = purple_connection_get_prpl(gc); + prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); + + if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, set_public_alias)) + prpl_info->set_public_alias(gc, alias, success_cb, failure_cb); + else { + struct public_alias_closure *closure = + g_new0(struct public_alias_closure, 1); + closure->account = account; + closure->failure_cb = failure_cb; + purple_timeout_add(0, set_public_alias_unsupported, closure); + } +} + +static gboolean +get_public_alias_unsupported(gpointer data) +{ + struct public_alias_closure *closure = data; + PurpleGetPublicAliasFailureCallback failure_cb = closure->failure_cb; + + failure_cb(closure->account, + _("This protocol does not support fetching the public alias.")); + g_free(closure); + + return FALSE; +} + +void +purple_account_get_public_alias(PurpleAccount *account, + PurpleGetPublicAliasSuccessCallback success_cb, + PurpleGetPublicAliasFailureCallback failure_cb) +{ + PurpleConnection *gc; + PurplePlugin *prpl = NULL; + PurplePluginProtocolInfo *prpl_info = NULL; + + g_return_if_fail(account != NULL); + g_return_if_fail(purple_account_is_connected(account)); + + gc = purple_account_get_connection(account); + prpl = purple_connection_get_prpl(gc); + prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); + + if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, get_public_alias)) + prpl_info->get_public_alias(gc, success_cb, failure_cb); + else { + struct public_alias_closure *closure = + g_new0(struct public_alias_closure, 1); + closure->account = account; + closure->failure_cb = failure_cb; + purple_timeout_add(0, get_public_alias_unsupported, closure); + } +} + void purple_account_clear_settings(PurpleAccount *account) { diff -r 28dd2b7331fd -r 77aba27f64da libpurple/account.h --- a/libpurple/account.h Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/account.h Wed May 05 15:42:34 2010 +0900 @@ -39,6 +39,10 @@ typedef void (*PurpleAccountRequestAuthorizationCb)(void *); typedef void (*PurpleAccountRegistrationCb)(PurpleAccount *account, gboolean succeeded, void *user_data); typedef void (*PurpleAccountUnregistrationCb)(PurpleAccount *account, gboolean succeeded, void *user_data); +typedef void (*PurpleSetPublicAliasSuccessCallback)(PurpleAccount *account, const char *new_alias); +typedef void (*PurpleSetPublicAliasFailureCallback)(PurpleAccount *account, const char *error); +typedef void (*PurpleGetPublicAliasSuccessCallback)(PurpleAccount *account, const char *alias); +typedef void (*PurpleGetPublicAliasFailureCallback)(PurpleAccount *account, const char *error); #include "connection.h" #include "log.h" @@ -462,6 +466,42 @@ const char *status_id, gboolean active, GList *attrs); /** + * Set a server-side (public) alias for this account. The account + * must already be connected. + * + * Currently, the public alias is not stored locally, although this + * may change in a later version. + * + * @param account The account + * @param alias The new public alias for this account or NULL + * to unset the alias/nickname (or return it to + * a protocol-specific "default", like the username) + * @param success_cb A callback which will be called if the alias + * is successfully set on the server (or NULL). + * @param failure_cb A callback which will be called if the alias + * is not successfully set on the server (or NULL). + * + * @since 2.7.0 + */ +void purple_account_set_public_alias(PurpleAccount *account, + const char *alias, PurpleSetPublicAliasSuccessCallback success_cb, + PurpleSetPublicAliasFailureCallback failure_cb); + +/** + * Fetch the server-side (public) alias for this account. The account + * must already be connected. + * + * @param account The account + * @param success_cb A callback which will be called with the alias + * @param failure_cb A callback which will be called if the prpl is + * unable to retrieve the server-side alias. + * @since 2.7.0 + */ +void purple_account_get_public_alias(PurpleAccount *account, + PurpleGetPublicAliasSuccessCallback success_cb, + PurpleGetPublicAliasFailureCallback failure_cb); + +/** * Clears all protocol-specific settings on an account. * * @param account The account. diff -r 28dd2b7331fd -r 77aba27f64da libpurple/ft.c --- a/libpurple/ft.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/ft.c Wed May 05 15:42:34 2010 +0900 @@ -60,6 +60,10 @@ /* TODO: Should really use a PurpleCircBuffer for this. */ GByteArray *buffer; + + gpointer thumbnail_data; /**< thumbnail image */ + gsize thumbnail_size; + gchar *thumbnail_mimetype; } PurpleXferPrivData; static int purple_xfer_choose_file(PurpleXfer *xfer); @@ -72,6 +76,10 @@ if (priv->buffer) g_byte_array_free(priv->buffer, TRUE); + g_free(priv->thumbnail_data); + + g_free(priv->thumbnail_mimetype); + g_free(priv); } @@ -266,15 +274,21 @@ } } -void purple_xfer_conversation_write(PurpleXfer *xfer, char *message, gboolean is_error) +static void +purple_xfer_conversation_write_internal(PurpleXfer *xfer, + const char *message, gboolean is_error, gboolean print_thumbnail) { PurpleConversation *conv = NULL; PurpleMessageFlags flags = PURPLE_MESSAGE_SYSTEM; char *escaped; + gconstpointer thumbnail_data; + gsize size; g_return_if_fail(xfer != NULL); g_return_if_fail(message != NULL); + thumbnail_data = purple_xfer_get_thumbnail(xfer, &size); + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, xfer->who, purple_xfer_get_account(xfer)); @@ -286,10 +300,39 @@ if (is_error) flags |= PURPLE_MESSAGE_ERROR; - purple_conversation_write(conv, NULL, escaped, flags, time(NULL)); + if (print_thumbnail && thumbnail_data) { + gchar *message_with_img; + gpointer data = g_memdup(thumbnail_data, size); + int id = purple_imgstore_add_with_id(data, size, NULL); + + message_with_img = + g_strdup_printf(" %s", id, escaped); + purple_conversation_write(conv, NULL, message_with_img, flags, + time(NULL)); + purple_imgstore_unref_by_id(id); + g_free(message_with_img); + } else { + purple_conversation_write(conv, NULL, escaped, flags, time(NULL)); + } g_free(escaped); } +void +purple_xfer_conversation_write(PurpleXfer *xfer, gchar *message, + gboolean is_error) +{ + purple_xfer_conversation_write_internal(xfer, message, is_error, FALSE); +} + +/* maybe this one should be exported publically? */ +static void +purple_xfer_conversation_write_with_thumbnail(PurpleXfer *xfer, + const gchar *message) +{ + purple_xfer_conversation_write_internal(xfer, message, FALSE, TRUE); +} + + static void purple_xfer_show_file_error(PurpleXfer *xfer, const char *filename) { int err = errno; @@ -448,6 +491,8 @@ { char *buf, *size_buf; size_t size; + gconstpointer thumb; + gsize thumb_size; /* If we have already accepted the request, ask the destination file name directly */ @@ -473,13 +518,19 @@ serv_got_im(purple_account_get_connection(xfer->account), xfer->who, xfer->message, 0, time(NULL)); - purple_request_accept_cancel(xfer, NULL, buf, NULL, - PURPLE_DEFAULT_ACTION_NONE, - xfer->account, xfer->who, NULL, - xfer, - G_CALLBACK(purple_xfer_choose_file), - G_CALLBACK(cancel_recv_cb)); - + if ((thumb = purple_xfer_get_thumbnail(xfer, &thumb_size))) { + purple_request_accept_cancel_with_icon(xfer, NULL, buf, NULL, + PURPLE_DEFAULT_ACTION_NONE, xfer->account, xfer->who, NULL, + thumb, thumb_size, xfer, + G_CALLBACK(purple_xfer_choose_file), + G_CALLBACK(cancel_recv_cb)); + } else { + purple_request_accept_cancel(xfer, NULL, buf, NULL, + PURPLE_DEFAULT_ACTION_NONE, xfer->account, xfer->who, NULL, + xfer, G_CALLBACK(purple_xfer_choose_file), + G_CALLBACK(cancel_recv_cb)); + } + g_free(buf); } else purple_xfer_choose_file(xfer); @@ -547,10 +598,12 @@ { gchar* message = NULL; PurpleBuddy *buddy = purple_find_buddy(xfer->account, xfer->who); + message = g_strdup_printf(_("%s is offering to send file %s"), buddy ? purple_buddy_get_alias(buddy) : xfer->who, purple_xfer_get_filename(xfer)); - purple_xfer_conversation_write(xfer, message, FALSE); + purple_xfer_conversation_write_with_thumbnail(xfer, message); g_free(message); + /* Ask for a filename to save to if it's not already given by a plugin */ if (xfer->local_filename == NULL) purple_xfer_ask_recv(xfer); @@ -1580,6 +1633,52 @@ ui_ops->update_progress(xfer, purple_xfer_get_progress(xfer)); } +gconstpointer +purple_xfer_get_thumbnail(const PurpleXfer *xfer, gsize *len) +{ + PurpleXferPrivData *priv = g_hash_table_lookup(xfers_data, xfer); + + if (len) + *len = priv->thumbnail_size; + + return priv->thumbnail_data; +} + +const gchar * +purple_xfer_get_thumbnail_mimetype(const PurpleXfer *xfer) +{ + PurpleXferPrivData *priv = g_hash_table_lookup(xfers_data, xfer); + + return priv->thumbnail_mimetype; +} + +void +purple_xfer_set_thumbnail(PurpleXfer *xfer, gconstpointer thumbnail, + gsize size, const gchar *mimetype) +{ + PurpleXferPrivData *priv = g_hash_table_lookup(xfers_data, xfer); + + g_free(priv->thumbnail_data); + g_free(priv->thumbnail_mimetype); + + if (thumbnail && size > 0) { + priv->thumbnail_data = g_memdup(thumbnail, size); + priv->thumbnail_size = size; + priv->thumbnail_mimetype = g_strdup(mimetype); + } else { + priv->thumbnail_data = NULL; + priv->thumbnail_size = 0; + priv->thumbnail_mimetype = NULL; + } +} + +void +purple_xfer_prepare_thumbnail(PurpleXfer *xfer, const gchar *formats) +{ + if (xfer->ui_ops->add_thumbnail) { + xfer->ui_ops->add_thumbnail(xfer, formats); + } +} /************************************************************************** * File Transfer Subsystem API diff -r 28dd2b7331fd -r 77aba27f64da libpurple/ft.h --- a/libpurple/ft.h Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/ft.h Wed May 05 15:42:34 2010 +0900 @@ -120,7 +120,12 @@ */ void (*data_not_sent)(PurpleXfer *xfer, const guchar *buffer, gsize size); - void (*_purple_reserved1)(void); + /** + * Op to create a thumbnail image for a file transfer + * + * @param xfer The file transfer structure + */ + void (*add_thumbnail)(PurpleXfer *xfer, const gchar *formats); } PurpleXferUiOps; /** @@ -687,6 +692,51 @@ */ void purple_xfer_prpl_ready(PurpleXfer *xfer); +/** + * Gets the thumbnail data for a transfer + * + * @param xfer The file transfer to get the thumbnail for + * @param len If not @c NULL, the length of the thumbnail data returned + * will be set in the location pointed to by this. + * @return The thumbnail data, or NULL if there is no thumbnail + * @since 2.7.0 + */ +gconstpointer purple_xfer_get_thumbnail(const PurpleXfer *xfer, gsize *len); + +/** + * Gets the mimetype of the thumbnail preview for a transfer + * + * @param xfer The file transfer to get the mimetype for + * @return The mimetype of the thumbnail, or @c NULL if not thumbnail is set + * @since 2.7.0 + */ +const gchar *purple_xfer_get_thumbnail_mimetype(const PurpleXfer *xfer); + + +/** + * Sets the thumbnail data for a transfer + * + * @param xfer The file transfer to set the data for + * @param thumbnail A pointer to the thumbnail data, this will be copied + * @param size The size in bytes of the passed in thumbnail data + * @param mimetype The mimetype of the generated thumbnail + * @since 2.7.0 + */ +void purple_xfer_set_thumbnail(PurpleXfer *xfer, gconstpointer thumbnail, + gsize size, const gchar *mimetype); + +/** + * Prepare a thumbnail for a transfer (if the UI supports it) + * will be no-op in case the UI doesn't implement thumbnail creation + * + * @param xfer The file transfer to create a thumbnail for + * @param formats A comma-separated list of mimetypes for image formats + * the protocols can use for thumbnails. + * @since 2.7.0 + */ +void purple_xfer_prepare_thumbnail(PurpleXfer *xfer, const gchar *formats); + + /*@}*/ /**************************************************************************/ diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/bonjour/bonjour.c --- a/libpurple/protocols/bonjour/bonjour.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/bonjour/bonjour.c Wed May 05 15:42:34 2010 +0900 @@ -528,7 +528,9 @@ NULL, /* get_account_text_table */ NULL, /* initiate_media */ NULL, /* get_media_caps */ - NULL /* get_moods */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; static PurplePluginInfo info = diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/gg/gg.c --- a/libpurple/protocols/gg/gg.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/gg/gg.c Wed May 05 15:42:34 2010 +0900 @@ -1601,12 +1601,6 @@ } break; case GG_EVENT_NOTIFY60: - purple_debug_info("gg", - "notify60_pre: (%d) status=%d; version=%d; descr=%s\n", - ev->event.notify60->uin, GG_S(ev->event.notify60->status), - ev->event.notify60->version, - ev->event.notify60->descr ? ev->event.notify60->descr : "(null)"); - for (i = 0; ev->event.notify60[i].uin; i++) { purple_debug_info("gg", "notify60: (%d) status=%d; version=%d; descr=%s\n", @@ -1737,7 +1731,7 @@ ggp_callback_recv, gc); ggp_buddylist_send(gc); - purple_connection_update_progress(gc, _("Connected"), 2, 2); + purple_connection_update_progress(gc, _("Connected"), 1, 2); purple_connection_set_state(gc, PURPLE_CONNECTED); } break; @@ -1990,7 +1984,7 @@ purple_debug_info("gg", "Trying to retrieve address from gg appmsg service\n"); info->session = gg_login(glp); - purple_connection_update_progress(gc, _("Connecting"), 1, 2); + purple_connection_update_progress(gc, _("Connecting"), 0, 2); if (info->session == NULL) { purple_connection_error_reason (gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, @@ -2512,7 +2506,9 @@ NULL, /* get_account_text_table */ NULL, /* initiate_media */ NULL, /* can_do_media */ - NULL /* get_moods */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; static PurplePluginInfo info = { diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/gg/search.c --- a/libpurple/protocols/gg/search.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/gg/search.c Wed May 05 15:42:34 2010 +0900 @@ -207,7 +207,7 @@ { char *tmp; - tmp = charset_convert(gg_pubdir50_get(res, num, field), "CP1250", "UTF-8"); + tmp = g_strdup(gg_pubdir50_get(res, num, field)); return (tmp == NULL) ? g_strdup("") : tmp; } diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/irc/irc.c --- a/libpurple/protocols/irc/irc.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/irc/irc.c Wed May 05 15:42:34 2010 +0900 @@ -945,7 +945,9 @@ NULL, /* get_account_text_table */ NULL, /* initiate_media */ NULL, /* get_media_caps */ - NULL /* get_moods */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; static gboolean load_plugin (PurplePlugin *plugin) { diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/jabber/auth.c --- a/libpurple/protocols/jabber/auth.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/jabber/auth.c Wed May 05 15:42:34 2010 +0900 @@ -45,35 +45,6 @@ JabberIqType type, const char *id, xmlnode *packet, gpointer data); -gboolean -jabber_process_starttls(JabberStream *js, xmlnode *packet) -{ - PurpleAccount *account; - xmlnode *starttls; - - account = purple_connection_get_account(js->gc); - - if((starttls = xmlnode_get_child(packet, "starttls"))) { - if(purple_ssl_is_supported()) { - jabber_send_raw(js, - "", -1); - return TRUE; - } else if(xmlnode_get_child(starttls, "required")) { - purple_connection_error_reason(js->gc, - PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, - _("Server requires TLS/SSL, but no TLS/SSL support was found.")); - return TRUE; - } else if(purple_account_get_bool(account, "require_tls", JABBER_DEFAULT_REQUIRE_TLS)) { - purple_connection_error_reason(js->gc, - PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, - _("You require encryption, but no TLS/SSL support was found.")); - return TRUE; - } - } - - return FALSE; -} - static void finish_plaintext_authentication(JabberStream *js) { JabberIq *iq; diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/jabber/auth.h --- a/libpurple/protocols/jabber/auth.h Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/jabber/auth.h Wed May 05 15:42:34 2010 +0900 @@ -45,7 +45,6 @@ void (*dispose)(JabberStream *js); }; -gboolean jabber_process_starttls(JabberStream *js, xmlnode *packet); void jabber_auth_start(JabberStream *js, xmlnode *packet); void jabber_auth_start_old(JabberStream *js); void jabber_auth_handle_challenge(JabberStream *js, xmlnode *packet); diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/jabber/auth_cyrus.c --- a/libpurple/protocols/jabber/auth_cyrus.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/jabber/auth_cyrus.c Wed May 05 15:42:34 2010 +0900 @@ -252,29 +252,14 @@ g_free(msg); return JABBER_SASL_STATE_CONTINUE; - } else { - /* We have no mechs which can work. - * Try falling back on the old jabber:iq:auth method. We get here if the server supports - * one or more sasl mechs, we are compiled with cyrus-sasl support, but we support or can connect with none of - * the offerred mechs. jabberd 2.0 w/ SASL and Apple's iChat Server 10.5 both handle and expect - * jabber:iq:auth in this situation. iChat Server in particular offers SASL GSSAPI by default, which is often - * not configured on the client side, and expects a fallback to jabber:iq:auth when it (predictably) fails. - * - * Note: xep-0078 points out that using jabber:iq:auth after a sasl failure is wrong. However, - * I believe this refers to actual authentication failure, not a simple lack of concordant mechanisms. - * Doing otherwise means that simply compiling with SASL support renders the client unable to connect to servers - * which would connect without issue otherwise. -evands - */ - js->auth_mech = NULL; - jabber_auth_start_old(js); - return JABBER_SASL_STATE_CONTINUE; } - /* not reached */ + break; /* Fatal errors. Give up and go home */ case SASL_BADPARAM: case SASL_NOMEM: + *error = g_strdup(_("SASL authentication failed")); break; /* For everything else, fail the mechanism and try again */ @@ -314,8 +299,11 @@ xmlnode_set_namespace(auth, NS_XMPP_SASL); xmlnode_set_attrib(auth, "mechanism", js->current_mech); - xmlnode_set_attrib(auth, "xmlns:ga", "http://www.google.com/talk/protocol/auth"); - xmlnode_set_attrib(auth, "ga:client-uses-full-bind-result", "true"); + if (g_str_equal(js->user->domain, "gmail.com") || + g_str_equal(js->user->domain, "googlemail.com")) { + xmlnode_set_attrib(auth, "xmlns:ga", "http://www.google.com/talk/protocol/auth"); + xmlnode_set_attrib(auth, "ga:client-uses-full-bind-result", "true"); + } if (clientout) { if (coutlen == 0) { @@ -330,7 +318,6 @@ *reply = auth; return JABBER_SASL_STATE_CONTINUE; } else { - *error = g_strdup(_("SASL authentication failed")); return JABBER_SASL_STATE_FAIL; } } @@ -404,17 +391,6 @@ continue; } - /* Don't include Google Talk's X-GOOGLE-TOKEN mechanism - * or Facebook Chat's X-FACEBOOK-PLATFORM mechansim, - * as we will not support them and including them gives a false fall-back - * to other mechs offerred, leading to incorrect error handling. - */ - if (g_str_equal(mech_name, "X-GOOGLE-TOKEN") - || g_str_equal(mech_name, "X-FACEBOOK-PLATFORM") ) { - g_free(mech_name); - continue; - } - g_string_append(js->sasl_mechs, mech_name); g_string_append_c(js->sasl_mechs, ' '); g_free(mech_name); @@ -542,6 +518,25 @@ sasl_dispose(&js->sasl); return jabber_auth_start_cyrus(js, reply, error); + + } else if ((js->auth_fail_count == 1) && + (js->current_mech && g_str_equal(js->current_mech, "GSSAPI"))) { + /* If we tried GSSAPI first, it failed, and it was the only method we had to try, try jabber:iq:auth + * for compatibility with iChat 10.5 Server. + * + * iChat Server 10.5 offers SASL GSSAPI by default, which is often + * not configured on the client side, and expects a fallback to jabber:iq:auth when it (predictably) fails. + * + * Note: xep-0078 points out that using jabber:iq:auth after a sasl failure is wrong. However, + * I believe this refers to actual authentication failure, not a simple lack of concordant mechanisms. + * Doing otherwise means that simply compiling with SASL support renders the client unable to connect to servers + * which would connect without issue otherwise. -evands + */ + sasl_dispose(&js->sasl); + js->sasl = NULL; + js->auth_mech = NULL; + jabber_auth_start_old(js); + return JABBER_SASL_STATE_CONTINUE; } } diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/jabber/auth_digest_md5.c --- a/libpurple/protocols/jabber/auth_digest_md5.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/jabber/auth_digest_md5.c Wed May 05 15:42:34 2010 +0900 @@ -188,16 +188,17 @@ if (g_hash_table_lookup(parts, "rspauth")) { char *rspauth = g_hash_table_lookup(parts, "rspauth"); + char *expected_rspauth = js->auth_mech_data; - if (rspauth && purple_strequal(rspauth, js->expected_rspauth)) { + if (rspauth && purple_strequal(rspauth, expected_rspauth)) { reply = xmlnode_new("response"); xmlnode_set_namespace(reply, NS_XMPP_SASL); } else { *msg = g_strdup(_("Invalid challenge from server")); state = JABBER_SASL_STATE_FAIL; } - g_free(js->expected_rspauth); - js->expected_rspauth = NULL; + g_free(js->auth_mech_data); + js->auth_mech_data = NULL; } else { /* assemble a response, and send it */ /* see RFC 2831 */ @@ -235,7 +236,7 @@ g_free(a2); a2 = g_strdup_printf(":xmpp/%s", realm); - js->expected_rspauth = generate_response_value(js->user, + js->auth_mech_data = generate_response_value(js->user, purple_connection_get_password(js->gc), nonce, cnonce, a2, realm); g_free(a2); @@ -276,6 +277,13 @@ return state; } +static void +digest_md5_dispose(JabberStream *js) +{ + g_free(js->auth_mech_data); + js->auth_mech_data = NULL; +} + static JabberSaslMech digest_md5_mech = { 10, /* priority */ "DIGEST-MD5", /* name */ @@ -283,7 +291,7 @@ digest_md5_handle_challenge, NULL, /* handle_success */ NULL, /* handle_failure */ - NULL /* handle_dispose */ + digest_md5_dispose, }; JabberSaslMech *jabber_auth_get_digest_md5_mech(void) diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/jabber/auth_plain.c --- a/libpurple/protocols/jabber/auth_plain.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/jabber/auth_plain.c Wed May 05 15:42:34 2010 +0900 @@ -40,13 +40,16 @@ auth = xmlnode_new("auth"); xmlnode_set_namespace(auth, NS_XMPP_SASL); - xmlnode_set_attrib(auth, "xmlns:ga", "http://www.google.com/talk/protocol/auth"); - xmlnode_set_attrib(auth, "ga:client-uses-full-bind-result", "true"); + if (g_str_equal(js->user->domain, "gmail.com") || + g_str_equal(js->user->domain, "googlemail.com")) { + xmlnode_set_attrib(auth, "xmlns:ga", "http://www.google.com/talk/protocol/auth"); + xmlnode_set_attrib(auth, "ga:client-uses-full-bind-result", "true"); + } response = g_string_new(""); - response = g_string_append_len(response, "\0", 1); + response = g_string_append_c(response, '\0'); response = g_string_append(response, js->user->node); - response = g_string_append_len(response, "\0", 1); + response = g_string_append_c(response, '\0'); response = g_string_append(response, purple_connection_get_password(js->gc)); diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/jabber/auth_scram.c --- a/libpurple/protocols/jabber/auth_scram.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/jabber/auth_scram.c Wed May 05 15:42:34 2010 +0900 @@ -47,6 +47,32 @@ g_return_val_if_reached(NULL); } +static const struct { + const char *error; + const char *meaning; +} server_errors[] = { + { "invalid-encoding", + N_("Invalid Encoding")}, + { "extensions-not-supported", + N_("Unsupported Extension") }, + { "channel-bindings-dont-match", + N_("Unexpected response from the server. This may indicate a possible MITM attack") }, + { "server-does-support-channel-binding", + N_("The server does support channel binding, but did not appear to advertise it. This indicates a likely MITM attack") }, + { "channel-binding-not-supported", + N_("Server does not support channel binding") }, + { "unsupported-channel-binding-type", + N_("Unsupported channel binding method") }, + { "unknown-user", + N_("User not found") }, + { "invalid-username-encoding", + N_("Invalid Username Encoding") }, + { "no-resources", + N_("Resource Constraint") }, + { "other-error", + N_("Unknown Error") } +}; + guchar *jabber_scram_hi(const JabberScramHash *hash, const GString *str, GString *salt, guint iterations) { diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/jabber/data.c --- a/libpurple/protocols/jabber/data.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/jabber/data.c Wed May 05 15:42:34 2010 +0900 @@ -36,7 +36,7 @@ JabberData * jabber_data_create_from_data(gconstpointer rawdata, gsize size, const char *type, - JabberStream *js) + gboolean ephemeral, JabberStream *js) { JabberData *data = g_new0(JabberData, 1); gchar *checksum = jabber_calculate_data_hash(rawdata, size, "sha1"); @@ -48,6 +48,7 @@ data->cid = g_strdup(cid); data->type = g_strdup(type); data->size = size; + data->ephemeral = ephemeral; data->data = g_memdup(rawdata, size); @@ -110,6 +111,12 @@ return data; } +void +jabber_data_destroy(JabberData *data) +{ + jabber_data_delete(data); +} + const char * jabber_data_get_cid(const JabberData *data) { @@ -289,14 +296,14 @@ const JabberData * jabber_data_find_local_by_alt(const gchar *alt) { - purple_debug_info("jabber", "looking up local smiley with alt = %s\n", alt); + purple_debug_info("jabber", "looking up local data object with alt = %s\n", alt); return g_hash_table_lookup(local_data_by_alt, alt); } const JabberData * jabber_data_find_local_by_cid(const gchar *cid) { - purple_debug_info("jabber", "lookup local smiley with cid = %s\n", cid); + purple_debug_info("jabber", "lookup local data object with cid = %s\n", cid); return g_hash_table_lookup(local_data_by_cid, cid); } @@ -305,7 +312,7 @@ const gchar *cid) { const JabberData *data = g_hash_table_lookup(remote_data_by_cid, cid); - purple_debug_info("jabber", "lookup remote smiley with cid = %s\n", cid); + purple_debug_info("jabber", "lookup remote data object with cid = %s\n", cid); if (data == NULL) { gchar *jid_cid = @@ -323,9 +330,10 @@ void jabber_data_associate_local(JabberData *data, const gchar *alt) { - purple_debug_info("jabber", "associating local smiley\n alt = %s, cid = %s\n", - alt, jabber_data_get_cid(data)); - g_hash_table_insert(local_data_by_alt, g_strdup(alt), data); + purple_debug_info("jabber", "associating local data object\n alt = %s, cid = %s\n", + alt , jabber_data_get_cid(data)); + if (alt) + g_hash_table_insert(local_data_by_alt, g_strdup(alt), data); g_hash_table_insert(local_data_by_cid, g_strdup(jabber_data_get_cid(data)), data); } @@ -371,6 +379,11 @@ xmlnode_set_attrib(result->node, "id", id); xmlnode_insert_child(result->node, jabber_data_get_xml_definition(data)); + /* if the data object is temporary, destroy it and remove the references + to it */ + if (data->ephemeral) { + g_hash_table_remove(local_data_by_cid, cid); + } } jabber_iq_send(result); } diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/jabber/data.h --- a/libpurple/protocols/jabber/data.h Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/jabber/data.h Wed May 05 15:42:34 2010 +0900 @@ -34,6 +34,7 @@ char *type; gsize size; gpointer data; + gboolean ephemeral; } JabberData; typedef void (JabberDataRequestCallback)(JabberData *data, gchar *alt, @@ -42,12 +43,16 @@ /* creates a JabberData instance from raw data */ JabberData *jabber_data_create_from_data(gconstpointer data, gsize size, - const char *type, JabberStream *js); + const char *type, gboolean ephemeral, JabberStream *js); /* create a JabberData instance from an XML "data" element (as defined by XEP 0231 */ JabberData *jabber_data_create_from_xml(xmlnode *tag); +/* destroy a JabberData instance, NOT to be used on data that has been + associated, since they get "owned" */ +void jabber_data_destroy(JabberData *data); + const char *jabber_data_get_cid(const JabberData *data); const char *jabber_data_get_type(const JabberData *data); diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/jabber/jabber.c --- a/libpurple/protocols/jabber/jabber.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/jabber/jabber.c Wed May 05 15:42:34 2010 +0900 @@ -210,6 +210,35 @@ return purple_strreplace(input, "__HOSTNAME__", hostname); } +static gboolean +jabber_process_starttls(JabberStream *js, xmlnode *packet) +{ + PurpleAccount *account; + xmlnode *starttls; + + account = purple_connection_get_account(js->gc); + + if((starttls = xmlnode_get_child(packet, "starttls"))) { + if(purple_ssl_is_supported()) { + jabber_send_raw(js, + "", -1); + return TRUE; + } else if(xmlnode_get_child(starttls, "required")) { + purple_connection_error_reason(js->gc, + PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, + _("Server requires TLS/SSL, but no TLS/SSL support was found.")); + return TRUE; + } else if(purple_account_get_bool(account, "require_tls", JABBER_DEFAULT_REQUIRE_TLS)) { + purple_connection_error_reason(js->gc, + PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, + _("You require encryption, but no TLS/SSL support was found.")); + return TRUE; + } + } + + return FALSE; +} + void jabber_stream_features_parse(JabberStream *js, xmlnode *packet) { if(xmlnode_get_child(packet, "starttls")) { @@ -364,8 +393,7 @@ int ret; gboolean success = TRUE; - if (len == -1) - len = strlen(data); + g_return_val_if_fail(len > 0, FALSE); if (js->state == JABBER_STREAM_CONNECTED) jabber_stream_restart_inactivity_timer(js); @@ -409,6 +437,12 @@ void jabber_send_raw(JabberStream *js, const char *data, int len) { + PurpleConnection *gc; + PurpleAccount *account; + + gc = js->gc; + account = purple_connection_get_account(gc); + /* because printing a tab to debug every minute gets old */ if(strcmp(data, "\t")) { const char *username; @@ -436,9 +470,9 @@ *data_start = '\0'; } - username = purple_connection_get_display_name(js->gc); + username = purple_connection_get_display_name(gc); if (!username) - username = purple_account_get_username(purple_connection_get_account(js->gc)); + username = purple_account_get_username(account); purple_debug_misc("jabber", "Sending%s (%s): %s%s%s\n", jabber_stream_is_ssl(js) ? " (ssl)" : "", username, @@ -449,10 +483,13 @@ g_free(text); } - purple_signal_emit(purple_connection_get_prpl(js->gc), "jabber-sending-text", js->gc, &data); + purple_signal_emit(purple_connection_get_prpl(gc), "jabber-sending-text", gc, &data); if (data == NULL) return; + if (len == -1) + len = strlen(data); + /* If we've got a security layer, we need to encode the data, * splitting it on the maximum buffer length negotiated */ #ifdef HAVE_CYRUS_SASL @@ -460,21 +497,36 @@ int pos = 0; if (!js->gsc && js->fd<0) - return; - - if (len == -1) - len = strlen(data); + g_return_if_reached(); while (pos < len) { int towrite; const char *out; unsigned olen; + int rc; towrite = MIN((len - pos), js->sasl_maxbuf); - sasl_encode(js->sasl, &data[pos], towrite, &out, &olen); + rc = sasl_encode(js->sasl, &data[pos], towrite, + &out, &olen); + if (rc != SASL_OK) { + gchar *error = + g_strdup_printf(_("SASL error: %s"), + sasl_errdetail(js->sasl)); + purple_debug_error("jabber", + "sasl_encode error %d: %s\n", rc, + sasl_errdetail(js->sasl)); + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + error); + g_free(error); + return; + } pos += towrite; + /* do_jabber_send_raw returns FALSE when it throws a + * connection error. + */ if (!do_jabber_send_raw(js, out, olen)) break; } @@ -482,9 +534,6 @@ } #endif - if (len == -1) - len = strlen(data); - if (js->bosh) jabber_bosh_connection_send_raw(js->bosh, data); else @@ -493,7 +542,7 @@ int jabber_prpl_send_raw(PurpleConnection *gc, const char *buf, int len) { - JabberStream *js = (JabberStream*)gc->proto_data; + JabberStream *js = purple_connection_get_protocol_data(gc); jabber_send_raw(js, buf, len); return len; } @@ -599,7 +648,7 @@ jabber_recv_cb(gpointer data, gint source, PurpleInputCondition condition) { PurpleConnection *gc = data; - JabberStream *js = gc->proto_data; + JabberStream *js = purple_connection_get_protocol_data(gc); int len; static char buf[4096]; @@ -609,14 +658,26 @@ if((len = read(js->fd, buf, sizeof(buf) - 1)) > 0) { gc->last_received = time(NULL); #ifdef HAVE_CYRUS_SASL - if (js->sasl_maxbuf>0) { + if (js->sasl_maxbuf > 0) { const char *out; unsigned int olen; - sasl_decode(js->sasl, buf, len, &out, &olen); - if (olen>0) { + int rc; + + rc = sasl_decode(js->sasl, buf, len, &out, &olen); + if (rc != SASL_OK) { + gchar *error = + g_strdup_printf(_("SASL error: %s"), + sasl_errdetail(js->sasl)); + purple_debug_error("jabber", + "sasl_decode_error %d: %s\n", rc, + sasl_errdetail(js->sasl)); + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + error); + } else if (olen > 0) { purple_debug_info("jabber", "RecvSASL (%u): %s\n", olen, out); - jabber_parser_process(js,out,olen); - if(js->reinit) + jabber_parser_process(js, out, olen); + if (js->reinit) jabber_stream_init(js); } return; @@ -1586,7 +1647,6 @@ g_free(js->old_source); g_free(js->old_uri); g_free(js->old_track); - g_free(js->expected_rspauth); if (js->vcard_timer != 0) purple_timeout_remove(js->vcard_timer); diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/jabber/jabber.h --- a/libpurple/protocols/jabber/jabber.h Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/jabber/jabber.h Wed May 05 15:42:34 2010 +0900 @@ -112,7 +112,7 @@ JabberSaslMech *auth_mech; gpointer auth_mech_data; - + /** * The header from the opening tag. This being NULL is treated * as a special condition in the parsing code (signifying the next @@ -122,9 +122,6 @@ char *stream_id; JabberStreamState state; - /* SASL authentication */ - char *expected_rspauth; - GHashTable *buddies; /* diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/jabber/libxmpp.c --- a/libpurple/protocols/jabber/libxmpp.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/jabber/libxmpp.c Wed May 05 15:42:34 2010 +0900 @@ -127,7 +127,9 @@ NULL, /* get_account_text_table */ jabber_initiate_media, /* initiate_media */ jabber_get_media_caps, /* get_media_caps */ - jabber_get_moods /* get_moods */ + jabber_get_moods, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; static gboolean load_plugin(PurplePlugin *plugin) diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/jabber/message.c --- a/libpurple/protocols/jabber/message.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/jabber/message.c Wed May 05 15:42:34 2010 +0900 @@ -969,7 +969,7 @@ JabberData *new_data = jabber_data_create_from_data(purple_imgstore_get_data(image), purple_imgstore_get_size(image), - jabber_message_get_mimetype_from_ext(ext), js); + jabber_message_get_mimetype_from_ext(ext), FALSE, js); purple_debug_info("jabber", "cache local smiley alt = %s, cid = %s\n", shortcut, jabber_data_get_cid(new_data)); diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/jabber/namespaces.h --- a/libpurple/protocols/jabber/namespaces.h Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/jabber/namespaces.h Wed May 05 15:42:34 2010 +0900 @@ -89,6 +89,9 @@ /* XEP-0237 Roster Versioning */ #define NS_ROSTER_VERSIONING "urn:xmpp:features:rosterver" +/* XEP-0264 File Transfer Thumbnails (Thumbs) */ +#define NS_THUMBS "urn:xmpp:thumbs:0" + /* Google extensions */ #define NS_GOOGLE_CAMERA "http://www.google.com/xmpp/protocol/camera/v1" #define NS_GOOGLE_VIDEO "http://www.google.com/xmpp/protocol/video/v1" diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/jabber/presence.c --- a/libpurple/protocols/jabber/presence.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/jabber/presence.c Wed May 05 15:42:34 2010 +0900 @@ -924,8 +924,9 @@ goto out; } - presence.chat = jabber_chat_find(js, presence.jid_from->node, - presence.jid_from->domain); + if (presence.jid_from->node) + presence.chat = jabber_chat_find(js, presence.jid_from->node, + presence.jid_from->domain); if(presence.jb->error_msg) { g_free(presence.jb->error_msg); presence.jb->error_msg = NULL; diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/jabber/si.c --- a/libpurple/protocols/jabber/si.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/jabber/si.c Wed May 05 15:42:34 2010 +0900 @@ -32,6 +32,7 @@ #include "notify.h" #include "buddy.h" +#include "data.h" #include "disco.h" #include "jabber.h" #include "ibb.h" @@ -39,6 +40,7 @@ #include "si.h" #define STREAMHOST_CONNECT_TIMEOUT 15 +#define ENABLE_FT_THUMBNAILS 0 #include "util.h" @@ -1248,18 +1250,14 @@ JabberIq *iq; xmlnode *si, *file, *feature, *x, *field, *option, *value; char buf[32]; - gchar *f1 = NULL, *f2 = NULL; - gsize dummy; +#if ENABLE_FT_THUMBNAILS + gconstpointer thumb; + gsize thumb_size; - /* yaz */ - f1 = g_filename_display_basename(xfer->local_filename); - f2 = botch_utf(f1, strlen(f1), &dummy); - if(f2){ - purple_xfer_set_filename(xfer, (char *)f2); - } - g_free(f1); f1 = NULL; - g_free(f2); f2 = NULL; - + purple_xfer_prepare_thumbnail(xfer, "jpeg,png"); +#endif + xfer->filename = g_path_get_basename(xfer->local_filename); + iq = jabber_iq_new(jsx->js, JABBER_IQ_SET); xmlnode_set_attrib(iq->node, "to", xfer->who); si = xmlnode_new_child(iq->node, "si"); @@ -1277,6 +1275,23 @@ xmlnode_set_attrib(file, "size", buf); /* maybe later we'll do hash and date attribs */ +#if ENABLE_FT_THUMBNAILS + /* add thumbnail, if appropriate */ + if ((thumb = purple_xfer_get_thumbnail(xfer, &thumb_size))) { + const gchar *mimetype = purple_xfer_get_thumbnail_mimetype(xfer); + JabberData *thumbnail_data = + jabber_data_create_from_data(thumb, thumb_size, + mimetype, TRUE, jsx->js); + xmlnode *thumbnail = xmlnode_new_child(file, "thumbnail"); + xmlnode_set_namespace(thumbnail, NS_THUMBS); + xmlnode_set_attrib(thumbnail, "cid", + jabber_data_get_cid(thumbnail_data)); + xmlnode_set_attrib(thumbnail, "mime-type", mimetype); + /* cache data */ + jabber_data_associate_local(thumbnail_data, NULL); + } +#endif + feature = xmlnode_new_child(si, "feature"); xmlnode_set_namespace(feature, "http://jabber.org/protocol/feature-neg"); x = xmlnode_new_child(feature, "x"); @@ -1655,12 +1670,29 @@ purple_xfer_request(xfer); } +#if ENABLE_FT_THUMBNAILS +static void +jabber_si_thumbnail_cb(JabberData *data, gchar *alt, gpointer userdata) +{ + PurpleXfer *xfer = (PurpleXfer *) userdata; + + if (data) { + purple_xfer_set_thumbnail(xfer, jabber_data_get_data(data), + jabber_data_get_size(data), jabber_data_get_type(data)); + /* data is ephemeral, get rid of now (the xfer re-owned the thumbnail */ + jabber_data_destroy(data); + } + + purple_xfer_request(xfer); +} +#endif + void jabber_si_parse(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *si) { JabberSIXfer *jsx; PurpleXfer *xfer; - xmlnode *file, *feature, *x, *field, *option, *value; + xmlnode *file, *feature, *x, *field, *option, *value, *thumbnail; const char *stream_id, *filename, *filesize_c, *profile; size_t filesize = 0; @@ -1742,10 +1774,27 @@ purple_xfer_set_request_denied_fnc(xfer, jabber_si_xfer_request_denied); purple_xfer_set_cancel_recv_fnc(xfer, jabber_si_xfer_cancel_recv); purple_xfer_set_end_fnc(xfer, jabber_si_xfer_end); - + js->file_transfers = g_list_append(js->file_transfers, xfer); +#if ENABLE_FT_THUMBNAILS + /* if there is a thumbnail, we should request it... */ + if ((thumbnail = xmlnode_get_child_with_namespace(file, "thumbnail", + NS_THUMBS))) { + const char *cid = xmlnode_get_attrib(thumbnail, "cid"); + if (cid) { + jabber_data_request(js, cid, purple_xfer_get_remote_user(xfer), + NULL, TRUE, jabber_si_thumbnail_cb, xfer); + } else { + purple_xfer_request(xfer); + } + } else { + purple_xfer_request(xfer); + } +#else + thumbnail = NULL; /* Silence warning */ purple_xfer_request(xfer); +#endif } void diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/msn/msn.c --- a/libpurple/protocols/msn/msn.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/msn/msn.c Wed May 05 15:42:34 2010 +0900 @@ -2774,7 +2774,9 @@ msn_get_account_text_table, /* get_account_text_table */ NULL, /* initiate_media */ NULL, /* get_media_caps */ - NULL /* get_moods */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; static PurplePluginInfo info = diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/msn/slp.c --- a/libpurple/protocols/msn/slp.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/msn/slp.c Wed May 05 15:42:34 2010 +0900 @@ -422,6 +422,12 @@ xfer->data = slpcall; + if (header->type == 0 && bin_len >= sizeof(MsnFileContext)) { + purple_xfer_set_thumbnail(xfer, &header->preview, + bin_len - sizeof(MsnFileContext), + "image/png"); + } + purple_xfer_request(xfer); } g_free(header); diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/msn/slplink.c --- a/libpurple/protocols/msn/slplink.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/msn/slplink.c Wed May 05 15:42:34 2010 +0900 @@ -692,15 +692,19 @@ gen_context(PurpleXfer *xfer, const char *file_name, const char *file_path) { gsize size = 0; - MsnFileContext header; + MsnFileContext *header; gchar *u8 = NULL; gchar *ret; gunichar2 *uni = NULL; glong currentChar = 0; glong len = 0; + const char *preview; + gsize preview_len; size = purple_xfer_get_size(xfer); + purple_xfer_prepare_thumbnail(xfer, "png"); + if (!file_name) { gchar *basename = g_path_get_basename(file_path); u8 = purple_utf8_try_convert(basename); @@ -716,23 +720,33 @@ u8 = NULL; } - header.length = GUINT32_TO_LE(sizeof(MsnFileContext) - 1); - header.version = GUINT32_TO_LE(2); /* V.3 contains additional unnecessary data */ - header.file_size = GUINT64_TO_LE(size); - header.type = GUINT32_TO_LE(1); /* No file preview */ + preview = purple_xfer_get_thumbnail(xfer, &preview_len); + header = g_malloc(sizeof(MsnFileContext) + preview_len); + + header->length = GUINT32_TO_LE(sizeof(MsnFileContext) - 1); + header->version = GUINT32_TO_LE(2); /* V.3 contains additional unnecessary data */ + header->file_size = GUINT64_TO_LE(size); + if (preview) + header->type = GUINT32_TO_LE(0); + else + header->type = GUINT32_TO_LE(1); len = MIN(len, MAX_FILE_NAME_LEN); for (currentChar = 0; currentChar < len; currentChar++) { - header.file_name[currentChar] = GUINT16_TO_LE(uni[currentChar]); + header->file_name[currentChar] = GUINT16_TO_LE(uni[currentChar]); } - memset(&header.file_name[currentChar], 0x00, (MAX_FILE_NAME_LEN - currentChar) * 2); + memset(&header->file_name[currentChar], 0x00, (MAX_FILE_NAME_LEN - currentChar) * 2); - memset(&header.unknown1, 0, sizeof(header.unknown1)); - header.unknown2 = GUINT32_TO_LE(0xffffffff); - header.preview[0] = '\0'; + memset(&header->unknown1, 0, sizeof(header->unknown1)); + header->unknown2 = GUINT32_TO_LE(0xffffffff); + if (preview) { + memcpy(&header->preview, preview, preview_len); + } + header->preview[preview_len] = '\0'; g_free(uni); - ret = purple_base64_encode((const guchar *)&header, sizeof(MsnFileContext)); + ret = purple_base64_encode((const guchar *)header, sizeof(MsnFileContext) + preview_len); + g_free(header); return ret; } diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/mxit/mxit.c --- a/libpurple/protocols/mxit/mxit.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/mxit/mxit.c Wed May 05 15:42:34 2010 +0900 @@ -635,7 +635,9 @@ mxit_get_text_table, /* get_account_text_table */ NULL, /* initiate_media */ NULL, /* get_media_caps */ - NULL /* get_moods */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/myspace/myspace.c --- a/libpurple/protocols/myspace/myspace.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/myspace/myspace.c Wed May 05 15:42:34 2010 +0900 @@ -3094,7 +3094,9 @@ msim_get_account_text_table, /* get_account_text_table */ NULL, /* initiate_media */ NULL, /* get_media_caps */ - NULL /* get_moods */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; /** diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/novell/novell.c --- a/libpurple/protocols/novell/novell.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/novell/novell.c Wed May 05 15:42:34 2010 +0900 @@ -3530,7 +3530,9 @@ NULL, /* get_account_text_table */ NULL, /* initiate_media */ NULL, /* get_media_caps */ - NULL /* get_moods */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; static PurplePluginInfo info = { diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/null/nullprpl.c --- a/libpurple/protocols/null/nullprpl.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/null/nullprpl.c Wed May 05 15:42:34 2010 +0900 @@ -1120,6 +1120,8 @@ NULL, /* get_account_text_table */ NULL, /* initiate_media */ NULL, /* get_media_caps */ + NULL, /* set_public_alias */ + NULL, /* get_public_alias */ NULL /* get_moods */ }; diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/oscar/libaim.c --- a/libpurple/protocols/oscar/libaim.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/oscar/libaim.c Wed May 05 15:42:34 2010 +0900 @@ -97,7 +97,9 @@ NULL, /* get_account_text_table */ NULL, /* initiate_media */ NULL, /* get_media_caps */ - NULL /* get_moods */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; static PurplePluginInfo info = diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/oscar/libicq.c --- a/libpurple/protocols/oscar/libicq.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/oscar/libicq.c Wed May 05 15:42:34 2010 +0900 @@ -109,6 +109,8 @@ NULL, /* initiate_media */ NULL, /* can_do_media */ oscar_get_purple_moods, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; static PurplePluginInfo info = diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/oscar/oscar.c --- a/libpurple/protocols/oscar/oscar.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/oscar/oscar.c Wed May 05 15:42:34 2010 +0900 @@ -3567,7 +3567,7 @@ PurpleConnection *gc = od->gc; PurpleAccount *account = purple_connection_get_account(gc); PurpleNotifyUserInfo *user_info; - gchar *tmp = NULL, *info_utf8 = NULL; + gchar *tmp = NULL, *info_utf8 = NULL, *base_profile_url = NULL; va_list ap; aim_userinfo_t *userinfo; @@ -3620,8 +3620,9 @@ } purple_notify_user_info_add_section_break(user_info); - tmp = g_strdup_printf("%s", - purple_normalize(account, userinfo->bn), _("View web profile")); + base_profile_url = oscar_util_valid_name_icq(userinfo->bn) ? "http://www.icq.com/people" : "http://profiles.aim.com"; + tmp = g_strdup_printf("%s", + base_profile_url, purple_normalize(account, userinfo->bn), _("View web profile")); purple_notify_user_info_add_pair(user_info, NULL, tmp); g_free(tmp); diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/qq/qq.c --- a/libpurple/protocols/qq/qq.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/qq/qq.c Wed May 05 15:42:34 2010 +0900 @@ -1041,7 +1041,9 @@ NULL, /* get_account_text_table */ NULL, /* initiate_media */ NULL, /* get_media_caps */ - NULL /* get_moods */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; static PurplePluginInfo info = { diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/silc/silc.c --- a/libpurple/protocols/silc/silc.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/silc/silc.c Wed May 05 15:42:34 2010 +0900 @@ -2117,7 +2117,9 @@ NULL, /* get_account_text_table */ NULL, /* initiate_media */ NULL, /* get_media_caps */ - NULL /* get_moods */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; static PurplePluginInfo info = diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/silc10/silc.c --- a/libpurple/protocols/silc10/silc.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/silc10/silc.c Wed May 05 15:42:34 2010 +0900 @@ -1842,7 +1842,10 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ NULL, /* get_account_text_table */ NULL, /* initiate_media */ - NULL /* can_do_media */ + NULL, /* get_media_caps */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; static PurplePluginInfo info = diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/simple/simple.c --- a/libpurple/protocols/simple/simple.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/simple/simple.c Wed May 05 15:42:34 2010 +0900 @@ -2110,7 +2110,9 @@ NULL, /* get_account_text_table */ NULL, /* initiate_media */ NULL, /* get_media_caps */ - NULL /* get_moods */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/yahoo/libyahoo.c --- a/libpurple/protocols/yahoo/libyahoo.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/yahoo/libyahoo.c Wed May 05 15:42:34 2010 +0900 @@ -266,7 +266,9 @@ yahoo_get_account_text_table, /* get_account_text_table */ NULL, /* initiate_media */ NULL, /* get_media_caps */ - NULL /* get_moods */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; static PurplePluginInfo info = diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/yahoo/libyahoojp.c --- a/libpurple/protocols/yahoo/libyahoojp.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/yahoo/libyahoojp.c Wed May 05 15:42:34 2010 +0900 @@ -162,7 +162,9 @@ yahoojp_get_account_text_table, /* get_account_text_table */ NULL, /* initiate_media */ NULL, /* get_media_caps */ - NULL /* get_moods */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; static PurplePluginInfo info = diff -r 28dd2b7331fd -r 77aba27f64da libpurple/protocols/zephyr/zephyr.c --- a/libpurple/protocols/zephyr/zephyr.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/protocols/zephyr/zephyr.c Wed May 05 15:42:34 2010 +0900 @@ -2909,7 +2909,9 @@ NULL, /* get_account_text_table */ NULL, /* initate_media */ NULL, /* get_media_caps */ - NULL /* get_moods */ + NULL, /* get_moods */ + NULL, /* set_public_alias */ + NULL /* get_public_alias */ }; static PurplePluginInfo info = { diff -r 28dd2b7331fd -r 77aba27f64da libpurple/prpl.h --- a/libpurple/prpl.h Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/prpl.h Wed May 05 15:42:34 2010 +0900 @@ -52,6 +52,13 @@ typedef struct _PurpleBuddyIconSpec PurpleBuddyIconSpec; /** + * A description of a file transfer thumbnail specification. + * This tells the UI if and what image formats the prpl support for file + * transfer thumbnails. + */ +typedef struct _PurpleThumbnailSpec PurpleThumbnailSpec; + +/** * This \#define exists just to make it easier to fill out the buddy icon * field in the prpl info struct for protocols that couldn't care less. */ @@ -573,8 +580,48 @@ /** * Returns an array of "PurpleMood"s, with the last one having * "mood" set to @c NULL. + * @since 2.7.0 */ PurpleMood *(*get_moods)(PurpleAccount *account); + + /** + * Set the user's "friendly name" (or alias or nickname or + * whatever term you want to call it) on the server. The + * protocol plugin should call success_cb or failure_cb + * *asynchronously* (if it knows immediately that the set will fail, + * call one of the callbacks from an idle/0-second timeout) depending + * on if the nickname is set successfully. + * + * @param gc The connection for which to set an alias + * @param alias The new server-side alias/nickname for this account, + * or NULL to unset the alias/nickname (or return it to + * a protocol-specific "default"). + * @param success_cb Callback to be called if the public alias is set + * @param failure_cb Callback to be called if setting the public alias + * fails + * @see purple_account_set_public_alias + * @since 2.7.0 + */ + void (*set_public_alias)(PurpleConnection *gc, const char *alias, + PurpleSetPublicAliasSuccessCallback success_cb, + PurpleSetPublicAliasFailureCallback failure_cb); + /** + * Retrieve the user's "friendly name" as set on the server. + * The protocol plugin should call success_cb or failure_cb + * *asynchronously* (even if it knows immediately that the set will fail, + * call one of the callbacks from an idle/0-second timeout) depending + * on if the nickname is retrieved. + * + * @param gc The connection for which to retireve the alias + * @param success_cb Callback to be called with the retrieved alias + * @param failure_cb Callback to be called if the prpl is unable to + * retrieve the alias + * @see purple_account_get_public_alias + * @since 2.7.0 + */ + void (*get_public_alias)(PurpleConnection *gc, + PurpleSetPublicAliasSuccessCallback success_cb, + PurpleSetPublicAliasFailureCallback failure_cb); }; #define PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl, member) \ diff -r 28dd2b7331fd -r 77aba27f64da libpurple/request.c --- a/libpurple/request.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/request.c Wed May 05 15:42:34 2010 +0900 @@ -1317,6 +1317,29 @@ } void * +purple_request_action_with_icon(void *handle, const char *title, + const char *primary, + const char *secondary, int default_action, + PurpleAccount *account, const char *who, + PurpleConversation *conv, gconstpointer icon_data, + gsize icon_size, void *user_data, size_t action_count, ...) +{ + void *ui_handle; + va_list args; + + g_return_val_if_fail(action_count > 0, NULL); + + va_start(args, action_count); + ui_handle = purple_request_action_with_icon_varg(handle, title, primary, + secondary, default_action, account, who, conv, icon_data, icon_size, + user_data, action_count, args); + va_end(args); + + return ui_handle; +} + + +void * purple_request_action_varg(void *handle, const char *title, const char *primary, const char *secondary, int default_action, @@ -1348,6 +1371,41 @@ } void * +purple_request_action_with_icon_varg(void *handle, const char *title, + const char *primary, const char *secondary, + int default_action, + PurpleAccount *account, const char *who, + PurpleConversation *conv, gconstpointer icon_data, + gsize icon_size, + void *user_data, size_t action_count, va_list actions) +{ + PurpleRequestUiOps *ops; + + g_return_val_if_fail(action_count > 0, NULL); + + ops = purple_request_get_ui_ops(); + + if (ops != NULL && ops->request_action_with_icon != NULL) { + PurpleRequestInfo *info; + + info = g_new0(PurpleRequestInfo, 1); + info->type = PURPLE_REQUEST_ACTION; + info->handle = handle; + info->ui_handle = ops->request_action_with_icon(title, primary, secondary, + default_action, account, who, conv, + icon_data, icon_size, + user_data, action_count, actions); + + handles = g_list_append(handles, info); + + return info->ui_handle; + } + + return NULL; +} + + +void * purple_request_fields(void *handle, const char *title, const char *primary, const char *secondary, PurpleRequestFields *fields, const char *ok_text, GCallback ok_cb, diff -r 28dd2b7331fd -r 77aba27f64da libpurple/request.h --- a/libpurple/request.h Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/request.h Wed May 05 15:42:34 2010 +0900 @@ -237,10 +237,18 @@ PurpleAccount *account, const char *who, PurpleConversation *conv, void *user_data); + /** @see purple_request_action_with_icon_varg(). */ + void *(*request_action_with_icon)(const char *title, const char *primary, + const char *secondary, int default_action, + PurpleAccount *account, const char *who, + PurpleConversation *conv, + gconstpointer icon_data, gsize icon_size, + void *user_data, + size_t action_count, va_list actions); + void (*_purple_reserved1)(void); void (*_purple_reserved2)(void); void (*_purple_reserved3)(void); - void (*_purple_reserved4)(void); } PurpleRequestUiOps; typedef void (*PurpleRequestInputCb)(void *, const char *); @@ -1393,6 +1401,29 @@ void *user_data, size_t action_count, va_list actions); /** + * Version of purple_request_action() supplying an image for the UI to + * optionally display as an icon in the dialog; see its documentation + * @since 2.7.0 + */ +void *purple_request_action_with_icon(void *handle, const char *title, + const char *primary, const char *secondary, int default_action, + PurpleAccount *account, const char *who, PurpleConversation *conv, + gconstpointer icon_data, gsize icon_size, void *user_data, + size_t action_count, ...); + +/** + * va_list version of purple_request_action_with_icon(); + * see its documentation. + * @since 2.7.0 + */ +void *purple_request_action_with_icon_varg(void *handle, const char *title, + const char *primary, const char *secondary, int default_action, + PurpleAccount *account, const char *who, PurpleConversation *conv, + gconstpointer icon_data, gsize icon_size, + void *user_data, size_t action_count, va_list actions); + + +/** * Displays groups of fields for the user to fill in. * * @param handle The plugin or connection handle. For some things this @@ -1477,6 +1508,19 @@ _("_Accept"), (accept_cb), _("_Cancel"), (cancel_cb)) /** + * A wrapper for purple_request_action_with_icon() that uses Accept and Cancel + * buttons. + */ +#define purple_request_accept_cancel_with_icon(handle, title, primary, secondary, \ + default_action, account, who, conv, \ + icon_data, icon_size, \ + user_data, accept_cb, cancel_cb) \ + purple_request_action_with_icon((handle), (title), (primary), (secondary), \ + (default_action), account, who, conv, icon_data, icon_size, \ + (user_data), 2, \ + _("_Accept"), (accept_cb), _("_Cancel"), (cancel_cb)) + +/** * Displays a file selector request dialog. Returns the selected filename to * the callback. Can be used for either opening a file or saving a file. * diff -r 28dd2b7331fd -r 77aba27f64da libpurple/tests/test_util.c --- a/libpurple/tests/test_util.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/tests/test_util.c Wed May 05 15:42:34 2010 +0900 @@ -121,6 +121,37 @@ } END_TEST +START_TEST(test_utf8_strip_unprintables) +{ + fail_unless(NULL == purple_utf8_strip_unprintables(NULL)); + /* invalid UTF-8 */ +#if 0 + /* disabled because make check fails on an assertion */ + fail_unless(NULL == purple_utf8_strip_unprintables("abc\x80\x7f")); +#endif + /* \t, \n, \r, space */ + assert_string_equal_free("ab \tcd\nef\r ", purple_utf8_strip_unprintables("ab \tcd\nef\r ")); + /* ASCII control characters (stripped) */ + assert_string_equal_free(" aaaa ", purple_utf8_strip_unprintables( + "\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0E\x0F\x10 aaaa " + "\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F")); + /* Basic ASCII */ + assert_string_equal_free("Foobar", purple_utf8_strip_unprintables("Foobar")); + /* 0xE000 - 0xFFFD (UTF-8 encoded) */ + /* U+F1F7 */ + assert_string_equal_free("aaaa\xef\x87\xb7", purple_utf8_strip_unprintables("aaaa\xef\x87\xb7")); +#if 0 + /* disabled because make check fails on an assertion */ + /* U+DB80 (Private Use High Surrogate, First) -- should be stripped */ + assert_string_equal_free("aaaa", purple_utf8_strip_unprintables("aaaa\xed\xa0\x80")); + /* U+FFFE (should be stripped) */ + assert_string_equal_free("aaaa", purple_utf8_strip_unprintables("aaaa\xef\xbf\xbe")); +#endif + /* U+FEFF (should not be stripped) */ + assert_string_equal_free("aaaa\xef\xbb\xbf", purple_utf8_strip_unprintables("aaaa\xef\xbb\xbf")); +} +END_TEST + START_TEST(test_mime_decode_field) { gchar *result = purple_mime_decode_field("=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?="); @@ -168,6 +199,10 @@ tcase_add_test(tc, test_markup_html_to_xhtml); suite_add_tcase(s, tc); + tc = tcase_create("Stripping Unparseables"); + tcase_add_test(tc, test_utf8_strip_unprintables); + suite_add_tcase(s, tc); + tc = tcase_create("MIME"); tcase_add_test(tc, test_mime_decode_field); suite_add_tcase(s, tc); diff -r 28dd2b7331fd -r 77aba27f64da libpurple/util.c --- a/libpurple/util.c Wed Apr 28 19:22:17 2010 +0900 +++ b/libpurple/util.c Wed May 05 15:42:34 2010 +0900 @@ -4636,12 +4636,22 @@ } workstr = iter = g_new(gchar, strlen(str) + 1); - for ( ; *str; ++str) { - guchar c = *str; - if (c >= 0x20 || c == '\t' || c == '\n' || c == '\r') { - *iter = c; - ++iter; + while (*str) { + gunichar ch = g_utf8_get_char(str); + gchar *next = g_utf8_next_char(str); + /* + * Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | + * [#x10000-#x10FFFF] + */ + if ((ch == '\t' || ch == '\n' || ch == '\r') || + (ch >= 0x20 && ch <= 0xD7FF) || + (ch >= 0xE000 && ch <= 0xFFFD) || + (ch >= 0x10000 && ch <= 0x10FFFF)) { + memcpy(iter, str, next - str); + iter += (next - str); } + + str = next; } /* nul-terminate the new string */ diff -r 28dd2b7331fd -r 77aba27f64da pidgin/gtkft.c --- a/pidgin/gtkft.c Wed Apr 28 19:22:17 2010 +0900 +++ b/pidgin/gtkft.c Wed May 05 15:42:34 2010 +0900 @@ -40,6 +40,9 @@ #define PIDGINXFER(xfer) \ (PidginXferUiData *)(xfer)->ui_data +/* the maximum size of files we will try to make a thumbnail for */ +#define PIDGIN_XFER_MAX_SIZE_IMAGE_THUMBNAIL 10 * 1024 * 1024 + struct _PidginXferDialog { gboolean keep_open; @@ -1157,6 +1160,67 @@ pidgin_xfer_dialog_cancel_xfer(xfer_dialog, xfer); } +static void +pidgin_xfer_add_thumbnail(PurpleXfer *xfer, const gchar *formats) +{ + purple_debug_info("ft", "creating thumbnail for transfer\n"); + + if (purple_xfer_get_size(xfer) <= PIDGIN_XFER_MAX_SIZE_IMAGE_THUMBNAIL) { + GdkPixbuf *thumbnail = + gdk_pixbuf_new_from_file_at_size( + purple_xfer_get_local_filename(xfer), 128, 128, NULL); + + if (thumbnail) { + gchar **formats_split = g_strsplit(formats, ",", 0); + gchar *buffer = NULL; + gsize size; + char *option_keys[2] = {NULL, NULL}; + char *option_values[2] = {NULL, NULL}; + int i; + gchar *format = NULL; + + for (i = 0; formats_split[i]; i++) { + if (purple_strequal(formats_split[i], "jpeg")) { + purple_debug_info("ft", "creating JPEG thumbnail\n"); + option_keys[0] = "quality"; + option_values[0] = "90"; + format = "jpeg"; + break; + } else if (purple_strequal(formats_split[i], "png")) { + purple_debug_info("ft", "creating PNG thumbnail\n"); + option_keys[0] = "compression"; + option_values[0] = "9"; + format = "png"; + break; + } + } + + /* Try the first format given by the PRPL without options */ + if (format == NULL) { + purple_debug_info("ft", + "creating thumbnail of format %s as demanded by PRPL\n", + formats_split[0]); + format = formats_split[0]; + } + + gdk_pixbuf_save_to_bufferv(thumbnail, &buffer, &size, format, + option_keys, option_values, NULL); + + if (buffer) { + gchar *mimetype = g_strdup_printf("image/%s", format); + purple_debug_info("ft", + "created thumbnail of %" G_GSIZE_FORMAT " bytes\n", + size); + purple_xfer_set_thumbnail(xfer, buffer, size, mimetype); + g_free(buffer); + g_free(mimetype); + } + g_object_unref(thumbnail); + g_strfreev(formats_split); + } + } +} + static PurpleXferUiOps ops = { pidgin_xfer_new_xfer, @@ -1168,7 +1232,7 @@ NULL, NULL, NULL, - NULL + pidgin_xfer_add_thumbnail }; /************************************************************************** diff -r 28dd2b7331fd -r 77aba27f64da pidgin/gtkrequest.c --- a/pidgin/gtkrequest.c Wed Apr 28 19:22:17 2010 +0900 +++ b/pidgin/gtkrequest.c Wed May 05 15:42:34 2010 +0900 @@ -26,6 +26,7 @@ #include "internal.h" #include "pidgin.h" +#include "debug.h" #include "prefs.h" #include "util.h" @@ -592,9 +593,11 @@ } static void * -pidgin_request_action(const char *title, const char *primary, +pidgin_request_action_with_icon(const char *title, const char *primary, const char *secondary, int default_action, - PurpleAccount *account, const char *who, PurpleConversation *conv, + PurpleAccount *account, const char *who, + PurpleConversation *conv, gconstpointer icon_data, + gsize icon_size, void *user_data, size_t action_count, va_list actions) { PidginRequestData *data; @@ -602,7 +605,7 @@ GtkWidget *vbox; GtkWidget *hbox; GtkWidget *label; - GtkWidget *img; + GtkWidget *img = NULL; void **buttons; char *label_text; char *primary_esc, *secondary_esc; @@ -659,8 +662,42 @@ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); /* Dialog icon. */ - img = gtk_image_new_from_stock(PIDGIN_STOCK_DIALOG_QUESTION, + if (icon_data) { + GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); + GdkPixbuf *pixbuf = NULL; + if (gdk_pixbuf_loader_write(loader, icon_data, icon_size, NULL)) { + pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); + if (pixbuf) { + /* scale the image if it is too large */ + int width = gdk_pixbuf_get_width(pixbuf); + int height = gdk_pixbuf_get_height(pixbuf); + if (width > 128 || height > 128) { + int scaled_width = width > height ? 128 : (128 * width) / height; + int scaled_height = height > width ? 128 : (128 * height) / width; + GdkPixbuf *scaled = + gdk_pixbuf_scale_simple(pixbuf, scaled_width, scaled_height, + GDK_INTERP_BILINEAR); + + purple_debug_info("pidgin", + "dialog icon was too large, scale it down\n"); + if (scaled) { + g_object_unref(pixbuf); + pixbuf = scaled; + } + } + img = gtk_image_new_from_pixbuf(pixbuf); + } + } else { + purple_debug_info("pidgin", "failed to parse dialog icon\n"); + } + gdk_pixbuf_loader_close(loader, NULL); + g_object_unref(loader); + } + + if (!img) { + img = gtk_image_new_from_stock(PIDGIN_STOCK_DIALOG_QUESTION, gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_HUGE)); + } gtk_misc_set_alignment(GTK_MISC(img), 0, 0); gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0); @@ -712,6 +749,17 @@ return data; } +static void * +pidgin_request_action(const char *title, const char *primary, + const char *secondary, int default_action, + PurpleAccount *account, const char *who, PurpleConversation *conv, + void *user_data, size_t action_count, va_list actions) +{ + return pidgin_request_action_with_icon(title, primary, secondary, + default_action, account, who, conv, NULL, 0, user_data, action_count, + actions); +} + static void req_entry_field_changed_cb(GtkWidget *entry, PurpleRequestField *field) { @@ -1699,7 +1747,7 @@ pidgin_request_file, pidgin_close_request, pidgin_request_folder, - NULL, + pidgin_request_action_with_icon, NULL, NULL, NULL diff -r 28dd2b7331fd -r 77aba27f64da po/ca.po --- a/po/ca.po Wed Apr 28 19:22:17 2010 +0900 +++ b/po/ca.po Wed May 05 15:42:34 2010 +0900 @@ -33,8 +33,8 @@ msgstr "" "Project-Id-Version: Pidgin\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-04-26 18:32+0200\n" -"PO-Revision-Date: 2010-04-26 19:11+0200\n" +"POT-Creation-Date: 2010-05-04 22:47+0200\n" +"PO-Revision-Date: 2010-05-04 23:17+0200\n" "Last-Translator: Josep Puigdemont i Casamajó \n" "Language-Team: Catalan \n" "MIME-Version: 1.0\n" @@ -1681,6 +1681,12 @@ msgid "Set User Info" msgstr "Estableix les dades d'usuari" +msgid "This protocol does not support setting a public alias." +msgstr "Aquest protocol no permet establir un àlies pulic." + +msgid "This protocol does not support fetching the public alias." +msgstr "Aquest protocol no permet aconseguir l'àlies públic." + msgid "Unknown" msgstr "Desconegut" @@ -3827,15 +3833,6 @@ msgid "execute" msgstr "executa" -msgid "Server requires TLS/SSL, but no TLS/SSL support was found." -msgstr "" -"El servidor requereix TLS/SSL per entrar, però no s'ha trobat cap " -"implementació de TLS/SSL." - -msgid "You require encryption, but no TLS/SSL support was found." -msgstr "" -"Heu requerit que es xifri, però no s'ha trobat cap implementació de TLS/SSL." - msgid "Server requires plaintext authentication over an unencrypted stream" msgstr "El servidor requereix autenticació de text sobre un flux no xifrat" @@ -3873,6 +3870,43 @@ msgid "SASL error: %s" msgstr "Error SASL: %s" +msgid "Invalid Encoding" +msgstr "La condició no és vàlida" + +msgid "Unsupported Extension" +msgstr "Aquesta extensió no està implementada" + +# MitM: Man-in-the-middle... segons wiki: intermediari +msgid "" +"Unexpected response from the server. This may indicate a possible MITM " +"attack" +msgstr "" +"S'ha rebut una resposta inesperada del servidor. Això podria indicar un " +"possible atac informàtic \"man-in-the-middle\"" + +msgid "" +"The server does support channel binding, but did not appear to advertise " +"it. This indicates a likely MITM attack" +msgstr "" +"Aques servidor permet vincular canals, tot i que no ho havia anunciat. Això " +"podria ser indicatiu d'un atac informàtic \"man-in-the-middle\"" + +msgid "Server does not support channel binding" +msgstr "El servidor no permet vincular canals" + +msgid "Unsupported channel binding method" +msgstr "Aquest mètode de vinculació de canals no està implementat" + +msgid "User not found" +msgstr "No s'ha trobat l'usuari" + +msgid "Invalid Username Encoding" +msgstr "La codificació del nom d'usuari no és vàlida" + +# Mirar com es traduïa 'Constraint variables' +msgid "Resource Constraint" +msgstr "Restriccions del recurs" + # FIXME: canonicalize -> normalitzar (josep) msgid "Unable to canonicalize username" msgstr "No s'ha pogut normalitzar el nom d'usuari" @@ -4178,6 +4212,15 @@ msgid "Roles:" msgstr "Rols:" +msgid "Server requires TLS/SSL, but no TLS/SSL support was found." +msgstr "" +"El servidor requereix TLS/SSL per entrar, però no s'ha trobat cap " +"implementació de TLS/SSL." + +msgid "You require encryption, but no TLS/SSL support was found." +msgstr "" +"Heu requerit que es xifri, però no s'ha trobat cap implementació de TLS/SSL." + msgid "Ping timed out" msgstr "S'ha esgitat el temps d'espera (ping)" @@ -4322,10 +4365,10 @@ msgstr "Permet les botzines" msgid "Mood Name" -msgstr "" +msgstr "Nom de l'estat d'ànim" msgid "Mood Comment" -msgstr "" +msgstr "Comentari sobre l'estat d'ànim" #. primitive #. ID @@ -4504,10 +4547,6 @@ msgid "Remote Connection Failed" msgstr "Ha fallat la connexió remota" -# Mirar com es traduïa 'Constraint variables' -msgid "Resource Constraint" -msgstr "Restriccions del recurs" - msgid "Restricted XML" msgstr "XML restringit" @@ -4871,9 +4910,8 @@ msgid "Anxious" msgstr "Ansiós" -#, fuzzy msgid "Aroused" -msgstr "S'enviarà" +msgstr "" msgid "Ashamed" msgstr "Avergonyit" @@ -4899,17 +4937,14 @@ msgid "Confused" msgstr "Confós" -#, fuzzy msgid "Contemplative" -msgstr "Contacte" - -#, fuzzy +msgstr "Contemplatiu" + msgid "Contented" -msgstr "Connectat" - -#, fuzzy +msgstr "Acontentat" + msgid "Cranky" -msgstr "Empresa" +msgstr "" msgid "Crazy" msgstr "Boig" @@ -4920,9 +4955,8 @@ msgid "Curious" msgstr "Curiós" -#, fuzzy msgid "Dejected" -msgstr "Rebutjat" +msgstr "Enfonsat" msgid "Depressed" msgstr "Deprimit" @@ -4931,11 +4965,10 @@ msgstr "Decebut" msgid "Disgusted" -msgstr "" - -#, fuzzy +msgstr "Repugnat" + msgid "Dismayed" -msgstr "Inhabilitat" +msgstr "Descoratjat" msgid "Distracted" msgstr "Distret" @@ -4950,9 +4983,8 @@ msgid "Excited" msgstr "Excitat" -#, fuzzy msgid "Flirtatious" -msgstr "Gloriós" +msgstr "Amb ganes de flirtar" msgid "Frustrated" msgstr "Frustrat" @@ -4960,9 +4992,8 @@ msgid "Grateful" msgstr "Agraït" -#, fuzzy msgid "Grieving" -msgstr "S'està recuperant..." +msgstr "De dol" #. 3 msgid "Grumpy" @@ -4997,9 +5028,8 @@ msgid "Impressed" msgstr "Impressionat" -#, fuzzy msgid "In awe" -msgstr "Enamorat" +msgstr "" msgid "In love" msgstr "Enamorat" @@ -6660,9 +6690,6 @@ msgid "Incorrect password" msgstr "La contrasenya no és correcta" -msgid "User not found" -msgstr "No s'ha trobat l'usuari" - msgid "Account has been disabled" msgstr "S'ha inhabilitat el compte" @@ -6963,7 +6990,7 @@ msgstr "A l'oficina" msgid "Taking a bath" -msgstr "" +msgstr "Prenent un bany" msgid "Watching TV" msgstr "Mirant la tele" @@ -7871,9 +7898,8 @@ msgid "Edit Buddy Comment" msgstr "Edita el comentari sobre l'amic" -#, fuzzy msgid "Get X-Status Msg" -msgstr "Aconsegueix el missatge d'estat" +msgstr "Aconsegueix el missatge d'estat X" msgid "End Direct IM Session" msgstr "Finalitzar la sessió de MI directa" @@ -10785,6 +10811,10 @@ #. * #. * A wrapper for purple_request_action() that uses Accept and Cancel buttons. #. +#. * +#. * A wrapper for purple_request_action_with_icon() that uses Accept and Cancel +#. * buttons. +#. msgid "_Accept" msgstr "_Accepta" @@ -11865,15 +11895,14 @@ msgid "/Conversation/Se_nd File..." msgstr "/Conversa/Envia un _fitxer..." -#, fuzzy msgid "/Conversation/Get _Attention" -msgstr "/Conversa/Aconsegueix informació" +msgstr "/Conversa/Aconseg_ueix atenció" msgid "/Conversation/Add Buddy _Pounce..." -msgstr "/Conversa/Afegeix un a_vís per a l'amic..." +msgstr "/Conversa/Afe_geix un avís per a l'amic..." msgid "/Conversation/_Get Info" -msgstr "/Conversa/_Aconsegueix informació" +msgstr "/Conversa/Aconsegueix inf_ormació" msgid "/Conversation/In_vite..." msgstr "/Conversa/Con_vida..." @@ -11888,16 +11917,16 @@ msgstr "/Conversa/_Bloca..." msgid "/Conversation/_Unblock..." -msgstr "/Conversa/_Desbloca..." +msgstr "/Conversa/Desb_loca..." msgid "/Conversation/_Add..." msgstr "/Conversa/_Afegeix..." msgid "/Conversation/_Remove..." -msgstr "/Conversa/Sup_rimeix..." +msgstr "/Conversa/_Suprimeix..." msgid "/Conversation/Insert Lin_k..." -msgstr "/Conversa/Insereix un _enllaç..." +msgstr "/Conversa/Insereix _un enllaç..." msgid "/Conversation/Insert Imag_e..." msgstr "/Conversa/Insereix una _imatge..." @@ -11950,9 +11979,8 @@ msgid "/Conversation/Send File..." msgstr "/Conversa/Envia un fitxer..." -#, fuzzy msgid "/Conversation/Get Attention" -msgstr "/Conversa/Aconsegueix informació" +msgstr "/Conversa/Aconsegueix atenció" msgid "/Conversation/Add Buddy Pounce..." msgstr "/Conversa/Afegeix avís per a l'amic..." @@ -12930,9 +12958,8 @@ msgid "Insert Smiley" msgstr "Insereix una emoticona" -#, fuzzy msgid "Send Attention" -msgstr "Alerta!" +msgstr "Envia atenció" msgid "_Bold" msgstr "_Negreta" @@ -12980,9 +13007,8 @@ msgid "_Smile!" msgstr "_Somrieu!" -#, fuzzy msgid "_Attention!" -msgstr "Alerta!" +msgstr "_Atenció!" msgid "Log Deletion Failed" msgstr "No s'ha pogut suprimir el registre" @@ -13936,9 +13962,8 @@ msgid "Custom Smiley Manager" msgstr "Gestor d'emoticones personalitzades" -#, fuzzy msgid "Attention received" -msgstr "Cal activació" +msgstr "S'ha rebut una alerta" msgid "Select Buddy Icon" msgstr "Seleccioneu una icona per a l'amic" @@ -16911,9 +16936,6 @@ #~ msgid "_Deny" #~ msgstr "_Denega" -#~ msgid "Invalid Username" -#~ msgstr "El nom d'usuari no és vàlid" - #~ msgid "Alias: %s
" #~ msgstr "Àlies: %s
" diff -r 28dd2b7331fd -r 77aba27f64da po/de.po --- a/po/de.po Wed Apr 28 19:22:17 2010 +0900 +++ b/po/de.po Wed May 05 15:42:34 2010 +0900 @@ -11,9 +11,9 @@ msgstr "" "Project-Id-Version: de\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-29 00:12-0700\n" -"PO-Revision-Date: 2010-02-11 21:02+0100\n" -"Last-Translator: Björn Voigt \n" +"POT-Creation-Date: 2010-05-04 19:40+0200\n" +"PO-Revision-Date: 2010-05-04 19:40+0200\n" +"Last-Translator: Jochen Kemnade \n" "Language-Team: Deutsch \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1360,8 +1360,6 @@ msgid "Saved Statuses" msgstr "Gespeicherter Status" -#. title -#. optional information msgid "Title" msgstr "Titel" @@ -1657,6 +1655,14 @@ msgid "Set User Info" msgstr "Benutzer-Info setzen" +msgid "This protocol does not support setting a public alias." +msgstr "" +"Dieses Protokoll unterstützt das Setzen eines öffentlichen Alias nicht." + +msgid "This protocol does not support fetching the public alias." +msgstr "" +"Dieses Protokoll unterstützt nicht das Abrufen von öffentlichen Aliasen." + msgid "Unknown" msgstr "Unbekannt" @@ -3811,15 +3817,6 @@ msgid "execute" msgstr "Ausführen" -msgid "Server requires TLS/SSL, but no TLS/SSL support was found." -msgstr "" -"Der Server benötigt TLS/SSL, es wurde aber kein TLS/SSL-Support gefunden." - -msgid "You require encryption, but no TLS/SSL support was found." -msgstr "" -"Sie fordern Verschlüsselung, aber es wurde keine TLS/SSL-Unterstützung " -"gefunden." - msgid "Server requires plaintext authentication over an unencrypted stream" msgstr "" "Der Server erfordert eine Klartext-Authentifizierung über einen " @@ -3863,6 +3860,41 @@ msgid "SASL error: %s" msgstr "SASL-Fehler: %s" +msgid "Invalid Encoding" +msgstr "Ungültige Kodierung" + +msgid "Unsupported Extension" +msgstr "Nicht-unterstützte Erweiterung" + +msgid "" +"Unexpected response from the server. This may indicate a possible MITM " +"attack" +msgstr "" +"Unerwartete Antwort vom Server. Das kann auf eine mögliche MITM-Attacke " +"hindeuten" + +msgid "" +"The server does support channel binding, but did not appear to advertise " +"it. This indicates a likely MITM attack" +msgstr "" +"Der Server unterstützt Kanalbindung, aber er macht das nicht bekannt. Das " +"deuted auf eine wahrscheinliche MITM-Attacke hin" + +msgid "Server does not support channel binding" +msgstr "Server unterstützt keine Kanalbindung" + +msgid "Unsupported channel binding method" +msgstr "Nicht-unterstützte Kanalbindungsmethode" + +msgid "User not found" +msgstr "Benutzer nicht gefunden" + +msgid "Invalid Username Encoding" +msgstr "Ungültig Kodierung des Benutzernamens" + +msgid "Resource Constraint" +msgstr "Ressourcen-Einschränkung" + msgid "Unable to canonicalize username" msgstr "Benutzername konnte nicht in Normalform gebracht werden" @@ -3940,6 +3972,11 @@ msgid "Organization Unit" msgstr "Organisationseinheit" +#. title +#. optional information +msgid "Job Title" +msgstr "Beruf" + msgid "Role" msgstr "Funktion" @@ -4163,12 +4200,24 @@ msgid "Roles:" msgstr "Rollen:" +msgid "Server requires TLS/SSL, but no TLS/SSL support was found." +msgstr "" +"Der Server benötigt TLS/SSL, es wurde aber kein TLS/SSL-Support gefunden." + +msgid "You require encryption, but no TLS/SSL support was found." +msgstr "" +"Sie fordern Verschlüsselung, aber es wurde keine TLS/SSL-Unterstützung " +"gefunden." + msgid "Ping timed out" msgstr "Ping-Zeitüberschreitung" msgid "Invalid XMPP ID" msgstr "Ungültige XMPP-ID" +msgid "Invalid XMPP ID. Username portion must be set." +msgstr "Falsche XMPP-ID. Der Benutzername muss gesetzt werden." + msgid "Invalid XMPP ID. Domain must be set." msgstr "Falsche XMPP-ID. Die Domain muss gesetzt werden." @@ -4305,14 +4354,18 @@ msgid "Allow Buzz" msgstr "Anklopfen erlauben" -#, fuzzy msgid "Mood Name" -msgstr "Zweiter Name" - -#, fuzzy +msgstr "Name der Stimmung" + msgid "Mood Comment" -msgstr "Buddy-Kommentar" - +msgstr "Stimmungskommentar" + +#. primitive +#. ID +#. name - use default +#. saveable +#. should be user_settable some day +#. independent msgid "Tune Artist" msgstr "Künstler anpassen" @@ -4483,9 +4536,6 @@ msgid "Remote Connection Failed" msgstr "Entfernte Verbindung fehlgeschlagen" -msgid "Resource Constraint" -msgstr "Eingeschränkte Ressourcen" - msgid "Restricted XML" msgstr "Eingeschränktes XML" @@ -4603,9 +4653,8 @@ msgid "Initiate Media" msgstr "Initiiere Medien" -#, fuzzy msgid "Account does not support PEP, can't set mood" -msgstr "Dieses Protokoll unterstützt keine Chaträume." +msgstr "Konto unterstützt kein PEP, kann die Stimmung nicht setzen" msgid "config: Configure a chat room." msgstr "config: Konfiguriere einen Chatraum." @@ -4663,9 +4712,8 @@ msgid "buzz: Buzz a user to get their attention" msgstr "buzz: Einen Kontakt anrufen, um seine Aufmerksamkeit zu erhalten" -#, fuzzy msgid "mood: Set current user mood" -msgstr "Wählen Sie den richtigen Benutzer" +msgstr "mood: Setze die aktuelle Benutzerstimmung" msgid "Extended Away" msgstr "Abwesend (erweitert)" @@ -4749,13 +4797,13 @@ "werden." msgid "XMPP stream header missing" -msgstr "" +msgstr "Der XMPP-Datenstromkopf fehlt" msgid "XMPP Version Mismatch" -msgstr "" +msgstr "XMPP-Versionskonflikt" msgid "XMPP stream missing ID" -msgstr "" +msgstr "Fehlende ID im XMPP-Datenstrom" msgid "XML Parse error" msgstr "Fehler beim Einlesen von XML-Daten" @@ -4834,32 +4882,27 @@ msgstr "" "Bitte wählen Sie die Ressource von %s, an die Sie eine Datei schicken möchten" -#, fuzzy msgid "Afraid" -msgstr "Arabisch" - -#, fuzzy +msgstr "Ängstlich" + msgid "Amazed" -msgstr "Beschämt" - -#, fuzzy +msgstr "Verblüfft" + msgid "Amorous" -msgstr "Glorreich" +msgstr "Sinnlich" #. 1 msgid "Angry" msgstr "Verärgert" -#, fuzzy msgid "Annoyed" -msgstr "Verbannt" +msgstr "Verärgert" msgid "Anxious" msgstr "Besorgt" -#, fuzzy msgid "Aroused" -msgstr "Sie senden" +msgstr "Aufgerüttelt" msgid "Ashamed" msgstr "Beschämt" @@ -4867,243 +4910,201 @@ msgid "Bored" msgstr "Gelangweilt" -#, fuzzy msgid "Brave" -msgstr "Speichern" - -#, fuzzy +msgstr "Tapfer" + msgid "Calm" -msgstr "Realm" - -#, fuzzy +msgstr "Beruhigt" + msgid "Cautious" -msgstr "Chats" - -#, fuzzy +msgstr "Zurückhaltend" + msgid "Cold" -msgstr "Fett" - -#, fuzzy +msgstr "Unterkühlt" + msgid "Confident" -msgstr "Konflikt" - -#, fuzzy +msgstr "Zuversichtlich" + msgid "Confused" -msgstr "Fortfahren" - -#, fuzzy +msgstr "Verwirrt" + msgid "Contemplative" -msgstr "Kontakt" - -#, fuzzy +msgstr "Nachdenklich" + msgid "Contented" -msgstr "Verbunden" - -#, fuzzy +msgstr "Zufrieden" + msgid "Cranky" -msgstr "Firma" +msgstr "Schrullig" msgid "Crazy" -msgstr "" - -#, fuzzy +msgstr "Verrückt" + msgid "Creative" -msgstr "Erzeugen" - -#, fuzzy +msgstr "Kreativ" + msgid "Curious" -msgstr "Glorreich" - -#, fuzzy +msgstr "Neugierig" + msgid "Dejected" -msgstr "Abgelehnt" - -#, fuzzy +msgstr "Niedergeschlagen" + msgid "Depressed" -msgstr "Gelöscht" - -#, fuzzy +msgstr "Deprimiert" + msgid "Disappointed" -msgstr "Verbindung unterbrochen." +msgstr "Enttäuscht" msgid "Disgusted" -msgstr "" - -#, fuzzy +msgstr "Empört" + msgid "Dismayed" -msgstr "Deaktiviert" - -#, fuzzy +msgstr "Bestürzt" + msgid "Distracted" -msgstr "Unbeteiligt" +msgstr "Abgelenkt" msgid "Embarrassed" -msgstr "" - -#, fuzzy +msgstr "Verlegen" + msgid "Envious" -msgstr "Besorgt" +msgstr "Neidisch" #. 2 msgid "Excited" msgstr "Aufgeregt" -#, fuzzy msgid "Flirtatious" -msgstr "Glorreich" +msgstr "Verführerisch" # old strings -#, fuzzy msgid "Frustrated" -msgstr "Vorname" +msgstr "Frustriert" msgid "Grateful" -msgstr "" - -#, fuzzy +msgstr "Dankbar" + msgid "Grieving" -msgstr "Empfange..." +msgstr "Trauernd" #. 3 msgid "Grumpy" -msgstr "Mürrisch" - -#, fuzzy +msgstr "Brummig" + msgid "Guilty" -msgstr "Stadt" +msgstr "Schuldig" #. 4 msgid "Happy" msgstr "Glücklich" msgid "Hopeful" -msgstr "" +msgstr "Hoffnungsvoll" #. 8 msgid "Hot" msgstr "Heiß" msgid "Humbled" -msgstr "" +msgstr "Gedemütigt" msgid "Humiliated" -msgstr "" - -#, fuzzy +msgstr "Erniedrigt" + msgid "Hungry" -msgstr "Verärgert" - -#, fuzzy +msgstr "Hungrig" + msgid "Hurt" -msgstr "Humor" +msgstr "Verletzt" msgid "Impressed" -msgstr "" - -#, fuzzy +msgstr "Beeindruckt" + msgid "In awe" -msgstr "Verliebt" +msgstr "Ehrfurchtsvoll" msgid "In love" msgstr "Verliebt" -#, fuzzy msgid "Indignant" -msgstr "Indonesisch" - -#, fuzzy +msgstr "Entrüstet" + msgid "Interested" -msgstr "Interessen" - -#, fuzzy +msgstr "Interessiert" + msgid "Intoxicated" -msgstr "Eingeladen" +msgstr "Betrunken" #. 6 msgid "Invincible" -msgstr "Unerschütterlich" +msgstr "Unbesiegbar" msgid "Jealous" msgstr "Eifersüchtig" -#, fuzzy msgid "Lonely" -msgstr "Affe" - -#, fuzzy +msgstr "Einsam" + msgid "Lost" -msgstr "Am lautesten" +msgstr "Verloren" msgid "Lucky" -msgstr "" - -#, fuzzy +msgstr "Glücklich" + msgid "Mean" -msgstr "Deutsch" - -#, fuzzy +msgstr "Gemein" + msgid "Moody" -msgstr "Stimmung" +msgstr "Launisch" msgid "Nervous" -msgstr "" - -#, fuzzy +msgstr "Reizbar" + msgid "Neutral" -msgstr "Detail" - -#, fuzzy +msgstr "Gleichgültig" + msgid "Offended" -msgstr "Offline" +msgstr "Beleidigt" msgid "Outraged" -msgstr "" - -#, fuzzy +msgstr "Schockiert" + msgid "Playful" -msgstr "Abspielen" - -#, fuzzy +msgstr "Verspielt" + msgid "Proud" -msgstr "Laut" - -#, fuzzy +msgstr "Stolz" + msgid "Relaxed" -msgstr "Echter Name" - -#, fuzzy +msgstr "Entspannt" + msgid "Relieved" -msgstr "Empfangen" - -#, fuzzy +msgstr "Erleichtert" + msgid "Remorseful" -msgstr "Entfernen" - -#, fuzzy +msgstr "Reumütig" + msgid "Restless" -msgstr "Registrieren" +msgstr "Ruhelos" #. 7 msgid "Sad" msgstr "Traurig" -#, fuzzy msgid "Sarcastic" -msgstr "Marathi" +msgstr "Sarkastisch" msgid "Satisfied" -msgstr "" - -#, fuzzy +msgstr "Befriedigt" + msgid "Serious" -msgstr "Glorreich" - -#, fuzzy +msgstr "Ernsthaft" + msgid "Shocked" -msgstr "Blockiert" +msgstr "Schockiert" msgid "Shy" -msgstr "" +msgstr "Schüchtern" #. 9 msgid "Sick" @@ -5115,40 +5116,34 @@ msgstr "Müde" msgid "Spontaneous" -msgstr "" - -#, fuzzy +msgstr "Spontan" + msgid "Stressed" -msgstr "Geschwindigkeit" - -#, fuzzy +msgstr "Gestresst" + msgid "Strong" -msgstr "Lied" +msgstr "Stark" msgid "Surprised" -msgstr "" +msgstr "Überrascht" msgid "Thankful" -msgstr "" +msgstr "Dankbar" msgid "Thirsty" -msgstr "" - -#, fuzzy +msgstr "Durstig" + msgid "Tired" -msgstr "Fire" - -#, fuzzy +msgstr "Müde" + msgid "Undefined" -msgstr "Unterstrichen" - -#, fuzzy +msgstr "Unbekannt" + msgid "Weak" -msgstr "Schlag" - -#, fuzzy +msgstr "Schwach" + msgid "Worried" -msgstr "Gelangweilt" +msgstr "Besorgt" msgid "Set User Nickname" msgstr "Setze Benutzer-Spitzname" @@ -5516,18 +5511,6 @@ msgid "Out to Lunch" msgstr "Zur Mittagspause" -#. primitive -#. ID -#. name - use default -#. saveable -#. should be user_settable some day -#. independent -msgid "Artist" -msgstr "Interpret" - -msgid "Album" -msgstr "Album" - msgid "Game Title" msgstr "Spieltitel" @@ -5677,9 +5660,6 @@ msgid "Work" msgstr "Geschäftlich" -msgid "Job Title" -msgstr "Beruf" - msgid "Company" msgstr "Firma" @@ -6719,9 +6699,6 @@ msgid "Incorrect password" msgstr "Falsches Passwort" -msgid "User not found" -msgstr "Benutzer nicht gefunden" - msgid "Account has been disabled" msgstr "Konto wurde deaktiviert" @@ -6988,6 +6965,10 @@ msgid "AOL does not allow your screen name to authenticate here" msgstr "AOL erlaubt Ihnen nicht, sich hier mit Ihrem Benutzernamen anzumelden" +#, c-format +msgid "Error requesting %s" +msgstr "Fehler beim Anfordern von %s" + msgid "Could not join chat room" msgstr "Konnte Chatraum nicht betreten" @@ -6995,104 +6976,88 @@ msgstr "Ungültiger Chatraumname" msgid "Thinking" -msgstr "" - -#, fuzzy +msgstr "Denkt nach" + msgid "Shopping" -msgstr "aufhört zu tippen" - -#, fuzzy +msgstr "Kauft ein" + msgid "Questioning" -msgstr "Frage-Dialog" - -#, fuzzy +msgstr "Fragt etwas" + msgid "Eating" -msgstr "Funkruf" - -#, fuzzy +msgstr "Beim Essen" + msgid "Watching a movie" -msgstr "Spielt ein Spiel" +msgstr "Schaut einen Film an" msgid "Typing" msgstr "Tippt gerade" -#, fuzzy msgid "At the office" -msgstr "Nicht im Büro" +msgstr "Im Büro" msgid "Taking a bath" -msgstr "" +msgstr "Nimmt ein Bad" msgid "Watching TV" -msgstr "" - -#, fuzzy +msgstr "Schaut Fernsehen" + msgid "Having fun" -msgstr "Auflegen" - -#, fuzzy +msgstr "Hat Spaß" + msgid "Sleeping" -msgstr "Müde" +msgstr "Schläft" msgid "Using a PDA" -msgstr "" - -#, fuzzy +msgstr "Benutzt einen PDA" + msgid "Meeting friends" -msgstr "IM-Freunde" - -#, fuzzy +msgstr "Freunde treffen" + msgid "On the phone" msgstr "Am Telefon" -#, fuzzy msgid "Surfing" -msgstr "Wiederkehrend" +msgstr "Surft (im Internet)" #. "I am mobile." / "John is mobile." msgid "Mobile" -msgstr "Mobil" +msgstr "Ist mobil" msgid "Searching the web" -msgstr "" +msgstr "Sucht etwas im Web" msgid "At a party" -msgstr "" +msgstr "Auf einer Party" msgid "Having Coffee" -msgstr "" +msgstr "Trinkt Kaffee" #. Playing video games -#, fuzzy msgid "Gaming" -msgstr "Zwillinge" +msgstr "Spielt am PC" msgid "Browsing the web" -msgstr "" - -#, fuzzy +msgstr "Surft im Web" + msgid "Smoking" -msgstr "Lied" - -#, fuzzy +msgstr "Raucht" + msgid "Writing" -msgstr "Arbeitet" +msgstr "Schreibt" #. Drinking [Alcohol] -#, fuzzy msgid "Drinking" -msgstr "Arbeitet" +msgstr "Trinkt" msgid "Listening to music" msgstr "Musik hören" -#, fuzzy msgid "Studying" -msgstr "Sende" - -#, fuzzy +msgstr "Studiert" + msgid "In the restroom" -msgstr "Interessen" +msgstr "Auf der Toilette" msgid "Received invalid data on connection with server" msgstr "Ungültige Daten in der Verbindung mit dem Server empfangen" @@ -7311,7 +7276,7 @@ msgstr "Spiele" msgid "ICQ Xtraz" -msgstr "" +msgstr "ICQ Xtraz" msgid "Add-Ins" msgstr "Zusätze" @@ -7379,23 +7344,18 @@ msgid "Invisible" msgstr "Unsichtbar" -#, fuzzy msgid "Evil" -msgstr "E-Mail" - -#, fuzzy +msgstr "Böse" + msgid "Depression" -msgstr "Beruf" - -#, fuzzy +msgstr "Depression" + msgid "At home" -msgstr "Über mich" - -#, fuzzy +msgstr "Zu Hause" + msgid "At work" -msgstr "Netzwerk" - -#, fuzzy +msgstr "Bei der Arbeit" + msgid "At lunch" msgstr "Zur Mittagspause" @@ -7936,9 +7896,8 @@ msgid "iTunes Music Store Link" msgstr "iTunes Music Store Link" -#, fuzzy msgid "Lunch" -msgstr "Finch" +msgstr "Mittagspause" #, c-format msgid "Buddy Comment for %s" @@ -7971,9 +7930,8 @@ msgid "Edit Buddy Comment" msgstr "Buddy-Kommentar bearbeiten" -#, fuzzy msgid "Get X-Status Msg" -msgstr "Abwesenheitsmitteilung abrufen" +msgstr "X-Status-Nachricht abrufen" msgid "End Direct IM Session" msgstr "Direkt-IM-Sitzung beenden" @@ -8384,6 +8342,10 @@ msgid "Admin" msgstr "Admin" +#. XXX: Should this be "Topic"? +msgid "Room Title" +msgstr "Raumtitel" + msgid "Notice" msgstr "Bemerkung" @@ -10311,9 +10273,6 @@ msgid "Yahoo! Protocol Plugin" msgstr "Yahoo!-Protokoll-Plugin" -msgid "Pager server" -msgstr "Pager-Server" - msgid "Pager port" msgstr "Pager-Port" @@ -10335,12 +10294,6 @@ msgid "Chat room list URL" msgstr "Chatraumliste (URL)" -msgid "Yahoo Chat server" -msgstr "Yahoo-Chat-Server" - -msgid "Yahoo Chat port" -msgstr "Yahoo-Chat-Port" - msgid "Yahoo JAPAN ID..." msgstr "Yahoo-JAPAN-ID..." @@ -10409,6 +10362,15 @@ "Konto gesperrt: Unbekannter Grund. Eventuell können Sie dies beheben, wenn " "Sie sich auf der Yahoo!-Webseite anmelden." +#. indicates a lock due to logging in too frequently +msgid "" +"Account locked: You have been logging in too frequently. Wait a few minutes " +"before trying to connect again. Logging into the Yahoo! website may help." +msgstr "" +"Konto gesperrt: Zu viele fehlgeschlagene Login-Versuche. Warten Sie einige " +"Minuten bevor Sie erneut versuchen sich zu verbinden. Eventuell können Sie " +"dies beheben, wenn Sie sich auf der Yahoo!-Webseite anmelden." + #. username or password missing msgid "Username or password missing" msgstr "Benutzername oder Passwort fehlt" @@ -10489,6 +10451,16 @@ msgid "Unable to establish a connection with %s: %s" msgstr "Die Verbindung mit %s konnte nicht hergestellt werden: %s" +msgid "Unable to connect: The server returned an empty response." +msgstr "Verbindung fehlgeschlagen: Der Server lieferte eine leere Antwort." + +msgid "" +"Unable to connect: The server's response did not contain the necessary " +"information" +msgstr "" +"Verbindung fehlgeschlagen: Die Antwort des Servers enthielt die nötigen " +"Informationen nicht" + msgid "Not at Home" msgstr "Nicht zu Hause" @@ -10879,6 +10851,10 @@ #. * #. * A wrapper for purple_request_action() that uses Accept and Cancel buttons. #. +#. * +#. * A wrapper for purple_request_action_with_icon() that uses Accept and Cancel +#. * buttons. +#. msgid "_Accept" msgstr "_Akzeptieren" @@ -10945,9 +10921,8 @@ msgid "Extended away" msgstr "Länger abwesend" -#, fuzzy msgid "Feeling" -msgstr "Empfange" +msgstr "Befinden" #, c-format msgid "%s (%s) changed status from %s to %s" @@ -11120,12 +11095,6 @@ msgid "Pidgin Internet Messenger" msgstr "Pidgin Internet-Sofortnachrichtendienst" -msgid "Orientation" -msgstr "Ausrichtung" - -msgid "The orientation of the tray." -msgstr "Die Ausrichtung der Kontrollleiste." - #. Build the login options frame. msgid "Login Options" msgstr "Anmeldeoptionen" @@ -11499,13 +11468,11 @@ msgid "Unknown node type" msgstr "Unbekannter Knotentyp" -#, fuzzy msgid "Please select your mood from the list" -msgstr "Bitte setzen Sie eine Stimmung aus der Liste." - -#, fuzzy +msgstr "Bitte wählen Sie Ihre Stimmung aus der Liste" + msgid "Message (optional)" -msgstr "Alias (optional)" +msgstr "Nachricht (optional)" msgid "Edit User Mood" msgstr "Benutzerstimmung ändern" @@ -11588,9 +11555,8 @@ msgid "/Tools/Pr_ivacy" msgstr "/Werkzeuge/Pri_vatsphäre" -#, fuzzy msgid "/Tools/Set _Mood" -msgstr "/Werkzeuge/_System-Mitschnitt" +msgstr "/Werkzeuge/Setze _Stimmung" msgid "/Tools/_File Transfers" msgstr "/Werkzeuge/_Dateiübertragungen" @@ -11611,20 +11577,17 @@ msgid "/Help/Online _Help" msgstr "/Hilfe/Online-_Hilfe" -#, fuzzy msgid "/Help/_Build Information" -msgstr "Buddy-Information" +msgstr "/Hilfe/_Build-Informationen" msgid "/Help/_Debug Window" msgstr "/Hilfe/_Debug-Fenster" -#, fuzzy msgid "/Help/De_veloper Information" -msgstr "Serverinformation" - -#, fuzzy +msgstr "/Hilfe/_Entwickler-Informationen" + msgid "/Help/_Translator Information" -msgstr "Persönliche Informationen" +msgstr "/Hilfe/Ü_bersetzer-Informationen" msgid "/Help/_About" msgstr "/Hilfe/Ü_ber" @@ -11855,9 +11818,8 @@ msgid "_Edit Account" msgstr "Konto _bearbeiten" -#, fuzzy msgid "Set _Mood..." -msgstr "Setze Stimmung..." +msgstr "Setze _Stimmung..." msgid "No actions available" msgstr "Keine Aktionen verfügbar" @@ -11979,9 +11941,8 @@ msgid "/Conversation/Se_nd File..." msgstr "/Unterhaltung/Datei _senden..." -#, fuzzy msgid "/Conversation/Get _Attention" -msgstr "/Unterhaltung/Info abrufen" +msgstr "/Unterhaltung/_Aufmerksamkeit erregen" msgid "/Conversation/Add Buddy _Pounce..." msgstr "/Unterhaltung/_Buddy-Alarm hinzufügen..." @@ -12064,9 +12025,8 @@ msgid "/Conversation/Send File..." msgstr "/Unterhaltung/Datei senden ..." -#, fuzzy msgid "/Conversation/Get Attention" -msgstr "/Unterhaltung/Info abrufen" +msgstr "/Unterhaltung/Aufmerksamkeit erregen" msgid "/Conversation/Add Buddy Pounce..." msgstr "/Unterhaltung/Buddy-Alarm hinzufügen..." @@ -12132,13 +12092,11 @@ msgid "0 people in room" msgstr "0 Personen im Raum" -#, fuzzy msgid "Close Find bar" -msgstr "Diesen Reiter schließen" - -#, fuzzy +msgstr "Suchleiste schließen" + msgid "Find:" -msgstr "Suchen" +msgstr "Suchen:" #, c-format msgid "%d person in room" @@ -12311,6 +12269,9 @@ msgid "Bengali" msgstr "Bengalisch" +msgid "Bengali-India" +msgstr "Bengalisch" + msgid "Bosnian" msgstr "Bosnisch" @@ -12533,7 +12494,7 @@ msgid "Lithuanian" msgstr "Litauisch" -#, fuzzy, c-format +#, c-format msgid "" "%s is a messaging client based on libpurple which is capable of connecting " "to multiple messaging services at once. %s is written in C using GTK+. %s " @@ -12542,15 +12503,14 @@ "copyrighted by its contributors, a list of whom is also distributed with %" "s. There is no warranty for %s.

" msgstr "" -"%s ist ein grafischer modularer Nachrichtendienst, basierend auf libpurple, " -"der AIM, MSN, Yahoo!, XMPP, ICQ, IRC, SILC, SIP/SIMPLE, Novell GroupWise, " -"Lotus Sametime, Bonjour, Zephyr, MySpaceIM, Gadu-Gadu und QQ gleichzeitig " -"unterstützt. Er wird mit GTK+ entwickelt.

Sie können das Programm " -"nach den Bedingungen der GPL (Version 2 oder später) modifizieren und " -"weitergeben. Eine Kopie der GPL ist in der Datei 'COPYING' enthalten, die " -"mit %s ausgeliefert wird. %s wird von seinen Mitwirkenden urheberrechtlich " -"geschützt. Die Datei 'COPYRIGHT' enthält die komplette Liste der " -"Mitwirkenden. Wir übernehmen keine Haftung für dieses Programm.

" +"%s ist ein Nachrichtendienst, basierend auf libpurple, der die Verbindung zu " +"mehreren Nachrichtendiensten gleichzeitig unterstützt. %s wird mit C und GTK" +"+ entwickelt. %s ist nach den Bedingungen der GPL (Version 2 oder später) " +"freigegeben und darf gemäß dieser bearbeitet und weiter verbreitet werden. " +"Eine Kopie der GPL wird mit %s ausgeliefert. %s wird von seinen " +"Mitwirkenden urheberrechtlich geschützt. Eine komplette Liste der " +"Mitwirkenden wird mit %s ausgeliefert. Wir übernehmen keine Haftung für %s." +"

" #, c-format msgid "" @@ -12559,8 +12519,12 @@ "Channel: #pidgin on irc.freenode.net
\tXMPP MUC: devel@conference.pidgin." "im

" msgstr "" - -#, fuzzy, c-format +"Hilfreiche Quellen
\tWebseite
\tHäufig gestellte Fragen (FAQ)
" +"\tIRC-Channel: #pidgin auf irc.freenode.net
\tXMPP-MUC: devel@conference." +"pidgin.im

" + +#, c-format msgid "" "Help from other Pidgin users is available by " "e-mailing support@pidgin.im
" msgstr "" -"Hilfe von anderen Pidgin-Benutzern: support@pidgin.im
Dies ist eine öffentliche Mailing-Liste! (Archiv)
Wir können nicht bei Problemen mit Drittanbieter-Protokollen oder " -"Plugins helfen!
Die Hauptsprache dieser Liste ist Englisch. Sie " -"können gern in einer anderen Sprache schreiben, aber die Antworten könnten " -"weniger hilfreich sein.
Deutschsprachige Benutzer können auch das Portal " -"
Pidgin-IM.de nutzen. Dort finden " -"Sie aktuelle Informationen zu Pidgin, können mit anderen Benutzern im Forum diskutieren und Hilfe zu " -"Problemen finden. Beachten Sie, dass dieses Portal unabhängig vom " -"offiziellen Pidgin-Projekt ist.

" +"Hilfe von anderen Pidgin-Benutzern erhält man " +"per E-Mail an support@pidgin.im
Dies ist eine öffentliche Mailing-Liste! (Archiv)
Wir können nicht bei Problemen mit " +"Drittanbieter-Protokollen oder Plugins helfen!
Die Hauptsprache dieser " +"Liste ist Englisch. Sie können gern in einer anderen Sprache " +"schreiben, aber die Antworten könnten weniger hilfreich sein.
Deutschsprachige Benutzer können auch das Portal Pidgin-IM.de nutzen. Dort finden Sie aktuelle " +"Informationen zu Pidgin, können mit anderen Benutzern im Forum diskutieren und Hilfe zu Problemen finden. " +"Beachten Sie, dass dieses Portal unabhängig vom offiziellen Pidgin-Projekt " +"ist.

" #, c-format msgid "About %s" msgstr "Über %s" -#, fuzzy msgid "Build Information" -msgstr "Buddy-Information" +msgstr "Build-Informationen" #. End of not to be translated section -#, fuzzy, c-format +#, c-format msgid "%s Build Information" -msgstr "Buddy-Information" +msgstr "%s-Build-Informationen" msgid "Current Developers" msgstr "Aktuelle Entwickler" @@ -12608,9 +12572,9 @@ msgid "Retired Crazy Patch Writers" msgstr "Zurückgetretene verrückte Patchschreiber" -#, fuzzy, c-format +#, c-format msgid "%s Developer Information" -msgstr "Serverinformation" +msgstr "%s-Entwickler-Informationen" msgid "Current Translators" msgstr "Aktuelle Übersetzer" @@ -12618,9 +12582,9 @@ msgid "Past Translators" msgstr "Frühere Übersetzer" -#, fuzzy, c-format +#, c-format msgid "%s Translator Information" -msgstr "Mehr Informationen" +msgstr "%s-Übersetzer-Informationen" msgid "_Name" msgstr "_Name" @@ -12871,7 +12835,7 @@ "Farbe, mit der der Name in einer empfangenen Nachricht dargestellt wird." msgid "\"Attention\" Name Color" -msgstr "Farbe des Absendernamens für „Achtung“-Nachrichten" +msgstr "Farbe des Absendernamens für „Aufmerksamkeits“-Nachrichten" msgid "Color to draw the name of a message you received containing your name." msgstr "" @@ -13042,9 +13006,8 @@ msgid "Insert Smiley" msgstr "Smiley einfügen" -#, fuzzy msgid "Send Attention" -msgstr "Senden-Knopf" +msgstr "Aufmerksamkeitsgesuch senden" msgid "_Bold" msgstr "_Fett" @@ -13092,7 +13055,7 @@ msgstr "_Lächeln!" msgid "_Attention!" -msgstr "" +msgstr "_Aufmerksamkeit!" msgid "Log Deletion Failed" msgstr "Löschen des Mitschnitts fehlgeschlagen" @@ -14040,9 +14003,8 @@ msgid "Custom Smiley Manager" msgstr "Verwaltung für benutzerdefinierte Smileys" -#, fuzzy msgid "Attention received" -msgstr "Aktivierung erforderlich" +msgstr "Aufmerksamkeitsgesuch erhalten" msgid "Select Buddy Icon" msgstr "Buddy-Icon auswählen" @@ -15189,8 +15151,17 @@ msgstr "Zeitstempelformat-Optionen" #, c-format -msgid "_Force 24-hour time format" -msgstr "_Erzwinge 24-Stunden Zeitformat" +msgid "_Force timestamp format:" +msgstr "_Erzwinge Zeitformat:" + +msgid "Use system default" +msgstr "System-Vorgabe verwenden" + +msgid "12 hour time format" +msgstr "12-Stunden-Zeitformat" + +msgid "24 hour time format" +msgstr "24-Stunden-Zeitformat" msgid "Show dates in..." msgstr "Zeige Datumsangaben in..." @@ -15391,11 +15362,31 @@ msgstr "Sendet und empfängt RAW-XMPP-Blöcke." #. * description -#, fuzzy msgid "This plugin is useful for debugging XMPP servers or clients." msgstr "" "Dieses Plugin ist nützlich zur Fehlersuche in XMPP-Servern oder -Clients." +#~ msgid "Artist" +#~ msgstr "Interpret" + +#~ msgid "Album" +#~ msgstr "Album" + +#~ msgid "Pager server" +#~ msgstr "Pager-Server" + +#~ msgid "Yahoo Chat server" +#~ msgstr "Yahoo-Chat-Server" + +#~ msgid "Yahoo Chat port" +#~ msgstr "Yahoo-Chat-Port" + +#~ msgid "Orientation" +#~ msgstr "Ausrichtung" + +#~ msgid "The orientation of the tray." +#~ msgstr "Die Ausrichtung der Kontrollleiste." + #~ msgid "Error creating conference." #~ msgstr "Fehler beim Erstellen der Konferenz."