# HG changeset patch # User Ka-Hing Cheung # Date 1204087777 0 # Node ID f61f7e8d897eb56d769fffcfad71633ad835e4b0 # Parent 00eaff9396ec3ef97e5af288935285079c8b82a7# Parent 382bc33e88249aba54bbc668e180dfa2a095fc5c propagate from branch 'im.pidgin.pidgin' (head 64e9bf80895d2671f0a42fecc17e3ba895b41426) to branch 'im.pidgin.pidgin.khc.msnp15' (head 21f516729b577a6ecb168d8ce480a466ede4c05d) diff -r 00eaff9396ec -r f61f7e8d897e COPYRIGHT --- a/COPYRIGHT Wed Feb 06 03:35:04 2008 +0000 +++ b/COPYRIGHT Wed Feb 27 04:49:37 2008 +0000 @@ -154,6 +154,7 @@ Konrad Gräfe Miah Gregory David Grohmann +Gideon N. Guillen Christian Hammond Erick Hamness Fred Hampton @@ -255,6 +256,7 @@ David Mohr Andrew Molloy Michael Monreal +Marco Monteiro Benjamin Moody John Moody Tim Mooney @@ -274,6 +276,7 @@ Ruediger Oertel Gudmundur Bjarni Olafsson Bartosz Oler +Oliver Stefan Ott Shawn Outman Nathan Owens (pianocomp81) diff -r 00eaff9396ec -r f61f7e8d897e ChangeLog --- a/ChangeLog Wed Feb 06 03:35:04 2008 +0000 +++ b/ChangeLog Wed Feb 27 04:49:37 2008 +0000 @@ -1,6 +1,6 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul -version 2.4.0 (??/??/????): +version 2.4.0 (??/??/2008): libpurple: * Fixed various problems with loss of status messages when going or returning from idle on MySpaceIM. @@ -10,12 +10,20 @@ * Partial support for viewing ICQ status notes (Collin from ComBOTS GmbH). * Support for /notice on IRC. - * Support for Yahoo Messenger 7.0+ file transfer method (Thanumalayan S.) + * Support for Yahoo! Messenger 7.0+ file transfer method (Thanumalayan S.) * Support for retrieving full names and addresses from the address book on Yahoo! Japan (Yusuke Odate) * The AIM/ICQ server-side preference for "allow others to see me as idle" is no longer unconditionally set to "yes" even when your libpurple preference is "no." + * Fix SSL certificate checks for renewed certificates + * Fix the ability to set vCard buddy icons on Google Talk/XMPP + * D-Bus fixes on 64bit + * Fixed retrieval of buddy icons and setting of server-side aliases on + Yahoo! and Yahoo! Japan when using an HTTP proxy server (Gideon N. + Guillen) + * Fixed an MSN bug that would leave you appearing offline when transferred + to different server Pidgin: * Added the ability to theme conversation name colors (red and blue) @@ -25,6 +33,7 @@ de Andrade) * Save the conversation "Enable Logging" option per-contact (Moos Heintzen) + * Typing notifications are now shown in the conversation area Finch: * Color is used in the buddylist to indicate status, and the conversation @@ -44,6 +53,7 @@ * Added a log viewer * Added the ability to block/unblock buddies - see the buddy context menu and the menu for the buddy list. + * Fixed a bug preventing finch working on x86_64 version 2.3.1 (12/7/2007): http://developer.pidgin.im/query?status=closed&milestone=2.3.1 diff -r 00eaff9396ec -r f61f7e8d897e ChangeLog.API --- a/ChangeLog.API Wed Feb 06 03:35:04 2008 +0000 +++ b/ChangeLog.API Wed Feb 27 04:49:37 2008 +0000 @@ -9,6 +9,7 @@ purple_micro_version variables are exported by version.h, giving the version of libpurple in use at runtime. * purple_util_set_current_song, purple_util_format_song_info + * purple_ip_address_is_valid * Some accessor functions to the Roomlist API: * purple_roomlist_get_fields * purple_roomlist_room_get_type @@ -43,6 +44,8 @@ * purple_connection_get_prpl * purple_xfer_get_start_time * purple_xfer_get_end_time + * purple_serv_got_private_alias for prpls to call after receiving a + private alias from the server. Pidgin: Added: diff -r 00eaff9396ec -r f61f7e8d897e doc/account-signals.dox --- a/doc/account-signals.dox Wed Feb 06 03:35:04 2008 +0000 +++ b/doc/account-signals.dox Wed Feb 27 04:49:37 2008 +0000 @@ -148,7 +148,8 @@ void (*account_error_changed)(PurpleAccount *account, const PurpleConnectionErrorInfo *old_error, const PurpleConnectionErrorInfo *current_error); @endsignalproto @signaldesc - Emitted when @a account's error changes. + Emitted when @a account's error changes. You should not call + purple_account_clear_current_error() while this signal is being emitted. @param account The account whose error has changed. @param old_error The account's previous error, or @c NULL if it had no error. After this signal is emitted, @a old_error is diff -r 00eaff9396ec -r f61f7e8d897e finch/gntblist.c --- a/finch/gntblist.c Wed Feb 06 03:35:04 2008 +0000 +++ b/finch/gntblist.c Wed Feb 27 04:49:37 2008 +0000 @@ -601,10 +601,10 @@ field = purple_request_field_string_new("screenname", _("Screen Name"), username, FALSE); purple_request_field_group_add_field(group, field); - field = purple_request_field_string_new("alias", _("Alias"), alias, FALSE); + field = purple_request_field_string_new("alias", _("Alias (optional)"), alias, FALSE); purple_request_field_group_add_field(group, field); - field = purple_request_field_string_new("group", _("Group"), grp, FALSE); + field = purple_request_field_string_new("group", _("Add in group"), grp, FALSE); purple_request_field_group_add_field(group, field); purple_request_field_set_type_hint(field, "group"); @@ -1408,7 +1408,6 @@ char *primary; const char *name, *sec = NULL; - /* XXX: could be a contact */ if (PURPLE_BLIST_NODE_IS_CONTACT(node)) { PurpleContact *c = (PurpleContact*)node; name = purple_contact_get_alias(c); @@ -2349,15 +2348,6 @@ return ret; } -static gboolean -blist_clicked(GntTree *tree, GntMouseEvent event, int x, int y, gpointer ggblist) -{ - if (event == GNT_RIGHT_MOUSE_DOWN) { - draw_context_menu(ggblist); - } - return FALSE; -} - static void plugin_action(GntMenuItem *item, gpointer data) { @@ -2940,7 +2930,6 @@ g_signal_connect(G_OBJECT(ggblist->tree), "key_pressed", G_CALLBACK(key_pressed), ggblist); g_signal_connect(G_OBJECT(ggblist->tree), "context-menu", G_CALLBACK(context_menu), ggblist); g_signal_connect(G_OBJECT(ggblist->tree), "collapse-toggled", G_CALLBACK(group_collapsed), NULL); - g_signal_connect_after(G_OBJECT(ggblist->tree), "clicked", G_CALLBACK(blist_clicked), ggblist); g_signal_connect(G_OBJECT(ggblist->tree), "activate", G_CALLBACK(selection_activate), ggblist); g_signal_connect_data(G_OBJECT(ggblist->tree), "gained-focus", G_CALLBACK(draw_tooltip), ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED); diff -r 00eaff9396ec -r f61f7e8d897e finch/gntconv.c --- a/finch/gntconv.c Wed Feb 06 03:35:04 2008 +0000 +++ b/finch/gntconv.c Wed Feb 27 04:49:37 2008 +0000 @@ -805,6 +805,10 @@ g_return_if_fail(ggconv != NULL); + if (flags & PURPLE_MESSAGE_SYSTEM) { + flags &= ~(PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV); + } + if (ggconv->active_conv != conv) { if (flags & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV)) finch_conversation_set_active(conv); @@ -837,7 +841,11 @@ if (purple_message_meify((char*)message, -1)) { name = g_strdup_printf("*** %s", who); - msgflags = gnt_color_pair(color_message_action); + if (!(flags & PURPLE_MESSAGE_SEND) && + (flags & PURPLE_MESSAGE_NICK)) + msgflags = gnt_color_pair(color_message_highlight); + else + msgflags = gnt_color_pair(color_message_action); me = TRUE; } else { name = g_strdup_printf("%s", who); diff -r 00eaff9396ec -r f61f7e8d897e finch/libgnt/gntbutton.c --- a/finch/libgnt/gntbutton.c Wed Feb 06 03:35:04 2008 +0000 +++ b/finch/libgnt/gntbutton.c Wed Feb 27 04:49:37 2008 +0000 @@ -79,7 +79,8 @@ static gboolean gnt_button_key_pressed(GntWidget *widget, const char *key) { - if (strcmp(key, GNT_KEY_ENTER) == 0) + if (strcmp(key, GNT_KEY_ENTER) == 0 || + strcmp(key, SAFE(cursor_down)) == 0) { gnt_widget_activate(widget); return TRUE; diff -r 00eaff9396ec -r f61f7e8d897e finch/libgnt/gntcombobox.c --- a/finch/libgnt/gntcombobox.c Wed Feb 06 03:35:04 2008 +0000 +++ b/finch/libgnt/gntcombobox.c Wed Feb 27 04:49:37 2008 +0000 @@ -155,6 +155,7 @@ { case '\r': case '\t': + case '\n': hide_popup(box, TRUE); return TRUE; case 27: diff -r 00eaff9396ec -r f61f7e8d897e finch/libgnt/gntentry.c --- a/finch/libgnt/gntentry.c Wed Feb 06 03:35:04 2008 +0000 +++ b/finch/libgnt/gntentry.c Wed Feb 27 04:49:37 2008 +0000 @@ -713,7 +713,7 @@ return FALSE; } - if ((text[0] == '\r' || text[0] == ' ') && entry->ddown) + if ((text[0] == '\r' || text[0] == ' ' || text[0] == '\n') && entry->ddown) { char *text = g_strdup(gnt_tree_get_selection_data(GNT_TREE(entry->ddown))); destroy_suggest(entry); @@ -782,7 +782,7 @@ return TRUE; } - if (text[0] == '\r') { + if (text[0] == '\r' || text[0] == '\n') { gnt_widget_activate(widget); return TRUE; } diff -r 00eaff9396ec -r f61f7e8d897e finch/libgnt/gntfilesel.c --- a/finch/libgnt/gntfilesel.c Wed Feb 06 03:35:04 2008 +0000 +++ b/finch/libgnt/gntfilesel.c Wed Feb 27 04:49:37 2008 +0000 @@ -342,7 +342,7 @@ static gboolean dir_key_pressed(GntTree *tree, const char *key, GntFileSel *sel) { - if (strcmp(key, "\r") == 0) { + if (strcmp(key, "\r") == 0 || strcmp(key, "\n") == 0) { char *str = g_strdup(gnt_tree_get_selection_data(tree)); char *path, *dir; @@ -376,7 +376,7 @@ struct stat st; int glob_ret; #endif - if (strcmp(key, "\r")) + if (strcmp(key, "\r") && strcmp(key, "\n")) return FALSE; str = (char*)gnt_entry_get_text(GNT_ENTRY(sel->location)); diff -r 00eaff9396ec -r f61f7e8d897e finch/libgnt/gntmain.c --- a/finch/libgnt/gntmain.c Wed Feb 06 03:35:04 2008 +0000 +++ b/finch/libgnt/gntmain.c Wed Feb 27 04:49:37 2008 +0000 @@ -221,7 +221,7 @@ io_invoke(GIOChannel *source, GIOCondition cond, gpointer null) { char keys[256]; - int rd; + gssize rd; char *k; char *cvrt = NULL; diff -r 00eaff9396ec -r f61f7e8d897e finch/libgnt/gntmenu.c --- a/finch/libgnt/gntmenu.c Wed Feb 06 03:35:04 2008 +0000 +++ b/finch/libgnt/gntmenu.c Wed Feb 27 04:49:37 2008 +0000 @@ -46,6 +46,7 @@ static void (*org_map)(GntWidget *wid); static void (*org_size_request)(GntWidget *wid); static gboolean (*org_key_pressed)(GntWidget *w, const char *t); +static gboolean (*org_clicked)(GntWidget *w, GntMouseEvent event, int x, int y); static void menuitem_activate(GntMenu *menu, GntMenuItem *item); @@ -390,6 +391,16 @@ menu->parentmenu->submenu = NULL; } +static gboolean +gnt_menu_clicked(GntWidget *widget, GntMouseEvent event, int x, int y) +{ + if (!org_clicked || !org_clicked(widget, event, x, y) || + !GNT_MENU(widget)->type == GNT_MENU_TOPLEVEL) + return FALSE; + gnt_widget_activate(widget); + return TRUE; +} + static void gnt_menu_class_init(GntMenuClass *klass) { @@ -401,6 +412,7 @@ org_draw = wid_class->draw; org_key_pressed = wid_class->key_pressed; org_size_request = wid_class->size_request; + org_clicked = wid_class->clicked; wid_class->destroy = gnt_menu_destroy; wid_class->draw = gnt_menu_draw; @@ -409,6 +421,7 @@ wid_class->key_pressed = gnt_menu_key_pressed; wid_class->activate = gnt_menu_activate; wid_class->hide = gnt_menu_hide; + wid_class->clicked = gnt_menu_clicked; parent_class->toggled = gnt_menu_toggled; diff -r 00eaff9396ec -r f61f7e8d897e finch/libgnt/gnttree.c --- a/finch/libgnt/gnttree.c Wed Feb 06 03:35:04 2008 +0000 +++ b/finch/libgnt/gnttree.c Wed Feb 27 04:49:37 2008 +0000 @@ -798,7 +798,7 @@ GntTree *tree = GNT_TREE(widget); GntTreeRow *old = tree->current; - if (text[0] == '\r') { + if (text[0] == '\r' || text[0] == '\n') { end_search(tree); gnt_widget_activate(widget); } else if (tree->priv->search) { diff -r 00eaff9396ec -r f61f7e8d897e finch/libgnt/gntwidget.c --- a/finch/libgnt/gntwidget.c Wed Feb 06 03:35:04 2008 +0000 +++ b/finch/libgnt/gntwidget.c Wed Feb 27 04:49:37 2008 +0000 @@ -407,6 +407,8 @@ { gboolean ret; g_signal_emit(widget, signals[SIG_CLICKED], 0, event, x, y, &ret); + if (!ret && event == GNT_RIGHT_MOUSE_DOWN) + ret = gnt_bindable_perform_action_named(GNT_BINDABLE(widget), "context-menu", NULL); return ret; } diff -r 00eaff9396ec -r f61f7e8d897e libpurple/account.c --- a/libpurple/account.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/account.c Wed Feb 27 04:49:37 2008 +0000 @@ -2368,8 +2368,13 @@ set_current_error(PurpleAccount *account, PurpleConnectionErrorInfo *new_err) { - PurpleAccountPrivate *priv = PURPLE_ACCOUNT_GET_PRIVATE(account); - PurpleConnectionErrorInfo *old_err = priv->current_error; + PurpleAccountPrivate *priv; + PurpleConnectionErrorInfo *old_err; + + g_return_if_fail(account != NULL); + + priv = PURPLE_ACCOUNT_GET_PRIVATE(account); + old_err = priv->current_error; if(new_err == old_err) return; @@ -2393,8 +2398,14 @@ const gchar *description, gpointer unused) { - PurpleAccount *account = purple_connection_get_account(gc); - PurpleConnectionErrorInfo *err = g_new0(PurpleConnectionErrorInfo, 1); + PurpleAccount *account; + PurpleConnectionErrorInfo *err; + + account = purple_connection_get_account(gc); + + g_return_if_fail(account != NULL); + + err = g_new0(PurpleConnectionErrorInfo, 1); err->type = type; err->description = g_strdup(description); diff -r 00eaff9396ec -r f61f7e8d897e libpurple/blist.c --- a/libpurple/blist.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/blist.c Wed Feb 27 04:49:37 2008 +0000 @@ -1588,7 +1588,7 @@ hb->group = gnode; g_hash_table_replace(purplebuddylist->buddies, hb, b); - if (b->account->gc) + if (purple_account_get_connection(b->account)) serv_move_buddy(b, (PurpleGroup *)cnode->parent, g); } else { gboolean empty_contact = FALSE; @@ -1597,7 +1597,7 @@ * gonna delete it instead */ g_free(hb->name); g_free(hb); - if (b->account->gc) + if (purple_account_get_connection(b->account)) purple_account_remove_buddy(b->account, b, (PurpleGroup *)cnode->parent); if (!cnode->child->next) @@ -2087,7 +2087,7 @@ prpl = purple_find_prpl(purple_account_get_protocol_id(chat->account)); prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); - parts = prpl_info->chat_info(chat->account->gc); + parts = prpl_info->chat_info(purple_account_get_connection(chat->account)); pce = parts->data; ret = g_hash_table_lookup(chat->components, pce->identifier); g_list_foreach(parts, (GFunc)g_free, NULL); diff -r 00eaff9396ec -r f61f7e8d897e libpurple/conversation.c --- a/libpurple/conversation.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/conversation.c Wed Feb 27 04:49:37 2008 +0000 @@ -209,11 +209,14 @@ const char *message, PurpleMessageFlags flags, time_t when) { PurpleConvMessage *msg; + PurpleConnection *gc; + + gc = purple_account_get_connection(conv->account); if (flags & PURPLE_MESSAGE_SEND) { const char *me = NULL; - if (conv->account->gc) - me = conv->account->gc->display_name; + if (gc) + me = purple_connection_get_display_name(gc); if (!me) me = conv->account->username; who = me; diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/irc/msgs.c --- a/libpurple/protocols/irc/msgs.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/irc/msgs.c Wed Feb 27 04:49:37 2008 +0000 @@ -495,6 +495,8 @@ cur++; } else if(irc->mode_chars && strchr(irc->mode_chars, *cur)) { + if (*cur == '~') + f = PURPLE_CBFLAGS_FOUNDER; cur++; } tmp = g_strndup(cur, end - cur); @@ -854,6 +856,9 @@ newflag = PURPLE_CBFLAGS_HALFOP; else if (*mcur == 'v') newflag = PURPLE_CBFLAGS_VOICE; + else if(irc->mode_chars + && strchr(irc->mode_chars, '~') && (*mcur == 'q')) + newflag = PURPLE_CBFLAGS_FOUNDER; if (newflag) { if (add) flags |= newflag; diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/jabber/buddy.c --- a/libpurple/protocols/jabber/buddy.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/jabber/buddy.c Wed Feb 27 04:49:37 2008 +0000 @@ -392,6 +392,7 @@ */ void jabber_set_info(PurpleConnection *gc, const char *info) { + PurpleStoredImage *img; JabberIq *iq; JabberStream *js = gc->proto_data; xmlnode *vc_node; @@ -410,57 +411,58 @@ */ vc_node = info ? xmlnode_from_str(info, -1) : NULL; - if(!vc_node) { - vc_node = xmlnode_new("vCard"); - for(tag_attr = vcard_tag_attr_list; tag_attr->attr != NULL; ++tag_attr) - xmlnode_set_attrib(vc_node, tag_attr->attr, tag_attr->value); + if (vc_node && (!vc_node->name || + g_ascii_strncasecmp(vc_node->name, "vCard", 5))) { + xmlnode_free(vc_node); + vc_node = NULL; } - if (vc_node->name && - !g_ascii_strncasecmp(vc_node->name, "vCard", 5)) { - PurpleStoredImage *img; - - if ((img = purple_buddy_icons_find_account_icon(gc->account))) { - gconstpointer avatar_data; - gsize avatar_len; - xmlnode *photo, *binval, *type; - gchar *enc; - int i; - unsigned char hashval[20]; - char *p, hash[41]; + if ((img = purple_buddy_icons_find_account_icon(gc->account))) { + gconstpointer avatar_data; + gsize avatar_len; + xmlnode *photo, *binval, *type; + gchar *enc; + int i; + unsigned char hashval[20]; + char *p, hash[41]; - avatar_data = purple_imgstore_get_data(img); - avatar_len = purple_imgstore_get_size(img); - /* have to get rid of the old PHOTO if it exists */ - if((photo = xmlnode_get_child(vc_node, "PHOTO"))) { - xmlnode_free(photo); - } - photo = xmlnode_new_child(vc_node, "PHOTO"); - type = xmlnode_new_child(photo, "TYPE"); - xmlnode_insert_data(type, "image/png", -1); - binval = xmlnode_new_child(photo, "BINVAL"); - enc = purple_base64_encode(avatar_data, avatar_len); - - purple_cipher_digest_region("sha1", avatar_data, - avatar_len, sizeof(hashval), - hashval, NULL); - - purple_imgstore_unref(img); - - p = hash; - for(i=0; i<20; i++, p+=2) - snprintf(p, 3, "%02x", hashval[i]); - js->avatar_hash = g_strdup(hash); - - xmlnode_insert_data(binval, enc, -1); - g_free(enc); + if(!vc_node) { + vc_node = xmlnode_new("vCard"); + for(tag_attr = vcard_tag_attr_list; tag_attr->attr != NULL; ++tag_attr) + xmlnode_set_attrib(vc_node, tag_attr->attr, tag_attr->value); } + avatar_data = purple_imgstore_get_data(img); + avatar_len = purple_imgstore_get_size(img); + /* have to get rid of the old PHOTO if it exists */ + if((photo = xmlnode_get_child(vc_node, "PHOTO"))) { + xmlnode_free(photo); + } + photo = xmlnode_new_child(vc_node, "PHOTO"); + type = xmlnode_new_child(photo, "TYPE"); + xmlnode_insert_data(type, "image/png", -1); + binval = xmlnode_new_child(photo, "BINVAL"); + enc = purple_base64_encode(avatar_data, avatar_len); + + purple_cipher_digest_region("sha1", avatar_data, + avatar_len, sizeof(hashval), + hashval, NULL); + + purple_imgstore_unref(img); + + p = hash; + for(i=0; i<20; i++, p+=2) + snprintf(p, 3, "%02x", hashval[i]); + js->avatar_hash = g_strdup(hash); + + xmlnode_insert_data(binval, enc, -1); + g_free(enc); + } + + if (vc_node != NULL) { iq = jabber_iq_new(js, JABBER_IQ_SET); xmlnode_insert_child(iq->node, vc_node); jabber_iq_send(iq); - } else { - xmlnode_free(vc_node); } } diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/jabber/jabber.c --- a/libpurple/protocols/jabber/jabber.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/jabber/jabber.c Wed Feb 27 04:49:37 2008 +0000 @@ -564,9 +564,16 @@ jabber_login_callback_ssl, jabber_ssl_connect_failure, js->certificate_CN, js->gc); } -static void jabber_login_connect(JabberStream *js, const char *fqdn, const char *host, int port) +static void jabber_login_connect(JabberStream *js, const char *domain, const char *host, int port) { - js->serverFQDN = g_strdup(fqdn); + /* host should be used in preference to domain to + * allow SASL authentication to work with FQDN of the server, + * but we use domain as fallback for when users enter IP address + * in connect server */ + if (purple_ip_address_is_valid(host)) + js->serverFQDN = g_strdup(domain); + else + js->serverFQDN = g_strdup(host); if (purple_proxy_connect(js->gc, js->gc->account, host, port, jabber_login_callback, js->gc) == NULL) diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/msn/notification.c --- a/libpurple/protocols/msn/notification.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/msn/notification.c Wed Feb 27 04:49:37 2008 +0000 @@ -1074,7 +1074,7 @@ PurpleConnection *gc; MsnUser *user; MsnObject *msnobj; - int clientid; + unsigned long clientid; int wlmclient; const char *state, *passport, *friendly, *old_friendly; @@ -1109,7 +1109,7 @@ } } - clientid = atoi(cmd->params[4]); + clientid = strtoul(cmd->params[4], NULL, 0); user->mobile = (clientid & MSN_CLIENT_CAP_MSNMOBILE); msn_user_set_state(user, state); diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/myspace/message.c --- a/libpurple/protocols/myspace/message.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/myspace/message.c Wed Feb 27 04:49:37 2008 +0000 @@ -50,11 +50,12 @@ { GString *gs; guint i, j; + guint msg_len; gs = g_string_new(""); - + msg_len = strlen(msg); - for (i = 0; i < strlen(msg); ++i) { + for (i = 0; i < msg_len; ++i) { struct MSIM_ESCAPE_REPLACEMENT *replacement; gchar *replace; @@ -93,10 +94,12 @@ { GString *gs; guint i, j; + guint msg_len; gs = g_string_new(""); + msg_len = strlen(msg); - for (i = 0; i < strlen(msg); ++i) { + for (i = 0; i < msg_len; ++i) { struct MSIM_ESCAPE_REPLACEMENT *replacement; gchar replace; @@ -105,7 +108,7 @@ for (j = 0; (replacement = &msim_escape_replacements[j]) && replacement->code != NULL; ++j) { if (msg[i] == replacement->code[0] && - i + 1 < strlen(msg) && + i + 1 < msg_len && msg[i + 1] == replacement->code[1]) { replace = replacement->text; ++i; @@ -426,6 +429,7 @@ * @param user_data Not used; required to match g_list_foreach() callback prototype. * * Frees both the element data and the element itself. + * Also frees the name if dynamic_name is TRUE. */ static void msim_msg_free_element(gpointer data, gpointer user_data) @@ -436,6 +440,12 @@ msim_msg_free_element_data(elem); + if (elem->dynamic_name) + /* Need to cast to remove const-ness, because + * elem->name is almost always a constant, static + * string, but not in this case. */ + g_free((gchar *)elem->name); + g_free(elem); } @@ -509,15 +519,18 @@ /** Create a new MsimMessageElement * - must be g_free()'d. * * For internal use; users probably want msim_msg_append() or msim_msg_insert_before(). + * + * @param dynamic_name Whether 'name' should be freed when the message is destroyed. */ static MsimMessageElement * -msim_msg_element_new(const gchar *name, MsimMessageType type, gpointer data) +msim_msg_element_new(const gchar *name, MsimMessageType type, gpointer data, gboolean dynamic_name) { MsimMessageElement *elem; elem = g_new0(MsimMessageElement, 1); elem->name = name; + elem->dynamic_name = dynamic_name; elem->type = type; elem->data = data; @@ -556,7 +569,18 @@ msim_msg_append(MsimMessage *msg, const gchar *name, MsimMessageType type, gpointer data) { - return g_list_append(msg, msim_msg_element_new(name, type, data)); + return g_list_append(msg, msim_msg_element_new(name, type, data, FALSE)); +} + +/** Append a new element, but with a dynamically-allocated name. + * Exactly the same as msim_msg_append(), except 'name' will be freed when + * the message is destroyed. Normally, it isn't, because a static string is given. + */ +static MsimMessage * +msim_msg_append_dynamic_name(MsimMessage *msg, gchar *name, + MsimMessageType type, gpointer data) +{ + return g_list_append(msg, msim_msg_element_new(name, type, data, TRUE)); } /** Insert a new element into a message, before the given element name. @@ -573,7 +597,7 @@ MsimMessageElement *new_elem; GList *node_before; - new_elem = msim_msg_element_new(name, type, data); + new_elem = msim_msg_element_new(name, type, data, FALSE); node_before = msim_msg_get_node(msg, name_before); @@ -1193,8 +1217,9 @@ purple_debug_info("msim_msg_parse_dictionary","-- %s: %s\n", key ? key : "(NULL)", value ? value : "(NULL)"); #endif - /* TODO: free key; right now it is treated as static */ - dict = msim_msg_append(dict, g_strdup(key), MSIM_TYPE_RAW, g_strdup(value)); + /* Append with _dynamic_name since g_strdup(key) is dynamic, and + * needs to be freed when the message is destroyed. It isn't static as usual. */ + dict = msim_msg_append_dynamic_name(dict, g_strdup(key), MSIM_TYPE_RAW, g_strdup(value)); g_strfreev(elements); } diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/myspace/message.h --- a/libpurple/protocols/myspace/message.h Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/myspace/message.h Wed Feb 27 04:49:37 2008 +0000 @@ -29,6 +29,7 @@ typedef struct _MsimMessageElement { const gchar *name; /**< Textual name of element. */ + gboolean dynamic_name; /**< TRUE if 'name' is a dynamic string to be freed, not static. */ guint type; /**< MSIM_TYPE_* code. */ gpointer data; /**< Pointer to data, or GUINT_TO_POINTER for int/bool. */ } MsimMessageElement; diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/myspace/myspace.c --- a/libpurple/protocols/myspace/myspace.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/myspace/myspace.c Wed Feb 27 04:49:37 2008 +0000 @@ -73,7 +73,7 @@ static gboolean msim_check_alive(gpointer data); #endif -static gboolean msim_we_are_logged_on(MsimSession *session, MsimMessage *msg); +static gboolean msim_is_username_set(MsimSession *session, MsimMessage *msg); static gboolean msim_process(MsimSession *session, MsimMessage *msg); @@ -291,27 +291,6 @@ gc->proto_data = msim_session_new(acct); gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_URLDESC; -#ifdef MSIM_MAX_PASSWORD_LENGTH - /* Passwords are limited in length. */ - if (strlen(acct->password) > MSIM_MAX_PASSWORD_LENGTH) { - gchar *str; - - str = g_strdup_printf( - _("Sorry, passwords over %d characters in length (yours is " - "%d) are not supported by MySpace."), - MSIM_MAX_PASSWORD_LENGTH, - (int)strlen(acct->password)); - - /* Notify an error message also, because this is important! */ - purple_notify_error(acct, _("MySpaceIM Error"), str, NULL); - - purple_connection_error_reason (gc, - PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, str); - g_free(str); - return; - } -#endif - /* 1. connect to server */ purple_connection_update_progress(gc, _("Connecting"), 0, /* which connection step this is */ @@ -1567,14 +1546,14 @@ } #endif -/** Called when the session key arrives. */ +/** Called when the session key arrives to check whether the user + * has a username, and set one if desired. */ static gboolean -msim_we_are_logged_on(MsimSession *session, MsimMessage *msg) +msim_is_username_set(MsimSession *session, MsimMessage *msg) { - MsimMessage *body; - g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE); g_return_val_if_fail(msg != NULL, FALSE); + g_return_val_if_fail(session->gc != NULL, FALSE); session->sesskey = msim_msg_get_integer(msg, "sesskey"); purple_debug_info("msim", "SESSKEY=<%d>\n", session->sesskey); @@ -1599,8 +1578,32 @@ * address and not username. Will be freed in msim_session_destroy(). */ session->username = msim_msg_get_string(msg, "uniquenick"); - /* Set display name to username (otherwise will show email address) */ - purple_connection_set_display_name(session->gc, session->username); + /* If user lacks a username, help them get one. */ + if (msim_msg_get_integer(msg, "uniquenick") == session->userid) { + purple_debug_info("msim_is_username_set", "no username is set\n"); + purple_request_yes_no(session->gc, + _("MySpaceIM - No Username Set"), + _("You appear to have no MySpace username."), + _("Would you like to set one now? (Note: THIS CANNOT BE CHANGED!)"), + 0, + session->account, + NULL, + NULL, + session->gc, + G_CALLBACK(msim_set_username_cb), + G_CALLBACK(msim_do_not_set_username_cb)); + purple_debug_info("msim_is_username_set","'username not set' alert prompted\n"); + return FALSE; + } + return TRUE; +} + +/** Called after username is set, if necessary and we're open for business. */ +gboolean msim_we_are_logged_on(MsimSession *session) +{ + MsimMessage *body; + + g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE); /* The session is now set up, ready to be connected. This emits the * signedOn signal, so clients can now do anything with msimprpl, and @@ -1608,20 +1611,8 @@ purple_connection_update_progress(session->gc, _("Connected"), 3, 4); purple_connection_set_state(session->gc, PURPLE_CONNECTED); - - /* Additional post-connect operations */ - - - if (msim_msg_get_integer(msg, "uniquenick") == session->userid) { - purple_debug_info("msim_we_are_logged_on", "TODO: pick username\n"); - /* No username is set. */ - purple_notify_error(session->account, - _("No username set"), - _("Please go to http://editprofile.myspace.com/index.cfm?fuseaction=profile.username and choose a username and try to login again."), NULL); - purple_connection_error_reason (session->gc, - PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("No username set")); - return FALSE; - } + /* Set display name to username (otherwise will show email address) */ + purple_connection_set_display_name(session->gc, session->username); body = msim_msg_new( "UserID", MSIM_TYPE_INTEGER, session->userid, @@ -1708,7 +1699,14 @@ if (msim_msg_get_integer(msg, "lc") == 1) { return msim_login_challenge(session, msg); } else if (msim_msg_get_integer(msg, "lc") == 2) { - return msim_we_are_logged_on(session, msg); + /* return msim_we_are_logged_on(session, msg); */ + if (msim_is_username_set(session, msg)) { + return msim_we_are_logged_on(session); + } else { + /* No username is set... We'll wait for the callbacks to do their work */ + /* When they're all done, the last one will call msim_we_are_logged_on() and pick up where we left off */ + return FALSE; + } } else if (msim_msg_get(msg, "bm")) { return msim_incoming_bm(session, msg); } else if (msim_msg_get(msg, "rid")) { @@ -1863,6 +1861,24 @@ reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; if (!purple_account_get_remember_password(session->account)) purple_account_set_password(session->account, NULL); +#ifdef MSIM_MAX_PASSWORD_LENGTH + if (strlen(session->account->password) > MSIM_MAX_PASSWORD_LENGTH) { + gchar *suggestion; + + suggestion = g_strdup_printf(_("%s Your password is " + "%d characters, greater than the " + "expected maximum length of %d for " + "MySpaceIM. Please shorten your " + "password at http://profileedit.myspace.com/index.cfm?fuseaction=accountSettings.changePassword and try again."), + full_errmsg, (int) + strlen(session->account->password), + MSIM_MAX_PASSWORD_LENGTH); + + /* Replace full_errmsg. */ + g_free(full_errmsg); + full_errmsg = suggestion; + } +#endif break; case MSIM_ERROR_LOGGED_IN_ELSEWHERE: /* Logged in elsewhere */ reason = PURPLE_CONNECTION_ERROR_NAME_IN_USE; @@ -2800,7 +2816,14 @@ * the documentation claims). */ group_name = msim_msg_get_string(contact_info, "GroupName"); if (group_name) { - group = purple_group_new(group_name); + group = purple_find_group(group_name); + if (!group) { + group = purple_group_new(group_name); + /* Add group to beginning. See #2752. */ + purple_blist_add_group(group, NULL); + + } + purple_debug_info("msim_add_contact_from_server_cb", "adding to GroupName: %s\n", group_name); g_free(group_name); @@ -2816,9 +2839,6 @@ buddy = purple_buddy_new(session->account, username, NULL); } - /* Add group to beginning. See #2752. */ - purple_blist_add_group(group, NULL); - /* TODO: use 'Position' in contact_info to take into account where buddy is */ purple_blist_add_buddy(buddy, NULL, group, NULL /* insertion point */); diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/myspace/myspace.h --- a/libpurple/protocols/myspace/myspace.h Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/myspace/myspace.h Wed Feb 27 04:49:37 2008 +0000 @@ -45,6 +45,7 @@ #include "cipher.h" /* for SHA-1 */ #include "util.h" /* for base64 */ #include "debug.h" /* for purple_debug_info */ +#include "request.h" /* For dialogs used in setting the username */ #include "xmlnode.h" #include "core.h" @@ -84,9 +85,12 @@ * http://settings.myspace.com/index.cfm?fuseaction=user.changepassword * (though curiously, not on the 'current password' field). */ -/* Not defined; instead have the client reject the password, until libpurple - * supports specifying a length limit on the protocol's password. */ -/* #define MSIM_MAX_PASSWORD_LENGTH 10 */ +/* After login fails, if password is greater than this many characters, + * warn user that it may be too long. */ +#define MSIM_MAX_PASSWORD_LENGTH 10 + +/* Maximum length of usernames, when setting. */ +#define MSIM_MAX_USERNAME_LENGTH 25 /* Build version of MySpaceIM to report to servers (1.0.xxx.0) */ #define MSIM_CLIENT_VERSION 697 @@ -108,6 +112,7 @@ /* Time between keepalives (seconds) - if no data within this time, is dead. */ #define MSIM_KEEPALIVE_INTERVAL (3 * 60) +/*#define MSIM_USE_KEEPALIVE*/ /* Time to check if alive (milliseconds) */ #define MSIM_KEEPALIVE_INTERVAL_CHECK (30 * 1000) @@ -221,6 +226,8 @@ gboolean msim_send_bm(MsimSession *session, const gchar *who, const gchar *text, int type); +gboolean msim_we_are_logged_on(MsimSession *session); + void msim_unrecognized(MsimSession *session, MsimMessage *msg, gchar *note); guint msim_new_reply_callback(MsimSession *session, MSIM_USER_LOOKUP_CB cb, gpointer data); diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/myspace/persist.h --- a/libpurple/protocols/myspace/persist.h Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/myspace/persist.h Wed Feb 27 04:49:37 2008 +0000 @@ -73,7 +73,8 @@ /** Messages to Change/send information */ MSIM_PERSIST_DSN_LID(MC_USER_PREFERENCES, 1, 10) MSIM_PERSIST_DSN_LID(MC_CONTACT_INFO, 0, 9) -MSIM_PERSIST_DSN_LID(MC_IMPORT_ALL_FRIENDS, 14, 21) +MSIM_PERSIST_DSN_LID(MC_SET_USERNAME, 9, 14) +MSIM_PERSIST_DSN_LID(MC_IMPORT_ALL_FRIENDS, 14, 21) MSIM_PERSIST_DSN_LID(MC_INVITE, 16, 25) /** Messages to Delete information */ diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/myspace/user.c --- a/libpurple/protocols/myspace/user.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/myspace/user.c Wed Feb 27 04:49:37 2008 +0000 @@ -24,6 +24,15 @@ static void msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, gsize len, const gchar *error_message); +/* Callbacks for setting the username bit */ +static void msim_check_username_availability_cb(PurpleConnection *gc, const char *value); +static void msim_username_is_available_cb(MsimSession *session, MsimMessage *userinfo, gpointer data); +static void msim_set_username_confirmed_cb(PurpleConnection *gc); +static void msim_username_is_set_cb(MsimSession *session, MsimMessage *userinfo, gpointer data); +static void msim_set_username(MsimSession *session, const gchar *username, + MSIM_USER_LOOKUP_CB cb, gpointer data); +static char *msim_username_to_set; + /** Format the "now playing" indicator, showing the artist and song. * @return Return a new string (must be g_free()'d), or NULL. */ @@ -487,6 +496,19 @@ return strspn(user, "0123456789") == strlen(user); } +/** Return whether a given username is syntactically valid. + * Note: does not actually check that the user exists. */ +gboolean +msim_is_valid_username(const gchar *user) +{ + return !msim_is_userid(user) && /* Not all numeric */ + strlen(user) <= MSIM_MAX_USERNAME_LENGTH + && strspn(user, "0123456789" + "abcdefghijklmnopqrstuvwxyz" + "_" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ") == strlen(user); +} + /** * Check if a string is an email address (contains an @). * @@ -537,4 +559,280 @@ user->image_url); /* checksum */ } +/*** + * If they hit cancel or no at any point in the Setting Username process, we come here. * + * Currently.. We're safe letting them get by without setting it.. Unless we hear otherwise.. * + * So for now, give them a menu.. If this becomes an issue with the Official client.. boot them here */ +void msim_do_not_set_username_cb(PurpleConnection *gc) { + purple_debug_info("msim", "Don't set username"); + /* Protocol won't log in now without a username set.. Disconnect */ + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("No username set")); +} + +/** They've decided to set a username! Yay! */ +void msim_set_username_cb(PurpleConnection *gc) { + g_return_if_fail(gc != NULL); + purple_debug_info("msim","Set username\n"); + purple_request_input(gc, _("MySpaceIM - Please Set a Username"), + _("Please enter a username to check its availability:"), + NULL, + "", FALSE, FALSE, NULL, + _("OK"), G_CALLBACK(msim_check_username_availability_cb), + _("Cancel"), G_CALLBACK(msim_do_not_set_username_cb), + purple_connection_get_account(gc), + NULL, + NULL, + gc); +} + +/** Once they've submitted their desired new username, + * check if it is available here. */ +static void msim_check_username_availability_cb(PurpleConnection *gc, const char *username_to_check) +{ + MsimMessage *user_msg; + MsimSession *session; + + g_return_if_fail(gc != NULL); + + session = (MsimSession *)gc->proto_data; + + g_return_if_fail(MSIM_SESSION_VALID(session)); + + purple_debug_info("msim_check_username_availability_cb", "Checking username: %s\n", username_to_check); + + user_msg = msim_msg_new( + "user", MSIM_TYPE_STRING, g_strdup(username_to_check), + NULL); + + /* 25 characters: letters, numbers, underscores */ + /* TODO: VERIFY ABOVE */ + + /* \persist\1\sesskey\288500516\cmd\1\dsn\5\uid\204084363\lid\7\rid\367\body\UserName=Jaywalker\final\ */ + /* Official client uses a standard lookup... So do we! */ + msim_lookup_user(session, username_to_check, msim_username_is_available_cb, user_msg); +} + +/** This is where we do a bit more than merely prompt the user. + * Now we have some real data to tell us the state of their requested username + * \persistr\\cmd\257\dsn\5\uid\204084363\lid\7\rid\367\body\UserName=TheAlbinoRhino1\final\ */ +static void msim_username_is_available_cb(MsimSession *session, MsimMessage *userinfo, gpointer data) +{ + MsimMessage *msg; + gchar *username; + MsimMessage *body; + gint userid; + + purple_debug_info("msim_username_is_available_cb", "Look up username callback made\n"); + + msg = (MsimMessage *)data; + g_return_if_fail(MSIM_SESSION_VALID(session)); + g_return_if_fail(msg != NULL); + + username = msim_msg_get_string(msg, "user"); + body = msim_msg_get_dictionary(userinfo, "body"); + + if (!body) { + purple_debug_info("msim_username_is_available_cb", "No body for %s?!\n", username); + purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, + "An error occured while trying to set the username.\n" + "Please try again, or visit http://editprofile.myspace.com/index.cfm?" + "fuseaction=profile.username to set your username."); + return; + } + + userid = msim_msg_get_integer(body, "UserID"); + + purple_debug_info("msim_username_is_available_cb", "Returned username is %s and userid is %d\n", username, userid); + msim_msg_free(body); + msim_msg_free(msg); + + /* The response for a free username will ONLY have the UserName in it.. + * thus making UserID return 0 when we msg_get_integer it */ + if (userid == 0) { + /* This username is currently unused */ + purple_debug_info("msim_username_is_available_cb", "Username available. Prompting to Confirm.\n"); + msim_username_to_set = g_strdup(username); + g_free(username); + purple_request_yes_no(session->gc, + _("MySpaceIM - Username Available"), + _("This username is available. Would you like to set it?"), + _("ONCE SET, THIS CANNOT BE CHANGED!"), + 0, + session->account, + NULL, + NULL, + session->gc, + G_CALLBACK(msim_set_username_confirmed_cb), + G_CALLBACK(msim_do_not_set_username_cb)); + } else { + /* Looks like its in use or we have an invalid response */ + purple_debug_info("msim_username_is_available_cb", "Username unavaiable. Prompting for new entry.\n"); + purple_request_input(session->gc, _("MySpaceIM - Please Set a Username"), + _("This username is unavailable."), + _("Please try another username:"), + "", FALSE, FALSE, NULL, + _("OK"), G_CALLBACK(msim_check_username_availability_cb), + _("Cancel"), G_CALLBACK(msim_do_not_set_username_cb), + session->account, + NULL, + NULL, + session->gc); + } +} + +/* They've confirmed that username that was available, Lets make the call to set it */ +static void msim_set_username_confirmed_cb(PurpleConnection *gc) +{ + MsimMessage *user_msg; + MsimSession *session; + + g_return_if_fail(gc != NULL); + + session = (MsimSession *)gc->proto_data; + + g_return_if_fail(MSIM_SESSION_VALID(session)); + + + user_msg = msim_msg_new( + "user", MSIM_TYPE_STRING, g_strdup(msim_username_to_set), + NULL); + + purple_debug_info("msim_set_username_confirmed_cb", "Setting username to %s\n", msim_username_to_set); + + /* Sets our username... keep your fingers crossed :) */ + msim_set_username(session, msim_username_to_set, msim_username_is_set_cb, user_msg); + g_free(msim_username_to_set); +} + +/** + * Asynchronously set new username, calling callback when receive result. + * + * @param session + * @param username The username we're setting for ourselves. Not freed. + * @param cb Callback, called with user information when available. + * @param data An arbitray data pointer passed to the callback. + */ +static void +msim_set_username(MsimSession *session, const gchar *username, + MSIM_USER_LOOKUP_CB cb, gpointer data) +{ + MsimMessage *body; + guint rid; + + g_return_if_fail(MSIM_SESSION_VALID(session)); + g_return_if_fail(username != NULL); + g_return_if_fail(cb != NULL); + + purple_debug_info("msim", "msim_set_username: " + "Setting username %s\n", username); + + msim_msg_dump("msim_set_username: data=%s\n", (MsimMessage *)data); + + /* Setup callback. Response will be associated with request using 'rid'. */ + rid = msim_new_reply_callback(session, cb, data); + + /* TODO: I dont know if the ContactType is -/ALWAYS/- 1 */ + + body = msim_msg_new("UserName", MSIM_TYPE_STRING, g_strdup(username),NULL); +/* \setinfo\\sesskey\469958979\info\Age=21.AvatarUrl=.BandName=.ContactType=1.DisplayName=Msim.Gender=M.ImageURL=http:/1/1x.myspace.com/1images/1no_pic.gif.LastLogin=128335268400000000.Location=US.ShowAvatar=False.SongName=.TotalFriends=1.UserName=msimprpl2\final\ +*/ + + /* Send request */ + g_return_if_fail(msim_send(session, + "setinfo", MSIM_TYPE_BOOLEAN, TRUE, + "sesskey", MSIM_TYPE_INTEGER, session->sesskey, + "info", MSIM_TYPE_DICTIONARY, body, + NULL)); + body = msim_msg_new("UserName", MSIM_TYPE_STRING, g_strdup(username),NULL); + g_return_if_fail(msim_send(session, + "persist", MSIM_TYPE_INTEGER, 1, + "sesskey", MSIM_TYPE_INTEGER, session->sesskey, + "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_GET, + "dsn", MSIM_TYPE_INTEGER, MG_MYSPACE_INFO_BY_STRING_DSN, + "uid", MSIM_TYPE_INTEGER, session->userid, + "lid", MSIM_TYPE_INTEGER, MG_MYSPACE_INFO_BY_STRING_LID, + "rid", MSIM_TYPE_INTEGER, rid, + "body", MSIM_TYPE_DICTIONARY, body, + NULL)); +} + +/** Called after username is set. */ +static void msim_username_is_set_cb(MsimSession *session, MsimMessage *userinfo, gpointer data) +{ + gchar *username, *errmsg; + MsimMessage *body; + + guint rid; + gint cmd,dsn,uid,lid,code; + /* \persistr\\cmd\258\dsn\9\uid\204084363\lid\14\rid\369\body\UserName=TheAlbinoRhino1.Code=0\final\ */ + + purple_debug_info("msim","username_is_set made\n"); + + g_return_if_fail(MSIM_SESSION_VALID(session)); + + + msim_msg_dump("username_is_set message is: %s\n", userinfo); + cmd = msim_msg_get_integer(userinfo, "cmd"); + dsn = msim_msg_get_integer(userinfo, "dsn"); + uid = msim_msg_get_integer(userinfo, "uid"); + lid = msim_msg_get_integer(userinfo, "lid"); + body = msim_msg_get_dictionary(userinfo, "body"); + errmsg = g_strdup("An error occured while trying to set the username.\n" + "Please try again, or visit http://editprofile.myspace.com/index.cfm?" + "fuseaction=profile.username to set your username."); + + if (!body) { + purple_debug_info("msim_username_is_set_cb", "No body"); + /* Error: No body! */ + purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg); + } + username = msim_msg_get_string(body, "UserName"); + code = msim_msg_get_integer(body,"Code"); + + msim_msg_free(body); + + purple_debug_info("msim_username_is_set_cb", + "cmd = %d, dsn = %d, lid = %d, code = %d, username = %s\n", + cmd, dsn, lid, code, username); + + if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_PUT) + && dsn == MC_SET_USERNAME_DSN + && lid == MC_SET_USERNAME_LID) { + purple_debug_info("msim_username_is_set_cb", "Proper cmd,dsn,lid for username_is_set!\n"); + purple_debug_info("msim_username_is_set_cb", "Username Set with return code %d\n",code); + if (code == 0) { + /* Good! */ + session->username = username; + msim_we_are_logged_on(session); + } else { + purple_debug_info("msim_username_is_set", "code is %d",code); + /* TODO: what to do here? */ + } + } else if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_GET) + && dsn == MG_MYSPACE_INFO_BY_STRING_DSN + && lid == MG_MYSPACE_INFO_BY_STRING_LID) { + /* Not quite done... ONE MORE STEP :) */ + rid = msim_new_reply_callback(session, msim_username_is_set_cb, data); + body = msim_msg_new("UserName", MSIM_TYPE_STRING, g_strdup(username), NULL); + if (!msim_send(session, "persist", MSIM_TYPE_INTEGER, 1, + "sesskey", MSIM_TYPE_INTEGER, session->sesskey, + "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_PUT, + "dsn", MSIM_TYPE_INTEGER, MC_SET_USERNAME_DSN, + "uid", MSIM_TYPE_INTEGER, session->userid, + "lid", MSIM_TYPE_INTEGER, MC_SET_USERNAME_LID, + "rid", MSIM_TYPE_INTEGER, rid, + "body", MSIM_TYPE_DICTIONARY, body, + NULL)) { + /* Error! */ + /* Can't set... Disconnect */ + purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg); + } + + } else { + /* Error! */ + purple_debug_info("msim","username_is_set Error: Invalid cmd/dsn/lid combination"); + purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg); + } + g_free(errmsg); +} diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/myspace/user.h --- a/libpurple/protocols/myspace/user.h Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/myspace/user.h Wed Feb 27 04:49:37 2008 +0000 @@ -51,6 +51,9 @@ gboolean msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user); gboolean msim_is_userid(const gchar *user); gboolean msim_is_email(const gchar *user); +gboolean msim_is_valid_username(const gchar *user); void msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data); +void msim_set_username_cb(PurpleConnection *gc); +void msim_do_not_set_username_cb(PurpleConnection *gc); #endif /* !_MYSPACE_USER_H */ diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/oscar/oscar.c --- a/libpurple/protocols/oscar/oscar.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/oscar/oscar.c Wed Feb 27 04:49:37 2008 +0000 @@ -6609,18 +6609,18 @@ g_return_val_if_fail(str != NULL, NULL); - strncpy(buf, str, BUF_LEN); - for (i=0, j=0; buf[j]; i++, j++) + /* copy str to buf and skip all blanks */ + for (i=0, j=0; str[j] && i < BUF_LEN; i++, j++) { - while (buf[j] == ' ') + while (str[j] == ' ') j++; - buf[i] = buf[j]; + buf[i] = str[j]; } buf[i] = '\0'; tmp1 = g_utf8_strdown(buf, -1); tmp2 = g_utf8_normalize(tmp1, -1, G_NORMALIZE_DEFAULT); - g_snprintf(buf, sizeof(buf), "%s", tmp2); + strcpy(buf, tmp2); g_free(tmp2); g_free(tmp1); diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/silc/util.c --- a/libpurple/protocols/silc/util.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/silc/util.c Wed Feb 27 04:49:37 2008 +0000 @@ -442,6 +442,7 @@ strcat(buf, "[rejects watching] "); if (mode & SILC_UMODE_BLOCK_INVITE) strcat(buf, "[blocks invites] "); + g_strchomp(buf); } void silcpurple_get_chmode_string(SilcUInt32 mode, char *buf, @@ -470,6 +471,7 @@ strcat(buf, "[users silenced] "); if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS) strcat(buf, "[operators silenced] "); + g_strchomp(buf); } void silcpurple_get_chumode_string(SilcUInt32 mode, char *buf, @@ -488,6 +490,7 @@ strcat(buf, "[blocks robot messages] "); if (mode & SILC_CHANNEL_UMODE_QUIET) strcat(buf, "[quieted] "); + g_strchomp(buf); } void @@ -544,6 +547,7 @@ if (strlen(s->str)) { *moodstr = s->str; g_string_free(s, FALSE); + g_strchomp(*moodstr); } else g_string_free(s, TRUE); @@ -573,6 +577,7 @@ if (strlen(s->str)) { *contactstr = s->str; g_string_free(s, FALSE); + g_strchomp(*contactstr); } else g_string_free(s, TRUE); diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/silc10/util.c --- a/libpurple/protocols/silc10/util.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/silc10/util.c Wed Feb 27 04:49:37 2008 +0000 @@ -432,6 +432,7 @@ strcat(buf, "[rejects watching] "); if (mode & SILC_UMODE_BLOCK_INVITE) strcat(buf, "[blocks invites] "); + g_strchomp(buf); } void silcpurple_get_chmode_string(SilcUInt32 mode, char *buf, @@ -460,6 +461,7 @@ strcat(buf, "[users silenced] "); if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS) strcat(buf, "[operators silenced] "); + g_strchomp(buf); } void silcpurple_get_chumode_string(SilcUInt32 mode, char *buf, @@ -478,6 +480,7 @@ strcat(buf, "[blocks robot messages] "); if (mode & SILC_CHANNEL_UMODE_QUIET) strcat(buf, "[quieted] "); + g_strchomp(buf); } void @@ -534,6 +537,7 @@ if (strlen(s->str)) { *moodstr = s->str; g_string_free(s, FALSE); + g_strchomp(*moodstr); } else g_string_free(s, TRUE); @@ -563,6 +567,7 @@ if (strlen(s->str)) { *contactstr = s->str; g_string_free(s, FALSE); + g_strchomp(*contactstr); } else g_string_free(s, TRUE); diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/yahoo/yahoo.c --- a/libpurple/protocols/yahoo/yahoo.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo.c Wed Feb 27 04:49:37 2008 +0000 @@ -1471,13 +1471,24 @@ to_y64(result96, digest, 16); pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, YAHOO_STATUS_AVAILABLE, 0); - yahoo_packet_hash(pack, "ssssss", - 0, name, - 6, result6, - 96, result96, - 1, name, - 244, YAHOO_CLIENT_VERSION_ID, - 135, YAHOO_CLIENT_VERSION); + + if(yd->jp) { + yahoo_packet_hash(pack, "sssss", + 0, name, + 6, result6, + 96, result96, + 1, name, + 135, YAHOOJP_CLIENT_VERSION); + } else { + yahoo_packet_hash(pack, "ssssss", + 0, name, + 6, result6, + 96, result96, + 1, name, + 244, YAHOO_CLIENT_VERSION_ID, + 135, YAHOO_CLIENT_VERSION); + } + yahoo_packet_send_and_free(pack, yd); g_free(hash_string_p); @@ -1923,13 +1934,24 @@ } purple_debug_info("yahoo", "yahoo status: %d\n", yd->current_status); pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->current_status, 0); - yahoo_packet_hash(pack, "ssssss", - 0, name, - 6, resp_6, - 96, resp_96, - 1, name, - 244, YAHOO_CLIENT_VERSION_ID, - 135, YAHOO_CLIENT_VERSION); + + if(yd->jp) { + yahoo_packet_hash(pack, "sssss", + 0, name, + 6, resp_6, + 96, resp_96, + 1, name, + 135, YAHOOJP_CLIENT_VERSION); + } else { + yahoo_packet_hash(pack, "ssssss", + 0, name, + 6, resp_6, + 96, resp_96, + 1, name, + 244, YAHOO_CLIENT_VERSION_ID, + 135, YAHOO_CLIENT_VERSION); + } + if (yd->picture_checksum) yahoo_packet_hash_int(pack, 192, yd->picture_checksum); @@ -3487,8 +3509,13 @@ "Host: login.yahoo.com\r\n" "Content-Length: 0\r\n\r\n", yd->cookie_t, yd->cookie_y); - - url_data = purple_util_fetch_url_request(base_url, FALSE, + gboolean use_whole_url = FALSE; + + /* use whole URL if using HTTP Proxy */ + if ((gc->account->proxy_info) && (gc->account->proxy_info->type == PURPLE_PROXY_HTTP)) + use_whole_url = TRUE; + + url_data = purple_util_fetch_url_request(base_url, use_whole_url, "Mozilla/4.0 (compatible; MSIE 5.5)", TRUE, request, FALSE, yahoo_get_inbox_token_cb, gc); diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/yahoo/yahoo.h --- a/libpurple/protocols/yahoo/yahoo.h Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo.h Wed Feb 27 04:49:37 2008 +0000 @@ -46,7 +46,7 @@ #define YAHOOJP_XFER_HOST "filetransfer.msg.yahoo.co.jp" #define YAHOOJP_WEBCAM_HOST "wc.yahoo.co.jp" /*not sure, must test:*/ -#define YAHOOJP_XFER_RELAY_HOST "relay.msg.yahoo.com" +#define YAHOOJP_XFER_RELAY_HOST "relay.msg.yahoo.co.jp" #define YAHOOJP_XFER_RELAY_PORT 80 #define YAHOOJP_ROOMLIST_URL "http://insider.msg.yahoo.co.jp/ycontent/" #define YAHOOJP_ROOMLIST_LOCALE "ja" @@ -76,6 +76,15 @@ #define YAHOO_CLIENT_VERSION_ID "2097087" #define YAHOO_CLIENT_VERSION "8.1.0.421" +#define YAHOOJP_CLIENT_VERSION "6,0,0,1710" + +#if 0 +/* The following were observed with the Yahoo Japan client current as of January + * 2008, but appear not to work correctly for file transfer. Here as reference */ +# define YAHOOJP_CLIENT_VERSION_ID "524223" +# define YAHOOJP_CLIENT_VERSION "7,0,1,1" +#endif + /* Index into attention types list. */ #define YAHOO_BUZZ 0 diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/yahoo/yahoo_aliases.c --- a/libpurple/protocols/yahoo/yahoo_aliases.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo_aliases.c Wed Feb 27 04:49:37 2008 +0000 @@ -148,6 +148,12 @@ char *request, *webpage, *webaddress; PurpleUtilFetchUrlData *url_data; + gboolean use_whole_url = FALSE; + + /* use whole URL if using HTTP Proxy */ + if ((gc->account->proxy_info) && (gc->account->proxy_info->type == PURPLE_PROXY_HTTP)) + use_whole_url = TRUE; + /* Using callback_data so I have access to gc in the callback function */ cb = g_new0(struct callback_data, 1); cb->gc = gc; @@ -155,15 +161,15 @@ /* Build all the info to make the web request */ url = yd->jp ? YAHOOJP_ALIAS_FETCH_URL : YAHOO_ALIAS_FETCH_URL; purple_url_parse(url, &webaddress, NULL, &webpage, NULL, NULL); - request = g_strdup_printf("GET /%s HTTP/1.1\r\n" + request = g_strdup_printf("GET %s%s/%s HTTP/1.1\r\n" "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\n" "Cookie: T=%s; Y=%s\r\n" "Host: %s\r\n" "Cache-Control: no-cache\r\n\r\n", - webpage, yd->cookie_t,yd->cookie_y, webaddress); + use_whole_url ? "http://" : "", use_whole_url ? webaddress : "", webpage, yd->cookie_t,yd->cookie_y, webaddress); /* We have a URL and some header information, let's connect and get some aliases */ - url_data = purple_util_fetch_url_request(url, FALSE, NULL, TRUE, request, FALSE, yahoo_fetch_aliases_cb, cb); + url_data = purple_util_fetch_url_request(url, use_whole_url, NULL, TRUE, request, FALSE, yahoo_fetch_aliases_cb, cb); if (url_data != NULL) { yd->url_datas = g_slist_prepend(yd->url_datas, url_data); } @@ -232,6 +238,11 @@ struct callback_data *cb; PurpleBuddy *buddy; PurpleUtilFetchUrlData *url_data; + gboolean use_whole_url = FALSE; + + /* use whole URL if using HTTP Proxy */ + if ((gc->account->proxy_info) && (gc->account->proxy_info->type == PURPLE_PROXY_HTTP)) + use_whole_url = TRUE; g_return_if_fail(alias != NULL); g_return_if_fail(who != NULL); @@ -274,18 +285,18 @@ g_free(escaped_alias); } - request = g_strdup_printf("POST /%s HTTP/1.1\r\n" + request = g_strdup_printf("POST %s%s/%s HTTP/1.1\r\n" "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\n" "Cookie: T=%s; Y=%s\r\n" "Host: %s\r\n" "Content-Length: %" G_GSIZE_FORMAT "\r\n" "Cache-Control: no-cache\r\n\r\n" "%s", - webpage, yd->cookie_t,yd->cookie_y, webaddress, + use_whole_url ? "http://" : "", use_whole_url ? webaddress : "", webpage, yd->cookie_t,yd->cookie_y, webaddress, strlen(content), content); /* We have a URL and some header information, let's connect and update the alias */ - url_data = purple_util_fetch_url_request(url, FALSE, NULL, TRUE, request, FALSE, yahoo_update_alias_cb, cb); + url_data = purple_util_fetch_url_request(url, use_whole_url, NULL, TRUE, request, FALSE, yahoo_update_alias_cb, cb); if (url_data != NULL) { yd->url_datas = g_slist_prepend(yd->url_datas, url_data); } diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/yahoo/yahoo_filexfer.c --- a/libpurple/protocols/yahoo/yahoo_filexfer.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo_filexfer.c Wed Feb 27 04:49:37 2008 +0000 @@ -1033,18 +1033,19 @@ void yahoo_send_file(PurpleConnection *gc, const char *who, const char *file) { struct yahoo_xfer_data *xfer_data; - struct yahoo_data *yd; + struct yahoo_data *yd = gc->proto_data; int ver = 0; PurpleXfer *xfer = yahoo_new_xfer(gc, who); YahooFriend *yf = yahoo_friend_find(gc, who); - /* To determine whether client uses ymsg 15 i.e. client is higher than YM 7 */ - if(yf && yf->version_id > 500000) - ver=15; + /* To determine if we should use yahoo p15 for transfer. Check other user's + * reported version, but if we're on Yahoo Japan, ignore it. */ + if(yf && yf->version_id > 500000 && !yd->jp) + ver = 15; + g_return_if_fail(xfer != NULL); if(ver == 15) { - yd = gc->proto_data; xfer_data = xfer->data; xfer_data->status_15 = STARTED; purple_xfer_set_init_fnc(xfer, yahoo_xfer_init_15); @@ -1320,17 +1321,21 @@ if(!xfer) return; /* - * In the file trans info packet tht we must reply with , we are supposed to mention the ip address... + * In the file trans info packet that we must reply with, we are + * supposed to mention the ip address... * purple connect does not give me a way of finding the ip address... - * so, purple dnsquery is used... but retries, trying with next ip address etc. is not implemented..TODO + * so, purple dnsquery is used... but retries, trying with next ip + * address etc. is not implemented..TODO */ if (yd->jp) { - purple_dnsquery_a(YAHOOJP_XFER_RELAY_HOST, YAHOOJP_XFER_RELAY_PORT, yahoo_xfer_dns_connected_15, xfer); + purple_dnsquery_a(YAHOOJP_XFER_RELAY_HOST, YAHOOJP_XFER_RELAY_PORT, + yahoo_xfer_dns_connected_15, xfer); } else { - purple_dnsquery_a(YAHOO_XFER_RELAY_HOST, YAHOO_XFER_RELAY_PORT, yahoo_xfer_dns_connected_15, xfer); + purple_dnsquery_a(YAHOO_XFER_RELAY_HOST, YAHOO_XFER_RELAY_PORT, + yahoo_xfer_dns_connected_15, xfer); } return; } diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/yahoo/yahoo_picture.c --- a/libpurple/protocols/yahoo/yahoo_picture.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo_picture.c Wed Feb 27 04:49:37 2008 +0000 @@ -116,6 +116,11 @@ struct yahoo_fetch_picture_data *data; PurpleBuddy *b = purple_find_buddy(gc->account, who); const char *locksum = NULL; + gboolean use_whole_url = FALSE; + + /* use whole URL if using HTTP Proxy */ + if ((gc->account->proxy_info) && (gc->account->proxy_info->type == PURPLE_PROXY_HTTP)) + use_whole_url = TRUE; /* FIXME: Cleanup this strtol() stuff if possible. */ if (b && (locksum = purple_buddy_icons_get_checksum_for_user(b)) != NULL && @@ -126,7 +131,7 @@ data->gc = gc; data->who = g_strdup(who); data->checksum = checksum; - url_data = purple_util_fetch_url(url, FALSE, + url_data = purple_util_fetch_url(url, use_whole_url, "Mozilla/4.0 (compatible; MSIE 5.0)", FALSE, yahoo_fetch_picture_cb, data); if (url_data != NULL) { diff -r 00eaff9396ec -r f61f7e8d897e libpurple/protocols/yahoo/yahoo_profile.c --- a/libpurple/protocols/yahoo/yahoo_profile.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo_profile.c Wed Feb 27 04:49:37 2008 +0000 @@ -932,11 +932,17 @@ /* Try to put the photo in there too, if there's one */ if (photo_url_text) { PurpleUtilFetchUrlData *url_data; + gboolean use_whole_url = FALSE; + + /* use whole URL if using HTTP Proxy */ + if ((info_data->gc->account->proxy_info) && (info_data->gc->account->proxy_info->type == PURPLE_PROXY_HTTP)) + use_whole_url = TRUE; + /* User-uploaded photos use a different server that requires the Host * header, but Yahoo Japan will use the "chunked" content encoding if * we specify HTTP 1.1. So we have to specify 1.0 & fix purple_util_fetch_url */ - url_data = purple_util_fetch_url(photo_url_text, FALSE, NULL, + url_data = purple_util_fetch_url(photo_url_text, use_whole_url, NULL, FALSE, yahoo_got_photo, info2_data); if (url_data != NULL) yd->url_datas = g_slist_prepend(yd->url_datas, url_data); diff -r 00eaff9396ec -r f61f7e8d897e libpurple/proxy.c --- a/libpurple/proxy.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/proxy.c Wed Feb 27 04:49:37 2008 +0000 @@ -737,6 +737,7 @@ proxy_do_write(connect_data, connect_data->fd, cond); return; } else if((ntlm = g_strrstr((const char *)connect_data->read_buffer, "Proxy-Authenticate: NTLM"))) { /* Empty message */ + gchar *ntlm_type1; gchar request[2048]; gchar *domain = (gchar*) purple_proxy_info_get_username(connect_data->gpi); gchar *username = NULL; @@ -759,11 +760,13 @@ connect_data->host, connect_data->port); g_return_if_fail(request_len < sizeof(request)); + ntlm_type1 = purple_ntlm_gen_type1(hostname, domain); request_len += g_snprintf(request + request_len, sizeof(request) - request_len, "Proxy-Authorization: NTLM %s\r\n" "Proxy-Connection: Keep-Alive\r\n\r\n", - purple_ntlm_gen_type1(hostname, domain)); + ntlm_type1); + g_free(ntlm_type1); *username = '\\'; purple_input_remove(connect_data->inpa); @@ -847,7 +850,7 @@ if (purple_proxy_info_get_username(connect_data->gpi) != NULL) { - char *t1, *t2; + char *t1, *t2, *ntlm_type1; char hostname[256]; ret = gethostname(hostname, sizeof(hostname)); @@ -864,11 +867,14 @@ t2 = purple_base64_encode((const guchar *)t1, strlen(t1)); g_free(t1); + ntlm_type1 = purple_ntlm_gen_type1(hostname, ""); + g_string_append_printf(request, "Proxy-Authorization: Basic %s\r\n" "Proxy-Authorization: NTLM %s\r\n" "Proxy-Connection: Keep-Alive\r\n", - t2, purple_ntlm_gen_type1(hostname, "")); + t2, ntlm_type1); + g_free(ntlm_type1); g_free(t2); } diff -r 00eaff9396ec -r f61f7e8d897e libpurple/server.c --- a/libpurple/server.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/server.c Wed Feb 27 04:49:37 2008 +0000 @@ -274,6 +274,29 @@ } } +void +purple_serv_got_private_alias(PurpleConnection *gc, const char *who, const char *alias) +{ + PurpleAccount *account = NULL; + GSList *buddies = NULL; + PurpleBuddy *b = NULL; + + account = purple_connection_get_account(gc); + buddies = purple_find_buddies(account, who); + + while(buddies != NULL) { + b = buddies->data; + + buddies = g_slist_delete_link(buddies, buddies); + + if((!b->alias && !alias) || (b->alias && alias && !strcmp(b->alias, alias))) + continue; + + purple_blist_alias_buddy(b, alias); + } +} + + PurpleAttentionType *purple_get_attention_type_from_code(PurpleAccount *account, guint type_code) { PurplePlugin *prpl; diff -r 00eaff9396ec -r f61f7e8d897e libpurple/server.h --- a/libpurple/server.h Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/server.h Wed Feb 27 04:49:37 2008 +0000 @@ -98,6 +98,17 @@ void serv_alias_buddy(PurpleBuddy *); void serv_got_alias(PurpleConnection *gc, const char *who, const char *alias); +/** + * A protocol plugin should call this when it retrieves a private alias from + * the server. Private aliases are the aliases the user sets, while public + * aliases are the aliases or display names that buddies set for themselves. + * + * @param gc The connection on which the alias was received. + * @param who The screen name of the buddy whose alias was received. + * @param alias The alias that was received. + */ +void purple_serv_got_private_alias(PurpleConnection *gc, const char *who, const char *alias); + /** * Receive a typing message from a remote user. Either PURPLE_TYPING diff -r 00eaff9396ec -r f61f7e8d897e libpurple/util.c --- a/libpurple/util.c Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/util.c Wed Feb 27 04:49:37 2008 +0000 @@ -4129,6 +4129,17 @@ return ((c - domain) > 3 ? TRUE : FALSE); } +gboolean +purple_ip_address_is_valid(const char *ip) +{ + int c, o1, o2, o3, o4; + char end; + c = sscanf(ip, "%d.%d.%d.%d%c", &o1, &o2, &o3, &o4, &end); + if (c > 4 || o1 < 0 || o1 > 255 || o2 < 0 || o2 > 255 || o3 < 0 || o3 > 255 || o4 < 0 || o4 > 255) + return FALSE; + return TRUE; +} + /* Stolen from gnome_uri_list_extract_uris */ GList * purple_uri_list_extract_uris(const gchar *uri_list) diff -r 00eaff9396ec -r f61f7e8d897e libpurple/util.h --- a/libpurple/util.h Wed Feb 06 03:35:04 2008 +0000 +++ b/libpurple/util.h Wed Feb 27 04:49:37 2008 +0000 @@ -1081,6 +1081,15 @@ gboolean purple_email_is_valid(const char *address); /** + * Checks if the given IP address is a syntactically valid IPv4 address. + * + * @param address The IP address to validate. + * + * @return True if the IP address is syntactically correct. + */ +gboolean purple_ip_address_is_valid(const char *ip); + +/** * This function extracts a list of URIs from the a "text/uri-list" * string. It was "borrowed" from gnome_uri_list_extract_uris * diff -r 00eaff9396ec -r f61f7e8d897e pidgin/gtkaccount.c --- a/pidgin/gtkaccount.c Wed Feb 06 03:35:04 2008 +0000 +++ b/pidgin/gtkaccount.c Wed Feb 27 04:49:37 2008 +0000 @@ -2092,8 +2092,10 @@ /* Figure out which node was clicked */ if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(dialog->treeview), event->x, event->y, &path, &column, NULL, NULL)) return FALSE; - if (column == gtk_tree_view_get_column(treeview, 0)) + if (column == gtk_tree_view_get_column(treeview, 0)) { + gtk_tree_path_free(path); return FALSE; + } gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, path); gtk_tree_path_free(path); diff -r 00eaff9396ec -r f61f7e8d897e pidgin/gtkblist.c --- a/pidgin/gtkblist.c Wed Feb 06 03:35:04 2008 +0000 +++ b/pidgin/gtkblist.c Wed Feb 27 04:49:37 2008 +0000 @@ -159,6 +159,7 @@ static void pidgin_blist_collapse_contact_cb(GtkWidget *w, PurpleBlistNode *node); static char *pidgin_get_group_title(PurpleBlistNode *gnode, gboolean expanded); static void pidgin_blist_expand_contact_cb(GtkWidget *w, PurpleBlistNode *node); +static void set_urgent(void); typedef enum { PIDGIN_BLIST_NODE_HAS_PENDING_MESSAGE = 1 << 0, /* Whether there's pending message in a conversation */ @@ -2952,6 +2953,9 @@ gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), x, y, &path, NULL, NULL, NULL); gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tv), path, NULL, &rect); + if (path) + gtk_tree_path_free(path); + /* Only autoexpand when in the middle of the cell to avoid annoying un-intended expands */ if (y < rect.y + (rect.height / 3) || y > rect.y + (2 * (rect.height /3))) @@ -2962,8 +2966,6 @@ gtkblist->tip_rect = rect; - if (path) - gtk_tree_path_free(path); gtkblist->drag_timeout = g_timeout_add(delay, (GSourceFunc)pidgin_blist_expand_timeout, tv); if (gtkblist->mouseover_contact) { @@ -4408,6 +4410,7 @@ /***********************************/ #define OBJECT_DATA_KEY_ACCOUNT "account" +#define DO_NOT_CLEAR_ERROR "do-not-clear-error" static gboolean find_account_widget(GObject *widget, @@ -4442,8 +4445,7 @@ PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); gtk_container_add(GTK_CONTAINER(priv->error_scrollbook), dialog); - if (!GTK_WIDGET_HAS_FOCUS(gtkblist->window)) - pidgin_set_urgent(GTK_WINDOW(gtkblist->window), TRUE); + set_urgent(); } static GtkWidget * @@ -4470,6 +4472,11 @@ { GtkWidget *widget = find_child_widget_by_account(container, account); if(widget) { + /* Since we are destroying the widget in response to a change in + * error, we should not clear the error. + */ + g_object_set_data(G_OBJECT(widget), DO_NOT_CLEAR_ERROR, + GINT_TO_POINTER(TRUE)); gtk_widget_destroy(widget); } } @@ -4495,7 +4502,12 @@ PurpleAccount *account) { g_hash_table_remove(gtkblist->connection_errors, account); - purple_account_clear_current_error(account); + /* If the error dialog is being destroyed in response to the + * account-error-changed signal, we don't want to clear the current + * error. + */ + if (g_object_get_data(G_OBJECT(dialog), DO_NOT_CLEAR_ERROR) == NULL) + purple_account_clear_current_error(account); } #define SSL_FAQ_URI "http://d.pidgin.im/wiki/FAQssl" @@ -4571,6 +4583,19 @@ } +static void +update_generic_error_message(PurpleAccount *account, + const char *description) +{ + PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); + GtkWidget *mini_dialog = find_child_widget_by_account( + GTK_CONTAINER(priv->error_scrollbook), account); + pidgin_mini_dialog_set_description(PIDGIN_MINI_DIALOG(mini_dialog), + description); + set_urgent(); +} + + /* Notifications about accounts which were disconnected with * PURPLE_CONNECTION_ERROR_NAME_IN_USE */ @@ -4724,8 +4749,7 @@ update_signed_on_elsewhere_minidialog_title(); - if (!GTK_WIDGET_HAS_FOCUS(gtkblist->window)) - pidgin_set_urgent(GTK_WINDOW(gtkblist->window), TRUE); + set_urgent(); } static void @@ -4742,6 +4766,20 @@ } +static void +update_signed_on_elsewhere_tooltip(PurpleAccount *account, + const char *description) +{ +#if GTK_CHECK_VERSION(2,12,0) + PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist); + GtkContainer *c = GTK_CONTAINER(priv->signed_on_elsewhere->contents); + GtkWidget *label = find_child_widget_by_account(c, account); + gtk_widget_set_tooltip_text(label, description); + set_urgent(); +#endif +} + + /* Call appropriate error notification code based on error types */ static void update_account_error_state(PurpleAccount *account, @@ -4749,35 +4787,60 @@ const PurpleConnectionErrorInfo *new, PidginBuddyList *gtkblist) { + gboolean descriptions_differ; + const char *desc; + + if (old == NULL && new == NULL) + return; + /* For backwards compatibility: */ if (new) pidgin_blist_update_account_error_state(account, new->description); else pidgin_blist_update_account_error_state(account, NULL); - pidgin_blist_select_notebook_page(gtkblist); - /* Don't bother updating the error if it hasn't changed. This stops - * URGENT being repeatedly set for network errors whenever they try to - * reconnect. - */ - if ((old == new) || - (old != NULL && new != NULL && old->type == new->type - && g_str_equal(old->description, new->description)) - ) - return; - - if (old) { + if (new != NULL) + pidgin_blist_select_notebook_page(gtkblist); + + if (old != NULL && new == NULL) { if(old->type == PURPLE_CONNECTION_ERROR_NAME_IN_USE) remove_from_signed_on_elsewhere(account); else remove_generic_error_dialog(account); - } - - if (new) { + return; + } + + if (old == NULL && new != NULL) { if(new->type == PURPLE_CONNECTION_ERROR_NAME_IN_USE) add_to_signed_on_elsewhere(account); else add_generic_error_dialog(account, new); + return; + } + + /* else, new and old are both non-NULL */ + + descriptions_differ = strcmp(old->description, new->description); + desc = new->description; + + switch (new->type) { + case PURPLE_CONNECTION_ERROR_NAME_IN_USE: + if (old->type == PURPLE_CONNECTION_ERROR_NAME_IN_USE + && descriptions_differ) { + update_signed_on_elsewhere_tooltip(account, desc); + } else { + remove_generic_error_dialog(account); + add_to_signed_on_elsewhere(account); + } + break; + default: + if (old->type == PURPLE_CONNECTION_ERROR_NAME_IN_USE) { + remove_from_signed_on_elsewhere(account); + add_generic_error_dialog(account, new); + } else if (descriptions_differ) { + update_generic_error_message(account, desc); + } + break; } } @@ -6740,8 +6803,7 @@ void pidgin_blist_add_alert(GtkWidget *widget) { gtk_container_add(GTK_CONTAINER(gtkblist->scrollbook), widget); - if (!GTK_WIDGET_HAS_FOCUS(gtkblist->window)) - pidgin_set_urgent(GTK_WINDOW(gtkblist->window), TRUE); + set_urgent(); } void @@ -6759,14 +6821,21 @@ gtkblist->headline_data = user_data; gtkblist->headline_destroy = destroy; if (text != NULL || pixbuf != NULL) { - if (!GTK_WIDGET_HAS_FOCUS(gtkblist->window)) - pidgin_set_urgent(GTK_WINDOW(gtkblist->window), TRUE); + set_urgent(); gtk_widget_show_all(gtkblist->headline_hbox); } else { gtk_widget_hide(gtkblist->headline_hbox); } } + +static void +set_urgent(void) +{ + if (!GTK_WIDGET_HAS_FOCUS(gtkblist->window)) + pidgin_set_urgent(GTK_WINDOW(gtkblist->window), TRUE); +} + static PurpleBlistUiOps blist_ui_ops = { pidgin_blist_new_list, diff -r 00eaff9396ec -r f61f7e8d897e pidgin/gtkconv.c --- a/pidgin/gtkconv.c Wed Feb 06 03:35:04 2008 +0000 +++ b/pidgin/gtkconv.c Wed Feb 27 04:49:37 2008 +0000 @@ -238,7 +238,10 @@ switch (purple_conversation_get_type(conv)) { case PURPLE_CONV_TYPE_IM: { - hide_conv(gtkconv, TRUE); + if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/close_immediately")) + close_this_sucker(gtkconv); + else + hide_conv(gtkconv, TRUE); break; } case PURPLE_CONV_TYPE_CHAT: @@ -2803,16 +2806,11 @@ void pidgin_conv_present_conversation(PurpleConversation *conv) { - PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); + PidginConversation *gtkconv; GdkModifierType state; - if (gtkconv == NULL) { - pidgin_conv_attach_to_conversation(conv); - gtkconv = PIDGIN_CONVERSATION(conv); - } else if (gtkconv->win == hidden_convwin) { - pidgin_conv_window_remove_gtkconv(hidden_convwin, gtkconv); - pidgin_conv_placement_place(gtkconv); - } + pidgin_conv_attach_to_conversation(conv); + gtkconv = PIDGIN_CONVERSATION(conv); pidgin_conv_switch_active_conversation(conv); /* Switch the tab only if the user initiated the event by pressing @@ -7641,6 +7639,7 @@ purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons", TRUE); purple_prefs_add_string(PIDGIN_PREFS_ROOT "/conversations/im/hide_new", "never"); + purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/im/close_immediately", TRUE); #ifdef _WIN32 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/win32/minimize_new_convs", FALSE); diff -r 00eaff9396ec -r f61f7e8d897e pidgin/gtkdialogs.c --- a/pidgin/gtkdialogs.c Wed Feb 06 03:35:04 2008 +0000 +++ b/pidgin/gtkdialogs.c Wed Feb 27 04:49:37 2008 +0000 @@ -97,6 +97,7 @@ /* Order: Alphabetical by Last Name */ static const struct developer patch_writers[] = { + {"Felipe 'shx' Contreras", NULL, NULL}, {"Dennis 'EvilDennisR' Ristuccia", N_("Senior Contributor/QA"), NULL}, {"Peter 'Fmoo' Ruibal", NULL, NULL}, {"Elliott 'QuLogic' Sales de Andrade", NULL, NULL}, @@ -121,7 +122,6 @@ /* Order: Alphabetical by Last Name */ static const struct developer retired_patch_writers[] = { - {"Felipe 'shx' Contreras", NULL, NULL}, {"Decklin Foster", NULL, NULL}, {"Peter 'Bleeter' Lawler", NULL, NULL}, {"Robert 'Robot101' McQueen", NULL, NULL}, diff -r 00eaff9396ec -r f61f7e8d897e pidgin/gtklog.c --- a/pidgin/gtklog.c Wed Feb 06 03:35:04 2008 +0000 +++ b/pidgin/gtklog.c Wed Feb 27 04:49:37 2008 +0000 @@ -263,11 +263,10 @@ gtk_tree_store_remove(treestore, iter); } } - gtk_tree_path_free(path); #else gtk_tree_store_remove(treestore, iter); +#endif gtk_tree_path_free(path); -#endif } delete_log_cleanup_cb(data); @@ -363,6 +362,7 @@ gtk_tree_model_get_iter(GTK_TREE_MODEL(lv->treestore), iter, path); val.g_type = 0; gtk_tree_model_get_value(GTK_TREE_MODEL(lv->treestore), iter, 1, &val); + gtk_tree_path_free(path); log = g_value_get_pointer(&val); diff -r 00eaff9396ec -r f61f7e8d897e pidgin/gtkprefs.c --- a/pidgin/gtkprefs.c Wed Feb 06 03:35:04 2008 +0000 +++ b/pidgin/gtkprefs.c Wed Feb 27 04:49:37 2008 +0000 @@ -943,6 +943,8 @@ pidgin_prefs_checkbox(_("Show _formatting on incoming messages"), PIDGIN_PREFS_ROOT "/conversations/show_incoming_formatting", vbox); + pidgin_prefs_checkbox(_("Close IMs immediately when the tab is closed"), + PIDGIN_PREFS_ROOT "/conversations/im/close_immediately", vbox); iconpref1 = pidgin_prefs_checkbox(_("Show _detailed information"), PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons", vbox); @@ -977,6 +979,7 @@ font_name = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/custom_font"); font_button = gtk_font_button_new_with_font(font_name ? font_name : NULL); + gtk_font_button_set_show_style(GTK_FONT_BUTTON(font_button), TRUE); hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Conversation _font:"), NULL, font_button, FALSE, NULL); if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/use_theme_font")) @@ -2194,7 +2197,6 @@ purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/show_group_count"); purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/show_warning_level"); purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/button_type"); - purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/close_immediately"); purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/ctrl_enter_sends"); purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/enter_sends"); purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/escape_closes"); diff -r 00eaff9396ec -r f61f7e8d897e pidgin/minidialog.c --- a/pidgin/minidialog.c Wed Feb 06 03:35:04 2008 +0000 +++ b/pidgin/minidialog.c Wed Feb 27 04:49:37 2008 +0000 @@ -164,7 +164,8 @@ priv->idle_destroy_cb_id = g_idle_add((GSourceFunc) idle_destroy_cb, data->mini_dialog); - data->callback(data->mini_dialog, button, data->user_data); + if (data->callback != NULL) + data->callback(data->mini_dialog, button, data->user_data); } diff -r 00eaff9396ec -r f61f7e8d897e pidgin/pixmaps/logo.png Binary file pidgin/pixmaps/logo.png has changed diff -r 00eaff9396ec -r f61f7e8d897e pidgin/pixmaps/toolbar/16/get-attention.png Binary file pidgin/pixmaps/toolbar/16/get-attention.png has changed diff -r 00eaff9396ec -r f61f7e8d897e po/de.po --- a/po/de.po Wed Feb 06 03:35:04 2008 +0000 +++ b/po/de.po Wed Feb 27 04:49:37 2008 +0000 @@ -11,8 +11,8 @@ msgstr "" "Project-Id-Version: de\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2008-01-23 10:20+0100\n" -"PO-Revision-Date: 2008-01-23 10:19+0100\n" +"POT-Creation-Date: 2008-02-24 19:28+0100\n" +"PO-Revision-Date: 2008-02-24 19:28+0100\n" "Last-Translator: Jochen Kemnade \n" "Language-Team: Deutsch \n" "MIME-Version: 1.0\n" @@ -196,11 +196,11 @@ msgid "Screen Name" msgstr "Benutzername" -msgid "Alias" -msgstr "Alias" - -msgid "Group" -msgstr "Gruppe" +msgid "Alias (optional)" +msgstr "Alias (optional)" + +msgid "Add in group" +msgstr "Zu Gruppe hinzufügen" msgid "Account" msgstr "Konto" @@ -218,6 +218,12 @@ msgid "Name" msgstr "Name" +msgid "Alias" +msgstr "Alias" + +msgid "Group" +msgstr "Gruppe" + msgid "Auto-join" msgstr "Automatisch beitreten" @@ -270,6 +276,9 @@ msgid "Send File" msgstr "Datei versenden" +msgid "Blocked" +msgstr "Blockiert" + msgid "View Log" msgstr "Mitschnitt anzeigen" @@ -335,6 +344,28 @@ msgid "Plugins" msgstr "Plugins" +msgid "Block/Unblock" +msgstr "Sperren/Sperrung aufheben" + +msgid "Block" +msgstr "Sperren" + +msgid "Unblock" +msgstr "Sperrung aufheben" + +msgid "" +"Please enter the screen name or alias of the person you would like to Block/" +"Unblock." +msgstr "" +"Bitte geben Sie den Benutzernamen der Person ein, die Sie blockieren oder " +"für die Sie die Blockierung aufheben wollen." + +#. Not multiline +#. Not masked? +#. No hints? +msgid "OK" +msgstr "OK" + msgid "New Instant Message" msgstr "Neue Sofortnachricht" @@ -343,12 +374,6 @@ msgstr "" "Bitte geben Sie den Benutzernamen der Person ein, mit der Sie chatten wollen." -#. Not multiline -#. Not masked? -#. No hints? -msgid "OK" -msgstr "OK" - msgid "Channel" msgstr "Kanal" @@ -368,6 +393,9 @@ msgid "Send IM..." msgstr "Nachricht senden..." +msgid "Block/Unblock..." +msgstr "Sperren/Sperrung aufheben..." + msgid "Join Chat..." msgstr "Chat betreten..." @@ -582,6 +610,9 @@ msgid "Add Buddy Pounce..." msgstr "Buddy-Alarm hinzufügen..." +msgid "View Log..." +msgstr "Mitschnitt anzeigen.." + msgid "Enable Logging" msgstr "Mitschnitt einschalten" @@ -733,6 +764,58 @@ msgid "Transferring" msgstr "Übertragung" +#, c-format +msgid "Conversation in %s on %s" +msgstr "Unterhaltung in %s am %s" + +#, c-format +msgid "Conversation with %s on %s" +msgstr "Unterhaltung mit %s am %s" + +msgid "%B %Y" +msgstr "%B %Y" + +msgid "" +"System events will only be logged if the \"Log all status changes to system " +"log\" preference is enabled." +msgstr "" +"Systemereignisse werden nur mitgeschnitten, wenn die Option „Schneide alle " +"Statusveränderungen im System-Mitschnitt mit“ aktiviert ist." + +msgid "" +"Instant messages will only be logged if the \"Log all instant messages\" " +"preference is enabled." +msgstr "" +"Sofortnachrichten werden nur mitgeschnitten, wenn die Option „Alle " +"Sofortnachrichten mitschneiden“ aktiviert ist." + +msgid "" +"Chats will only be logged if the \"Log all chats\" preference is enabled." +msgstr "" +"Chats werden nur mitgeschnitten, wenn die Option „Alle Chats mitschneiden“ " +"aktiviert ist." + +msgid "No logs were found" +msgstr "Keine Mitschnitte gefunden" + +msgid "Total log size:" +msgstr "Gesamte Mitschnittgröße:" + +#. Search box ********* +msgid "Scroll/Search: " +msgstr "Scrollen/Suchen: " + +#, c-format +msgid "Conversations in %s" +msgstr "Unterhaltung in %s" + +#, c-format +msgid "Conversations with %s" +msgstr "Unterhaltung mit %s" + +msgid "System Log" +msgstr "System-Mitschnitt" + msgid "Emails" msgstr "E-Mails" @@ -908,7 +991,7 @@ msgid "Play a sound" msgstr "Einen Klang abspielen" -msgid "Pounce only when my status is not available" +msgid "Pounce only when my status is not Available" msgstr "Nur alarmieren, wenn ich nicht verfügbar bin" msgid "Recurring" @@ -1348,6 +1431,9 @@ msgid "Online/Offline" msgstr "Online/Offline" +msgid "Meebo" +msgstr "Meebo" + msgid "No Grouping" msgstr "Keine Gruppierung" @@ -2906,18 +2992,9 @@ msgid "Connection failed." msgstr "Verbindung fehlgeschlagen." -msgid "Blocked" -msgstr "Blockiert" - msgid "Add to chat" msgstr "Zum Chat hinzufügen" -msgid "Unblock" -msgstr "Sperrung aufheben" - -msgid "Block" -msgstr "Sperren" - msgid "Chat _name:" msgstr "Chat_name:" @@ -4455,9 +4532,9 @@ "Kann die Datei nicht an %s senden, Anwesenheit des Benutzers nicht abonniert" #, c-format -msgid "Please select which resource of %s you would like to send a file to" -msgstr "" -"Bitte wählen Sie, welcher Ressource von %s Sie eine Datei schicken möchten" +msgid "Please select the resource of %s to which you would like to send a file" +msgstr "" +"Bitte wählen Sie die Ressource von %s, an die Sie eine Datei schicken möchten" msgid "Select a Resource" msgstr "Wählen Sie eine Ressource" @@ -4741,6 +4818,15 @@ msgid "Page" msgstr "Nachricht" +msgid "Home Phone Number" +msgstr "Private Telefonnummer" + +msgid "Work Phone Number" +msgstr "Geschäftliche Handynummer" + +msgid "Mobile Phone Number" +msgstr "Handynummer" + msgid "Be Right Back" msgstr "Bin gleich zurück" @@ -4753,6 +4839,12 @@ msgid "Out to Lunch" msgstr "Zur Mittagspause" +#. primitive +#. ID +#. name - use default +#. savable +#. should be user_settable some day +#. independent msgid "Artist" msgstr "Interpret" @@ -5227,18 +5319,6 @@ "Benutzen sie libpurple mit RC4-Unterstützung (>= 2.0.1). MySpaceIM-Plugin " "wird nicht geladen." -#, c-format -msgid "" -"Sorry, passwords over %d characters in length (yours is %d) are not " -"supported by MySpace." -msgstr "" -"Passwörter mit mehr als %d Zeichen (Ihres hat %d) werden von MySpace leider " -"nicht unterstützt." - -#. Notify an error message also, because this is important! -msgid "MySpaceIM Error" -msgstr "MySpaceIM-Fehler" - msgid "Reading challenge" msgstr "Lese Challenge" @@ -5272,27 +5352,41 @@ msgid "MySpace" msgstr "MySpace" +msgid "MySpaceIM - No Username Set" +msgstr "MySpaceIM - Kein Benutzername gesetzt" + +msgid "You appear to have no MySpace username." +msgstr "Sie scheinen keinen MySpace-Benutzernamen zu haben." + +msgid "Would you like to set one now? (Note: THIS CANNOT BE CHANGED!)" +msgstr "" +"Möchten Sie jetzt einen setzen? (Bemerkung: DIES KANN NICHT GEÄNDERT WERDEN!)" + #. The session is now set up, ready to be connected. This emits the #. * signedOn signal, so clients can now do anything with msimprpl, and #. * we're ready for it (session key, userid, username all setup). msgid "Connected" msgstr "Verbunden" -msgid "No username set" -msgstr "Kein Benutzername gesetzt" - -msgid "" -"Please go to http://editprofile.myspace.com/index.cfm?fuseaction=profile." -"username and choose a username and try to login again." -msgstr "" -"Bitte besuchen Sie http://editprofile.myspace.com/index.cfm?" -"fuseaction=profile.username und wählen sie einen Benutzernamen und versuchen " -"Sie sich erneut anzumelden." - #, c-format msgid "Protocol error, code %d: %s" msgstr "Protokollfehler, Code %d: %s" +#, c-format +msgid "" +"%s Your password is %d characters, greater than the expected maximum length " +"of %d for MySpaceIM. Please shorten your password at http://profileedit." +"myspace.com/index.cfm?fuseaction=accountSettings.changePassword and try " +"again." +msgstr "" +"%s Ihr Passwort hat %d Buchstaben, mehr als die erwartete maximale Länge von " +"%d für MySpaceIM. Bitte kürzen Sie ihr Passwort unter http://profileedit." +"myspace.com/index.cfm?fuseaction=accountSettings.changePassword und " +"versuchen Sie es erneut." + +msgid "MySpaceIM Error" +msgstr "MySpaceIM-Fehler" + msgid "Failed to add buddy" msgstr "Kontakt konnte nicht hinzugefügt werden" @@ -5321,8 +5415,8 @@ msgid "Invalid input condition" msgstr "Ungültige Eingabebedingung" -msgid "Read buffer full" -msgstr "Lesepuffer voll" +msgid "Read buffer full (2)" +msgstr "Lesepuffer voll (2)" msgid "Unparseable message" msgstr "Kann die Nachricht nicht parsen" @@ -5403,6 +5497,32 @@ msgid "Client Version" msgstr "Client-Version" +#. Protocol won't log in now without a username set.. Disconnect +msgid "No username set" +msgstr "Kein Benutzername gesetzt" + +msgid "MySpaceIM - Please Set a Username" +msgstr "MySpaceIM - Bitte setzen Sie einen Benutzernamen" + +msgid "Please enter a username to check its availability:" +msgstr "" +"Bitte geben Sie einen Benutzernamen ein um seine Verfügbarkeit zu überprüfen:" + +msgid "MySpaceIM - Username Available" +msgstr "MySpaceIM - Benutzername verfügbar" + +msgid "This username is available. Would you like to set it?" +msgstr "Dieser Benutzername ist verfügbar. Möchten Sie ihn setzen?" + +msgid "ONCE SET, THIS CANNOT BE CHANGED!" +msgstr "EINMAL GESETZT, KANN DIES NICHT GEÄNDERT WERDEN!" + +msgid "This username is unavailable." +msgstr "Dieser Benutzername ist nicht verfügbar." + +msgid "Please try another username:" +msgstr "Bitte versuchen Sie einen anderen Benutzernamen:" + #. TODO: icons for each zap #. Lots of comments for translators: #. Zap means "to strike suddenly and forcefully as if with a @@ -6752,12 +6872,6 @@ msgid "Search for Buddy by Information" msgstr "Suche Buddy nach Information" -msgid "Use recent buddies group" -msgstr "Benutze neueste Gruppe" - -msgid "Show how long you have been idle" -msgstr "Anzeigen, wie lange ich untätig war" - msgid "" "Always use AIM/ICQ proxy server for\n" "file transfers and direct IM (slower,\n" @@ -7116,8 +7230,11 @@ msgid "Error requesting login token" msgstr "Fehler beim Abfragen des Anmelde-Tokens" -msgid "Unable to login, check debug log" -msgstr "Anmeldung fehlgeschlagen, Debugmitschnitt beachten" +msgid "Unable to login. Check debug log." +msgstr "Anmeldung fehlgeschlagen, Debugmitschnitt beachten." + +msgid "Unable to login" +msgstr "Anmeldung fehlgeschlagen" #. we didn't successfully connect. tdt->toc_fd is valid here msgid "Unable to connect." @@ -8713,9 +8830,6 @@ msgid "John Noname" msgstr "Max Mustermann" -msgid "Cannot find/access ~/.silc directory" -msgstr "Kann nicht auf das Verzeichnis ~/.silc zugreifen" - #, c-format msgid "Could not load SILC key pair: %s" msgstr "Konnte SILC-Schlüsselpaar nicht laden: %s" @@ -11380,6 +11494,12 @@ msgid "_Smile!" msgstr "_Lächeln!" +msgid "Log Deletion Failed" +msgstr "Löschen des Mitschnitts fehlgeschlagen" + +msgid "Check permissions and try again." +msgstr "Überprüfenb Sie die Berechtigungen und versuchen Sie es erneut." + #, c-format msgid "" "Are you sure you want to permanently delete the log of the conversation with " @@ -11404,6 +11524,12 @@ "Wollen Sie wirklich den System-Mitschnitt, gestartet am %s, permanent " "löschen?" +msgid "Delete Log?" +msgstr "Mitschnitt löschen?" + +msgid "Delete Log..." +msgstr "Mitschnitt löschen..." + #, c-format msgid "Conversation in %s on %s" msgstr "Unterhaltung mit %s am %s" @@ -11412,50 +11538,10 @@ msgid "Conversation with %s on %s" msgstr "Unterhaltung mit %s am %s" -msgid "%B %Y" -msgstr "%B %Y" - -msgid "" -"System events will only be logged if the \"Log all status changes to system " -"log\" preference is enabled." -msgstr "" -"Systemereignisse werden nur mitgeschnitten, wenn die Option „Schneide alle " -"Statusveränderungen im System-Mitschnitt mit“ aktiviert ist." - -msgid "" -"Instant messages will only be logged if the \"Log all instant messages\" " -"preference is enabled." -msgstr "" -"Sofortnachrichten werden nur mitgeschnitten, wenn die Option „Alle " -"Sofortnachrichten mitschneiden“ aktiviert ist." - -msgid "" -"Chats will only be logged if the \"Log all chats\" preference is enabled." -msgstr "" -"Chats werden nur mitgeschnitten, wenn die Option „Alle Chats mitschneiden“ " -"aktiviert ist." - -msgid "No logs were found" -msgstr "Keine Mitschnitte gefunden" - #. Steal the "HELP" response and use it to trigger browsing to the logs folder msgid "_Browse logs folder" msgstr "_Mitschnitt-Ordner anschauen" -msgid "Total log size:" -msgstr "Gesamte Mitschnittgröße:" - -#, c-format -msgid "Conversations in %s" -msgstr "Unterhaltung in %s" - -#, c-format -msgid "Conversations with %s" -msgstr "Unterhaltung mit %s" - -msgid "System Log" -msgstr "System-Mitschnitt" - #, c-format msgid "%s %s. Try `%s -h' for more information.\n" msgstr "%s %s. Versuchen Sie `%s -h' für weitere Informationen.\n" @@ -11783,6 +11869,9 @@ msgid "Show _formatting on incoming messages" msgstr "Zeige _Formatierung bei ankommenden Nachrichten" +msgid "Close IMs immediately when the tab is closed" +msgstr "IMs automatisch schließen, wenn der Reiter geschlossen wird" + msgid "Show _detailed information" msgstr "_Detaillierte Informationen anzeigen" @@ -11905,6 +11994,9 @@ msgid "Konqueror" msgstr "Konqueror" +msgid "Desktop Default" +msgstr "Desktop-Standard" + msgid "GNOME Default" msgstr "GNOME-Standard" @@ -12084,6 +12176,10 @@ msgid "Set privacy for:" msgstr "Setze Privatsphäre für:" +#. Remove All button +msgid "Remove Al_l" +msgstr "A_lle Entfernen" + msgid "Permit User" msgstr "Benutzer erlauben"