summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKa-Hing Cheung <khc@pidgin.im>2008-02-27 04:49:37 +0000
committerKa-Hing Cheung <khc@pidgin.im>2008-02-27 04:49:37 +0000
commitc3340e52d9b1376a45006e0c2d05f575f87420ff (patch)
treef3e3a86acbead9af625ac642fc665e02f8e32c09
parent0db46209071acbf94ed1dde4f4fa66abec07d36b (diff)
parentdc0d9d2415e03b6203f1fa5776fb4b82a058977c (diff)
downloadpidgin-c3340e52d9b1376a45006e0c2d05f575f87420ff.tar.gz
propagate from branch 'im.pidgin.pidgin' (head bd66c165dcad362bffa597c13946e522fdd65421)
to branch 'im.pidgin.pidgin.khc.msnp15' (head dc56b94fffcd71590f08b0120188fc7c36a6c16b)
-rw-r--r--COPYRIGHT3
-rw-r--r--ChangeLog14
-rw-r--r--ChangeLog.API3
-rw-r--r--doc/account-signals.dox3
-rw-r--r--finch/gntblist.c15
-rw-r--r--finch/gntconv.c10
-rw-r--r--finch/libgnt/gntbutton.c3
-rw-r--r--finch/libgnt/gntcombobox.c1
-rw-r--r--finch/libgnt/gntentry.c4
-rw-r--r--finch/libgnt/gntfilesel.c4
-rw-r--r--finch/libgnt/gntmain.c2
-rw-r--r--finch/libgnt/gntmenu.c13
-rw-r--r--finch/libgnt/gnttree.c2
-rw-r--r--finch/libgnt/gntwidget.c2
-rw-r--r--libpurple/account.c19
-rw-r--r--libpurple/blist.c6
-rw-r--r--libpurple/conversation.c7
-rw-r--r--libpurple/protocols/irc/msgs.c5
-rw-r--r--libpurple/protocols/jabber/buddy.c84
-rw-r--r--libpurple/protocols/jabber/jabber.c13
-rw-r--r--libpurple/protocols/msn/notification.c4
-rw-r--r--libpurple/protocols/myspace/message.c43
-rw-r--r--libpurple/protocols/myspace/message.h1
-rw-r--r--libpurple/protocols/myspace/myspace.c114
-rw-r--r--libpurple/protocols/myspace/myspace.h13
-rw-r--r--libpurple/protocols/myspace/persist.h3
-rw-r--r--libpurple/protocols/myspace/user.c298
-rw-r--r--libpurple/protocols/myspace/user.h3
-rw-r--r--libpurple/protocols/oscar/oscar.c10
-rw-r--r--libpurple/protocols/silc/util.c5
-rw-r--r--libpurple/protocols/silc10/util.c5
-rw-r--r--libpurple/protocols/yahoo/yahoo.c57
-rw-r--r--libpurple/protocols/yahoo/yahoo.h11
-rw-r--r--libpurple/protocols/yahoo/yahoo_aliases.c23
-rw-r--r--libpurple/protocols/yahoo/yahoo_filexfer.c23
-rw-r--r--libpurple/protocols/yahoo/yahoo_picture.c7
-rw-r--r--libpurple/protocols/yahoo/yahoo_profile.c8
-rw-r--r--libpurple/proxy.c12
-rw-r--r--libpurple/server.c23
-rw-r--r--libpurple/server.h11
-rw-r--r--libpurple/util.c11
-rw-r--r--libpurple/util.h9
-rw-r--r--pidgin/gtkaccount.c4
-rw-r--r--pidgin/gtkblist.c115
-rw-r--r--pidgin/gtkconv.c17
-rw-r--r--pidgin/gtkdialogs.c2
-rw-r--r--pidgin/gtklog.c4
-rw-r--r--pidgin/gtkprefs.c4
-rw-r--r--pidgin/minidialog.c3
-rw-r--r--pidgin/pixmaps/logo.pngbin28415 -> 26268 bytes
-rw-r--r--pidgin/pixmaps/toolbar/16/get-attention.pngbin0 -> 908 bytes
-rw-r--r--po/de.po290
52 files changed, 1031 insertions, 315 deletions
diff --git a/COPYRIGHT b/COPYRIGHT
index ad2582e654..23f88baade 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -154,6 +154,7 @@ Ryan C. Gordon
Konrad Gräfe
Miah Gregory
David Grohmann
+Gideon N. Guillen
Christian Hammond
Erick Hamness
Fred Hampton
@@ -255,6 +256,7 @@ Arkadiusz Miskiewicz
David Mohr
Andrew Molloy
Michael Monreal
+Marco Monteiro
Benjamin Moody
John Moody
Tim Mooney
@@ -274,6 +276,7 @@ Yusuke Odate
Ruediger Oertel
Gudmundur Bjarni Olafsson
Bartosz Oler
+Oliver
Stefan Ott
Shawn Outman
Nathan Owens (pianocomp81)
diff --git a/ChangeLog b/ChangeLog
index 31ef35dcf6..5baed6e360 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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 @@ version 2.4.0 (??/??/????):
* 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 @@ version 2.4.0 (??/??/????):
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 @@ version 2.4.0 (??/??/????):
* 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 --git a/ChangeLog.API b/ChangeLog.API
index 74ae3c59bf..13b6d324c5 100644
--- a/ChangeLog.API
+++ b/ChangeLog.API
@@ -9,6 +9,7 @@ version 2.4.0 (??/??/????):
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 @@ version 2.4.0 (??/??/????):
* 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 --git a/doc/account-signals.dox b/doc/account-signals.dox
index d48afcd8c0..5d24f2b53d 100644
--- a/doc/account-signals.dox
+++ b/doc/account-signals.dox
@@ -148,7 +148,8 @@ void (*account_authorization_granted)(PurpleAccount *account, const char *user);
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 --git a/finch/gntblist.c b/finch/gntblist.c
index fefb83910f..100b9c107f 100644
--- a/finch/gntblist.c
+++ b/finch/gntblist.c
@@ -601,10 +601,10 @@ finch_request_add_buddy(PurpleAccount *account, const char *username, const char
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 @@ finch_blist_remove_node_cb(PurpleBlistNode *selected, PurpleBlistNode *node)
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 @@ blist_node_compare_log(PurpleBlistNode *n1, PurpleBlistNode *n2)
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 @@ blist_show(PurpleBuddyList *list)
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 --git a/finch/gntconv.c b/finch/gntconv.c
index ae2323094e..f1f18b78c2 100644
--- a/finch/gntconv.c
+++ b/finch/gntconv.c
@@ -805,6 +805,10 @@ finch_write_common(PurpleConversation *conv, const char *who, const char *messag
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 @@ finch_write_common(PurpleConversation *conv, const char *who, const char *messag
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 --git a/finch/libgnt/gntbutton.c b/finch/libgnt/gntbutton.c
index b25db1fd99..090fb5d6bc 100644
--- a/finch/libgnt/gntbutton.c
+++ b/finch/libgnt/gntbutton.c
@@ -79,7 +79,8 @@ gnt_button_map(GntWidget *widget)
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 --git a/finch/libgnt/gntcombobox.c b/finch/libgnt/gntcombobox.c
index 04ff01d786..c012113e23 100644
--- a/finch/libgnt/gntcombobox.c
+++ b/finch/libgnt/gntcombobox.c
@@ -155,6 +155,7 @@ gnt_combo_box_key_pressed(GntWidget *widget, const char *text)
{
case '\r':
case '\t':
+ case '\n':
hide_popup(box, TRUE);
return TRUE;
case 27:
diff --git a/finch/libgnt/gntentry.c b/finch/libgnt/gntentry.c
index a23c0f0b70..61e2a6b6a7 100644
--- a/finch/libgnt/gntentry.c
+++ b/finch/libgnt/gntentry.c
@@ -713,7 +713,7 @@ gnt_entry_key_pressed(GntWidget *widget, const char *text)
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 @@ gnt_entry_key_pressed(GntWidget *widget, const char *text)
return TRUE;
}
- if (text[0] == '\r') {
+ if (text[0] == '\r' || text[0] == '\n') {
gnt_widget_activate(widget);
return TRUE;
}
diff --git a/finch/libgnt/gntfilesel.c b/finch/libgnt/gntfilesel.c
index c46a302818..01bbdf7fd0 100644
--- a/finch/libgnt/gntfilesel.c
+++ b/finch/libgnt/gntfilesel.c
@@ -342,7 +342,7 @@ location_changed(GntFileSel *sel, GError **err)
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 @@ location_key_pressed(GntTree *tree, const char *key, GntFileSel *sel)
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 --git a/finch/libgnt/gntmain.c b/finch/libgnt/gntmain.c
index d67d755cbc..6291805714 100644
--- a/finch/libgnt/gntmain.c
+++ b/finch/libgnt/gntmain.c
@@ -221,7 +221,7 @@ static gboolean
io_invoke(GIOChannel *source, GIOCondition cond, gpointer null)
{
char keys[256];
- int rd;
+ gssize rd;
char *k;
char *cvrt = NULL;
diff --git a/finch/libgnt/gntmenu.c b/finch/libgnt/gntmenu.c
index 388213368f..e81226dc9f 100644
--- a/finch/libgnt/gntmenu.c
+++ b/finch/libgnt/gntmenu.c
@@ -46,6 +46,7 @@ static void (*org_destroy)(GntWidget *wid);
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 @@ gnt_menu_hide(GntWidget *widget)
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 @@ gnt_menu_class_init(GntMenuClass *klass)
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 @@ gnt_menu_class_init(GntMenuClass *klass)
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 --git a/finch/libgnt/gnttree.c b/finch/libgnt/gnttree.c
index 532fdcf2e1..8d8260a8e3 100644
--- a/finch/libgnt/gnttree.c
+++ b/finch/libgnt/gnttree.c
@@ -798,7 +798,7 @@ gnt_tree_key_pressed(GntWidget *widget, const char *text)
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 --git a/finch/libgnt/gntwidget.c b/finch/libgnt/gntwidget.c
index 05bbc6be2c..770c52343a 100644
--- a/finch/libgnt/gntwidget.c
+++ b/finch/libgnt/gntwidget.c
@@ -407,6 +407,8 @@ gnt_widget_clicked(GntWidget *widget, GntMouseEvent event, int x, int y)
{
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 --git a/libpurple/account.c b/libpurple/account.c
index a4acbf7067..0b1e1daeb3 100644
--- a/libpurple/account.c
+++ b/libpurple/account.c
@@ -2368,8 +2368,13 @@ static void
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 @@ connection_error_cb(PurpleConnection *gc,
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 --git a/libpurple/blist.c b/libpurple/blist.c
index ed6c063839..6e7bdf4ee2 100644
--- a/libpurple/blist.c
+++ b/libpurple/blist.c
@@ -1588,7 +1588,7 @@ void purple_blist_add_contact(PurpleContact *contact, PurpleGroup *group, Purple
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 @@ void purple_blist_add_contact(PurpleContact *contact, PurpleGroup *group, Purple
* 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 @@ const char *purple_chat_get_name(PurpleChat *chat)
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 --git a/libpurple/conversation.c b/libpurple/conversation.c
index 772dc5407b..577128267c 100644
--- a/libpurple/conversation.c
+++ b/libpurple/conversation.c
@@ -209,11 +209,14 @@ add_message_to_history(PurpleConversation *conv, const char *who, const char *al
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 --git a/libpurple/protocols/irc/msgs.c b/libpurple/protocols/irc/msgs.c
index 8e46db2969..f9f1048e4e 100644
--- a/libpurple/protocols/irc/msgs.c
+++ b/libpurple/protocols/irc/msgs.c
@@ -495,6 +495,8 @@ void irc_msg_names(struct irc_conn *irc, const char *name, const char *from, cha
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 @@ void irc_msg_mode(struct irc_conn *irc, const char *name, const char *from, char
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 --git a/libpurple/protocols/jabber/buddy.c b/libpurple/protocols/jabber/buddy.c
index 1bc955ee54..024c2749f5 100644
--- a/libpurple/protocols/jabber/buddy.c
+++ b/libpurple/protocols/jabber/buddy.c
@@ -392,6 +392,7 @@ static xmlnode *insert_tag_to_parent_tag(xmlnode *start, const char *parent_tag,
*/
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 @@ void jabber_set_info(PurpleConnection *gc, const char *info)
*/
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];
-
- 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);
+ 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(!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);
+ }
- purple_cipher_digest_region("sha1", avatar_data,
- avatar_len, sizeof(hashval),
- hashval, NULL);
+ 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_imgstore_unref(img);
+ purple_cipher_digest_region("sha1", avatar_data,
+ avatar_len, sizeof(hashval),
+ hashval, NULL);
- p = hash;
- for(i=0; i<20; i++, p+=2)
- snprintf(p, 3, "%02x", hashval[i]);
- js->avatar_hash = g_strdup(hash);
+ purple_imgstore_unref(img);
- xmlnode_insert_data(binval, enc, -1);
- g_free(enc);
- }
+ 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 --git a/libpurple/protocols/jabber/jabber.c b/libpurple/protocols/jabber/jabber.c
index 9600bd6da3..5a098d75aa 100644
--- a/libpurple/protocols/jabber/jabber.c
+++ b/libpurple/protocols/jabber/jabber.c
@@ -564,9 +564,16 @@ static void tls_init(JabberStream *js)
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)
-{
- js->serverFQDN = g_strdup(fqdn);
+static void jabber_login_connect(JabberStream *js, const char *domain, const char *host, int port)
+{
+ /* 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 --git a/libpurple/protocols/msn/notification.c b/libpurple/protocols/msn/notification.c
index 5799b139ab..d841d77cf7 100644
--- a/libpurple/protocols/msn/notification.c
+++ b/libpurple/protocols/msn/notification.c
@@ -1074,7 +1074,7 @@ nln_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
PurpleConnection *gc;
MsnUser *user;
MsnObject *msnobj;
- int clientid;
+ unsigned long clientid;
int wlmclient;
const char *state, *passport, *friendly, *old_friendly;
@@ -1109,7 +1109,7 @@ nln_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
}
}
- 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 --git a/libpurple/protocols/myspace/message.c b/libpurple/protocols/myspace/message.c
index 99244b63a0..ffbf77e5da 100644
--- a/libpurple/protocols/myspace/message.c
+++ b/libpurple/protocols/myspace/message.c
@@ -50,11 +50,12 @@ msim_escape(const gchar *msg)
{
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 @@ msim_unescape(const gchar *msg)
{
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 @@ msim_unescape(const gchar *msg)
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 @@ msim_msg_free_element_data(MsimMessageElement *elem)
* @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(gpointer data, gpointer user_data)
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 @@ msim_send(MsimSession *session, ...)
/** 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 @@ MsimMessage *
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 @@ msim_msg_insert_before(MsimMessage *msg, const gchar *name_before,
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 @@ msim_msg_dictionary_parse(gchar *raw)
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 --git a/libpurple/protocols/myspace/message.h b/libpurple/protocols/myspace/message.h
index dee18f10c5..78c7365c2f 100644
--- a/libpurple/protocols/myspace/message.h
+++ b/libpurple/protocols/myspace/message.h
@@ -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 --git a/libpurple/protocols/myspace/myspace.c b/libpurple/protocols/myspace/myspace.c
index a5238d6448..46aa1edd1d 100644
--- a/libpurple/protocols/myspace/myspace.c
+++ b/libpurple/protocols/myspace/myspace.c
@@ -73,7 +73,7 @@ static gboolean msim_preprocess_incoming(MsimSession *session, MsimMessage *msg)
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 @@ msim_login(PurpleAccount *acct)
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 @@ msim_check_newer_version_cb(PurpleUtilFetchUrlData *url_data,
}
#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 @@ msim_we_are_logged_on(MsimSession *session, MsimMessage *msg)
* 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 @@ msim_we_are_logged_on(MsimSession *session, MsimMessage *msg)
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 @@ msim_process(MsimSession *session, MsimMessage *msg)
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 @@ msim_error(MsimSession *session, MsimMessage *msg)
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 @@ msim_add_contact_from_server_cb(MsimSession *session, MsimMessage *user_lookup_i
* 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 @@ msim_add_contact_from_server_cb(MsimSession *session, MsimMessage *user_lookup_i
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 --git a/libpurple/protocols/myspace/myspace.h b/libpurple/protocols/myspace/myspace.h
index e325f2c27c..973c4eb42c 100644
--- a/libpurple/protocols/myspace/myspace.h
+++ b/libpurple/protocols/myspace/myspace.h
@@ -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 @@ int msim_test_escaping(void);
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 --git a/libpurple/protocols/myspace/persist.h b/libpurple/protocols/myspace/persist.h
index c2091e2a27..b8a09ab55b 100644
--- a/libpurple/protocols/myspace/persist.h
+++ b/libpurple/protocols/myspace/persist.h
@@ -73,7 +73,8 @@ MSIM_PERSIST_DSN_LID(MG_SERVER_INFO, 101, 20)
/** 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 --git a/libpurple/protocols/myspace/user.c b/libpurple/protocols/myspace/user.c
index f234d6c251..7347088554 100644
--- a/libpurple/protocols/myspace/user.c
+++ b/libpurple/protocols/myspace/user.c
@@ -24,6 +24,15 @@ static gchar *msim_format_now_playing(const gchar *band, const gchar *song);
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 @@ msim_is_userid(const gchar *user)
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 @@ msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data,
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 --git a/libpurple/protocols/myspace/user.h b/libpurple/protocols/myspace/user.h
index 6c01d8fd38..633883dc14 100644
--- a/libpurple/protocols/myspace/user.h
+++ b/libpurple/protocols/myspace/user.h
@@ -51,6 +51,9 @@ void msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info
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 --git a/libpurple/protocols/oscar/oscar.c b/libpurple/protocols/oscar/oscar.c
index 99a2df885a..8a553700ee 100644
--- a/libpurple/protocols/oscar/oscar.c
+++ b/libpurple/protocols/oscar/oscar.c
@@ -6609,18 +6609,18 @@ oscar_normalize(const PurpleAccount *account, const char *str)
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 --git a/libpurple/protocols/silc/util.c b/libpurple/protocols/silc/util.c
index 198ad486cc..f6b771167a 100644
--- a/libpurple/protocols/silc/util.c
+++ b/libpurple/protocols/silc/util.c
@@ -442,6 +442,7 @@ void silcpurple_get_umode_string(SilcUInt32 mode, char *buf,
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 @@ void silcpurple_get_chmode_string(SilcUInt32 mode, char *buf,
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 @@ void silcpurple_get_chumode_string(SilcUInt32 mode, char *buf,
strcat(buf, "[blocks robot messages] ");
if (mode & SILC_CHANNEL_UMODE_QUIET)
strcat(buf, "[quieted] ");
+ g_strchomp(buf);
}
void
@@ -544,6 +547,7 @@ silcpurple_parse_attrs(SilcDList attrs, char **moodstr, char **statusstr,
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 @@ silcpurple_parse_attrs(SilcDList attrs, char **moodstr, char **statusstr,
if (strlen(s->str)) {
*contactstr = s->str;
g_string_free(s, FALSE);
+ g_strchomp(*contactstr);
} else
g_string_free(s, TRUE);
diff --git a/libpurple/protocols/silc10/util.c b/libpurple/protocols/silc10/util.c
index 9ef8185579..6cbe5124de 100644
--- a/libpurple/protocols/silc10/util.c
+++ b/libpurple/protocols/silc10/util.c
@@ -432,6 +432,7 @@ void silcpurple_get_umode_string(SilcUInt32 mode, char *buf,
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 @@ void silcpurple_get_chmode_string(SilcUInt32 mode, char *buf,
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 @@ void silcpurple_get_chumode_string(SilcUInt32 mode, char *buf,
strcat(buf, "[blocks robot messages] ");
if (mode & SILC_CHANNEL_UMODE_QUIET)
strcat(buf, "[quieted] ");
+ g_strchomp(buf);
}
void
@@ -534,6 +537,7 @@ silcpurple_parse_attrs(SilcDList attrs, char **moodstr, char **statusstr,
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 @@ silcpurple_parse_attrs(SilcDList attrs, char **moodstr, char **statusstr,
if (strlen(s->str)) {
*contactstr = s->str;
g_string_free(s, FALSE);
+ g_strchomp(*contactstr);
} else
g_string_free(s, TRUE);
diff --git a/libpurple/protocols/yahoo/yahoo.c b/libpurple/protocols/yahoo/yahoo.c
index 5156832f6f..a873a211e8 100644
--- a/libpurple/protocols/yahoo/yahoo.c
+++ b/libpurple/protocols/yahoo/yahoo.c
@@ -1471,13 +1471,24 @@ static void yahoo_process_auth_old(PurpleConnection *gc, const char *seed)
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 @@ static void yahoo_process_auth_new(PurpleConnection *gc, const char *seed)
}
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 @@ static void yahoo_show_inbox(PurplePluginAction *action)
"Host: login.yahoo.com\r\n"
"Content-Length: 0\r\n\r\n",
yd->cookie_t, yd->cookie_y);
+ 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, FALSE,
+ 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 --git a/libpurple/protocols/yahoo/yahoo.h b/libpurple/protocols/yahoo/yahoo.h
index 8150d5c82a..59e2ad9bbf 100644
--- a/libpurple/protocols/yahoo/yahoo.h
+++ b/libpurple/protocols/yahoo/yahoo.h
@@ -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 --git a/libpurple/protocols/yahoo/yahoo_aliases.c b/libpurple/protocols/yahoo/yahoo_aliases.c
index 7c826192bc..9871f2a8b9 100644
--- a/libpurple/protocols/yahoo/yahoo_aliases.c
+++ b/libpurple/protocols/yahoo/yahoo_aliases.c
@@ -148,6 +148,12 @@ yahoo_fetch_aliases(PurpleConnection *gc)
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 @@ yahoo_fetch_aliases(PurpleConnection *gc)
/* 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 @@ yahoo_update_alias(PurpleConnection *gc, const char *who, const char *alias)
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 @@ yahoo_update_alias(PurpleConnection *gc, const char *who, const char *alias)
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 --git a/libpurple/protocols/yahoo/yahoo_filexfer.c b/libpurple/protocols/yahoo/yahoo_filexfer.c
index 6db5ceb863..a2b2a6f440 100644
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.c
@@ -1033,18 +1033,19 @@ static void yahoo_xfer_dns_connected_15(GSList *hosts, gpointer data, const char
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 @@ void yahoo_process_filetrans_15(PurpleConnection *gc, struct yahoo_packet *pkt)
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 --git a/libpurple/protocols/yahoo/yahoo_picture.c b/libpurple/protocols/yahoo/yahoo_picture.c
index 86e8b32964..0f40690963 100644
--- a/libpurple/protocols/yahoo/yahoo_picture.c
+++ b/libpurple/protocols/yahoo/yahoo_picture.c
@@ -116,6 +116,11 @@ void yahoo_process_picture(PurpleConnection *gc, struct yahoo_packet *pkt)
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 @@ void yahoo_process_picture(PurpleConnection *gc, struct yahoo_packet *pkt)
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 --git a/libpurple/protocols/yahoo/yahoo_profile.c b/libpurple/protocols/yahoo/yahoo_profile.c
index f5c9161166..82d0f6a452 100644
--- a/libpurple/protocols/yahoo/yahoo_profile.c
+++ b/libpurple/protocols/yahoo/yahoo_profile.c
@@ -932,11 +932,17 @@ static void yahoo_got_info(PurpleUtilFetchUrlData *url_data, gpointer user_data,
/* 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 --git a/libpurple/proxy.c b/libpurple/proxy.c
index fb9ecc4d6f..f55a8f2f16 100644
--- a/libpurple/proxy.c
+++ b/libpurple/proxy.c
@@ -737,6 +737,7 @@ http_canread(gpointer data, gint source, PurpleInputCondition cond)
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 @@ http_canread(gpointer data, gint source, PurpleInputCondition cond)
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 @@ http_canwrite(gpointer data, gint source, PurpleInputCondition cond)
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 @@ http_canwrite(gpointer data, gint source, PurpleInputCondition cond)
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 --git a/libpurple/server.c b/libpurple/server.c
index 4135d78154..9017204b9e 100644
--- a/libpurple/server.c
+++ b/libpurple/server.c
@@ -274,6 +274,29 @@ serv_got_alias(PurpleConnection *gc, const char *who, const char *alias)
}
}
+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 --git a/libpurple/server.h b/libpurple/server.h
index 348b630c0f..ee4b70ad74 100644
--- a/libpurple/server.h
+++ b/libpurple/server.h
@@ -98,6 +98,17 @@ int serv_chat_send(PurpleConnection *, int, const char *, PurpleMessageFlags fl
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 --git a/libpurple/util.c b/libpurple/util.c
index 08b203f352..3e2c2618b2 100644
--- a/libpurple/util.c
+++ b/libpurple/util.c
@@ -4129,6 +4129,17 @@ purple_email_is_valid(const char *address)
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 --git a/libpurple/util.h b/libpurple/util.h
index f14a1c4cde..36ddf13d2f 100644
--- a/libpurple/util.h
+++ b/libpurple/util.h
@@ -1081,6 +1081,15 @@ const char *purple_url_encode(const char *str);
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 --git a/pidgin/gtkaccount.c b/pidgin/gtkaccount.c
index c4251bd7b1..067725dd82 100644
--- a/pidgin/gtkaccount.c
+++ b/pidgin/gtkaccount.c
@@ -2092,8 +2092,10 @@ account_treeview_double_click_cb(GtkTreeView *treeview, GdkEventButton *event, g
/* 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 --git a/pidgin/gtkblist.c b/pidgin/gtkblist.c
index 7ceab94dc4..4ef585817f 100644
--- a/pidgin/gtkblist.c
+++ b/pidgin/gtkblist.c
@@ -159,6 +159,7 @@ static void redo_buddy_list(PurpleBuddyList *list, gboolean remove, gboolean rer
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 @@ static gboolean pidgin_blist_drag_motion_cb(GtkWidget *tv, GdkDragContext *drag_
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 @@ static gboolean pidgin_blist_drag_motion_cb(GtkWidget *tv, GdkDragContext *drag_
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 @@ headline_box_press_cb(GtkWidget *widget, GdkEventButton *event, PidginBuddyList
/***********************************/
#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 @@ add_error_dialog(PidginBuddyList *gtkblist,
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 @@ remove_child_widget_by_account(GtkContainer *container,
{
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 @@ generic_error_destroy_cb(GtkObject *dialog,
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 @@ remove_generic_error_dialog(PurpleAccount *account)
}
+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 @@ add_to_signed_on_elsewhere(PurpleAccount *account)
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 @@ remove_from_signed_on_elsewhere(PurpleAccount *account)
}
+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 @@ update_account_error_state(PurpleAccount *account,
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 (new != NULL)
+ pidgin_blist_select_notebook_page(gtkblist);
- if (old) {
+ 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);
+ return;
}
- if (new) {
+ 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 @@ pidgin_blist_visibility_manager_remove()
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 @@ pidgin_blist_set_headline(const char *text, GdkPixbuf *pixbuf, GCallback callbac
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 --git a/pidgin/gtkconv.c b/pidgin/gtkconv.c
index 794dddf06b..3bf092e120 100644
--- a/pidgin/gtkconv.c
+++ b/pidgin/gtkconv.c
@@ -238,7 +238,10 @@ close_conv_cb(GtkWidget *w, GdkEventButton *dontuse, PidginConversation *gtkconv
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 @@ icon_menu(GtkObject *obj, GdkEventButton *e, PidginConversation *gtkconv)
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 @@ pidgin_conversations_init(void)
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 --git a/pidgin/gtkdialogs.c b/pidgin/gtkdialogs.c
index 8e74776999..b843970c9d 100644
--- a/pidgin/gtkdialogs.c
+++ b/pidgin/gtkdialogs.c
@@ -97,6 +97,7 @@ static const struct developer developers[] = {
/* 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 @@ static const struct developer retired_developers[] = {
/* 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 --git a/pidgin/gtklog.c b/pidgin/gtklog.c
index a7d40e4004..bcc1b8cd66 100644
--- a/pidgin/gtklog.c
+++ b/pidgin/gtklog.c
@@ -263,11 +263,10 @@ static void delete_log_cb(gpointer *data)
gtk_tree_store_remove(treestore, iter);
}
}
- gtk_tree_path_free(path);
#else
gtk_tree_store_remove(treestore, iter);
- gtk_tree_path_free(path);
#endif
+ gtk_tree_path_free(path);
}
delete_log_cleanup_cb(data);
@@ -363,6 +362,7 @@ static gboolean log_button_press_cb(GtkWidget *treeview, GdkEventButton *event,
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 --git a/pidgin/gtkprefs.c b/pidgin/gtkprefs.c
index be2536b5b2..4c8f0045ed 100644
--- a/pidgin/gtkprefs.c
+++ b/pidgin/gtkprefs.c
@@ -943,6 +943,8 @@ conv_page(void)
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 @@ conv_page(void)
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 @@ void pidgin_prefs_update_old()
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 --git a/pidgin/minidialog.c b/pidgin/minidialog.c
index 19bbd3000c..c638f37437 100644
--- a/pidgin/minidialog.c
+++ b/pidgin/minidialog.c
@@ -164,7 +164,8 @@ mini_dialog_button_clicked_cb(GtkButton *button,
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 --git a/pidgin/pixmaps/logo.png b/pidgin/pixmaps/logo.png
index 0be80c6424..07d3d5a08e 100644
--- a/pidgin/pixmaps/logo.png
+++ b/pidgin/pixmaps/logo.png
Binary files differ
diff --git a/pidgin/pixmaps/toolbar/16/get-attention.png b/pidgin/pixmaps/toolbar/16/get-attention.png
new file mode 100644
index 0000000000..a28738889b
--- /dev/null
+++ b/pidgin/pixmaps/toolbar/16/get-attention.png
Binary files differ
diff --git a/po/de.po b/po/de.po
index 401930b9b6..cb099f5249 100644
--- a/po/de.po
+++ b/po/de.po
@@ -11,8 +11,8 @@ msgid ""
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 <jochenkemnade@web.de>\n"
"Language-Team: Deutsch <de@li.org>\n"
"MIME-Version: 1.0\n"
@@ -196,11 +196,11 @@ msgstr "Fehler beim Hinzufügen des Buddys"
msgid "Screen Name"
msgstr "Benutzername"
-msgid "Alias"
-msgstr "Alias"
+msgid "Alias (optional)"
+msgstr "Alias (optional)"
-msgid "Group"
-msgstr "Gruppe"
+msgid "Add in group"
+msgstr "Zu Gruppe hinzufügen"
msgid "Account"
msgstr "Konto"
@@ -218,6 +218,12 @@ msgstr "Chats"
msgid "Name"
msgstr "Name"
+msgid "Alias"
+msgstr "Alias"
+
+msgid "Group"
+msgstr "Gruppe"
+
msgid "Auto-join"
msgstr "Automatisch beitreten"
@@ -270,6 +276,9 @@ msgstr "Buddy-Alarm hinzufügen"
msgid "Send File"
msgstr "Datei versenden"
+msgid "Blocked"
+msgstr "Blockiert"
+
msgid "View Log"
msgstr "Mitschnitt anzeigen"
@@ -335,13 +344,21 @@ msgstr "Gespeichert..."
msgid "Plugins"
msgstr "Plugins"
-msgid "New Instant Message"
-msgstr "Neue Sofortnachricht"
+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 IM."
+"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, mit der Sie chatten wollen."
+"Bitte geben Sie den Benutzernamen der Person ein, die Sie blockieren oder "
+"für die Sie die Blockierung aufheben wollen."
#. Not multiline
#. Not masked?
@@ -349,6 +366,14 @@ msgstr ""
msgid "OK"
msgstr "OK"
+msgid "New Instant Message"
+msgstr "Neue Sofortnachricht"
+
+msgid ""
+"Please enter the screen name or alias of the person you would like to IM."
+msgstr ""
+"Bitte geben Sie den Benutzernamen der Person ein, mit der Sie chatten wollen."
+
msgid "Channel"
msgstr "Kanal"
@@ -368,6 +393,9 @@ msgstr "Optionen"
msgid "Send IM..."
msgstr "Nachricht senden..."
+msgid "Block/Unblock..."
+msgstr "Sperren/Sperrung aufheben..."
+
msgid "Join Chat..."
msgstr "Chat betreten..."
@@ -582,6 +610,9 @@ msgstr "Zeige Zeitstempel"
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 @@ msgstr "Fertig"
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 @@ msgstr "Einen Befehl ausführen"
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 @@ msgstr "Offline-Buddys"
msgid "Online/Offline"
msgstr "Online/Offline"
+msgid "Meebo"
+msgstr "Meebo"
+
msgid "No Grouping"
msgstr "Keine Gruppierung"
@@ -2906,18 +2992,9 @@ msgstr "Ihre Buddy-Liste wurde auf dem Server gespeichert."
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 @@ msgstr ""
"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"
+msgid "Please select the resource of %s to which you would like to send a file"
msgstr ""
-"Bitte wählen Sie, welcher Ressource von %s Sie eine Datei schicken möchten"
+"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 @@ msgstr "Eine SMS senden."
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 @@ msgstr "Am Telefon"
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 @@ msgstr ""
"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,26 +5352,40 @@ msgstr "Neue Bild-Kommentare"
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"
+#, c-format
+msgid "Protocol error, code %d: %s"
+msgstr "Protokollfehler, Code %d: %s"
+#, c-format
msgid ""
-"Please go to http://editprofile.myspace.com/index.cfm?fuseaction=profile."
-"username and choose a username and try to login again."
+"%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 ""
-"Bitte besuchen Sie http://editprofile.myspace.com/index.cfm?"
-"fuseaction=profile.username und wählen sie einen Benutzernamen und versuchen "
-"Sie sich erneut anzumelden."
+"%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."
-#, c-format
-msgid "Protocol error, code %d: %s"
-msgstr "Protokollfehler, Code %d: %s"
+msgid "MySpaceIM Error"
+msgstr "MySpaceIM-Fehler"
msgid "Failed to add buddy"
msgstr "Kontakt konnte nicht hinzugefügt werden"
@@ -5321,8 +5415,8 @@ msgstr "'blocklist'-Kommando gescheitert"
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 @@ msgstr "Freunde insgesamt"
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 @@ msgstr "Suche Buddys nach E-Mail-Adresse..."
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 @@ msgstr "Fehler beim Aufrechterhalten der Verbindung (Keep alive)"
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 @@ msgstr "Konnte die SILC-Client-Verbindung nicht herstellen"
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 @@ msgstr "_Horizontale Linie"
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 @@ msgstr ""
"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 "<span size='larger' weight='bold'>Conversation in %s on %s</span>"
msgstr "<span size='larger' weight='bold'>Unterhaltung mit %s am %s</span>"
@@ -11412,50 +11538,10 @@ msgstr "<span size='larger' weight='bold'>Unterhaltung mit %s am %s</span>"
msgid "<span size='larger' weight='bold'>Conversation with %s on %s</span>"
msgstr "<span size='larger' weight='bold'>Unterhaltung mit %s am %s</span>"
-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 @@ msgstr "N_eue Unterhaltungen:"
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 @@ msgstr "Mozilla"
msgid "Konqueror"
msgstr "Konqueror"
+msgid "Desktop Default"
+msgstr "Desktop-Standard"
+
msgid "GNOME Default"
msgstr "GNOME-Standard"
@@ -12084,6 +12176,10 @@ msgstr "Einstellungen bzgl. der Privatsphäre werden sofort wirksam."
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"