changeset 27858:a5bb767b8644

propagate from branch 'im.pidgin.pidgin' (head 420b71541a7786d593759ead8d775f487291fb97) to branch 'im.pidgin.pidgin.yaz' (head 63207704bdd62ed93263dbb54f5ede5d640e2e5a)
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Tue, 17 Jun 2008 09:06:41 +0000
parents 85fc34efe733 (diff) 2506d79768b8 (current diff)
children a6721f23d3d9
files libpurple/protocols/jabber/si.c libpurple/protocols/oscar/oscar.c libpurple/util.c pidgin/gtkconv.c pidgin/gtkutils.c
diffstat 25 files changed, 280 insertions(+), 152 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/blist.h	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/blist.h	Tue Jun 17 09:06:41 2008 +0000
@@ -31,13 +31,20 @@
 
 #include <glib.h>
 
+/** @copydoc _PurpleBuddyList */
 typedef struct _PurpleBuddyList PurpleBuddyList;
+/** @copydoc _PurpleBlistUiOps */
 typedef struct _PurpleBlistUiOps PurpleBlistUiOps;
+/** @copydoc _PurpleBlistNode */
 typedef struct _PurpleBlistNode PurpleBlistNode;
 
+/** @copydoc _PurpleChat */
 typedef struct _PurpleChat PurpleChat;
+/** @copydoc _PurpleGroup */
 typedef struct _PurpleGroup PurpleGroup;
+/** @copydoc _PurpleContact */
 typedef struct _PurpleContact PurpleContact;
+/** @copydoc _PurpleBuddy */
 typedef struct _PurpleBuddy PurpleBuddy;
 
 /**************************************************************************/
--- a/libpurple/cmds.h	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/cmds.h	Tue Jun 17 09:06:41 2008 +0000
@@ -30,6 +30,7 @@
 /**************************************************************************/
 /*@{*/
 
+/** The possible results of running a command with purple_cmd_do_command(). */
 typedef enum _PurpleCmdStatus {
 	PURPLE_CMD_STATUS_OK,
 	PURPLE_CMD_STATUS_FAILED,
@@ -39,16 +40,31 @@
 	PURPLE_CMD_STATUS_WRONG_TYPE,
 } PurpleCmdStatus;
 
+/** Commands registered with the core return one of these values when run.
+ *  Normally, a command will want to return one of the first two; in some
+ *  unusual cases, you might want to have several functions called for a
+ *  particular command; in this case, they should return
+ *  #PURPLE_CMD_RET_CONTINUE to cause the core to fall through to other
+ *  commands with the same name.
+ */
 typedef enum _PurpleCmdRet {
-	PURPLE_CMD_RET_OK,       /**< Everything's okay. Don't look for another command to call. */
+	PURPLE_CMD_RET_OK,       /**< Everything's okay; Don't look for another command to call. */
 	PURPLE_CMD_RET_FAILED,   /**< The command failed, but stop looking.*/
 	PURPLE_CMD_RET_CONTINUE, /**< Continue, looking for other commands with the same name to call. */
 } PurpleCmdRet;
 
 #define PURPLE_CMD_FUNC(func) ((PurpleCmdFunc)func)
 
+/** A function implementing a command, as passed to purple_cmd_register().
+ *
+ *  @todo document the arguments to these functions.
+ * */
 typedef PurpleCmdRet (*PurpleCmdFunc)(PurpleConversation *, const gchar *cmd,
                                   gchar **args, gchar **error, void *data);
+/** A unique integer representing a command registered with
+ *  purple_cmd_register(), which can subsequently be passed to
+ *  purple_cmd_unregister() to unregister that command.
+ */
 typedef guint PurpleCmdId;
 
 typedef enum _PurpleCmdPriority {
--- a/libpurple/connection.h	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/connection.h	Tue Jun 17 09:06:41 2008 +0000
@@ -27,6 +27,7 @@
 #ifndef _PURPLE_CONNECTION_H_
 #define _PURPLE_CONNECTION_H_
 
+/** @copydoc _PurpleConnection */
 typedef struct _PurpleConnection PurpleConnection;
 
 /**
@@ -121,7 +122,7 @@
 	 */
 	PURPLE_CONNECTION_ERROR_CERT_OTHER_ERROR = 15,
 
-	/** Some other error occured which fits into none of the other
+	/** Some other error occurred which fits into none of the other
 	 *  categories.
 	 */
 	/* purple_connection_error_reason() in connection.c uses the fact that
@@ -223,6 +224,8 @@
 	void (*_purple_reserved3)(void);
 } PurpleConnectionUiOps;
 
+
+/* Represents an active connection on an account. */
 struct _PurpleConnection
 {
 	PurplePlugin *prpl;            /**< The protocol plugin.               */
--- a/libpurple/conversation.h	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/conversation.h	Tue Jun 17 09:06:41 2008 +0000
@@ -32,11 +32,17 @@
 /**************************************************************************/
 
 
+/** @copydoc _PurpleConversationUiOps */
 typedef struct _PurpleConversationUiOps PurpleConversationUiOps;
+/** @copydoc _PurpleConversation */
 typedef struct _PurpleConversation      PurpleConversation;
+/** @copydoc _PurpleConvIm */
 typedef struct _PurpleConvIm            PurpleConvIm;
+/** @copydoc _PurpleConvChat */
 typedef struct _PurpleConvChat          PurpleConvChat;
+/** @copydoc _PurpleConvChatBuddy */
 typedef struct _PurpleConvChatBuddy     PurpleConvChatBuddy;
+/** @copydoc _PurpleConvMessage */
 typedef struct _PurpleConvMessage       PurpleConvMessage;
 
 /**
--- a/libpurple/core.h	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/core.h	Tue Jun 17 09:06:41 2008 +0000
@@ -1,4 +1,5 @@
 /**
+ * @file core.h Startup and shutdown of libpurple
  * @defgroup core libpurple
  * @see @ref core-signals
  */
@@ -28,12 +29,36 @@
 
 typedef struct PurpleCore PurpleCore;
 
+/** Callbacks that fire at different points of the initialization and teardown
+ *  of libpurple, along with a hook to return descriptive information about the
+ *  UI.
+ */
 typedef struct
 {
+	/** Called just after the preferences subsystem is initialized; the UI
+	 *  could use this callback to add some preferences it needs to be in
+	 *  place when other subsystems are initialized.
+	 */
 	void (*ui_prefs_init)(void);
-	void (*debug_ui_init)(void); /* Unfortunate necessity. */
+	/** Called just after the debug subsystem is initialized, but before
+	 *  just about every other component's initialization.  The UI should
+	 *  use this hook to call purple_debug_set_ui_ops() so that debugging
+	 *  information for other components can be logged during their
+	 *  initialization.
+	 */
+	void (*debug_ui_init)(void);
+	/** Called after all of libpurple has been initialized.  The UI should
+	 *  use this hook to set all other necessary UiOps structures.
+	 *
+	 *  @see @ref ui-ops
+	 */
 	void (*ui_init)(void);
+	/** Called after most of libpurple has been uninitialized. */
 	void (*quit)(void);
+
+	/** Called by purple_core_get_ui_info(); should return the information
+	 *  documented there.
+	 */
 	GHashTable* (*get_ui_info)(void);
 
 	void (*_purple_reserved1)(void);
@@ -64,17 +89,23 @@
 void purple_core_quit(void);
 
 /**
+ * <p>
  * Calls purple_core_quit().  This can be used as the function 
  * passed to purple_timeout_add() when you want to shutdown Purple 
  * in a specified amount of time.  When shutting down Purple 
  * from a plugin, you must use this instead of purple_core_quit();
  * for an immediate exit, use a timeout value of 0: 
- *   purple_timeout_add(0, purple_core_quitcb, NULL);
+ * </p>
+ *
+ * <code>purple_timeout_add(0, purple_core_quitcb, NULL);</code>
+ *
+ * <p>
  * This is ensures that code from your plugin is not being 
  * executed when purple_core_quit() is called.  If the plugin
  * called purple_core_quit() directly, you would get a core dump
  * after purple_core_quit() executes and control returns to your
  * plugin because purple_core_quit() frees all plugins.
+ * </p>
  */
 gboolean purple_core_quit_cb(gpointer unused);
 
@@ -86,7 +117,8 @@
 const char *purple_core_get_version(void);
 
 /**
- * Returns the ID of the UI that is using the core.
+ * Returns the ID of the UI that is using the core, as passed to
+ * purple_core_init().
  *
  * @return The ID of the UI that is currently using the core.
  */
@@ -95,7 +127,7 @@
 /**
  * Returns a handle to the purple core.
  *
- * This is used for such things as signals.
+ * This is used to connect to @ref core-signals "core signals".
  */
 PurpleCore *purple_get_core(void);
 
@@ -114,10 +146,10 @@
 PurpleCoreUiOps *purple_core_get_ui_ops(void);
 
 /**
- * Migrates from .gaim to .purple.
+ * Migrates from <tt>.gaim</tt> to <tt>.purple</tt>.
  *
- * UIs MUST NOT call this if they have been told to use a custom
- * user directory.
+ * UIs <strong>must not</strong> call this if they have been told to use a
+ * custom user directory.
  *
  * @return A boolean indicating success or migration failure. On failure,
  *         the application must display an error to the user and then exit.
@@ -125,20 +157,33 @@
 gboolean purple_core_migrate(void);
 
 /**
- * Ensures that only one instance is running.
+ * Ensures that only one instance is running.  If libpurple is built with D-Bus
+ * support, this checks if another process owns the libpurple bus name and if
+ * so whether that process is using the same configuration directory as this
+ * process.
  *
- * @return A boolean such that @c TRUE indicates that this is the first instance,
- *         whereas @c FALSE indicates that there is another instance running.
+ * @return @c TRUE if this is the first instance of libpurple running;
+ *         @c FALSE if there is another instance running.
  *
  * @since 2.1.0
  */
 gboolean purple_core_ensure_single_instance(void);
 
 /**
- * Returns a hashtable containing various information about the UI
+ * Returns a hash table containing various information about the UI.  The
+ * following well-known entries may be in the table (along with any others the
+ * UI might choose to include):
+ *
+ * <dl>
+ *   <dt><tt>name</tt></dt>
+ *   <dd>the user-readable name for the UI.</dd>
+ *
+ *   <dt><tt>version</tt></dt>
+ *   <dd>a user-readable description of the current version of the UI.</dd>
+ * </dl>
  *
  * @return A GHashTable with strings for keys and values.  This
- * hash table must not be freed.
+ * hash table must not be freed and should not be modified.
  *
  * @since 2.1.0
  *
--- a/libpurple/protocols/gg/search.h	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/protocols/gg/search.h	Tue Jun 17 09:06:41 2008 +0000
@@ -130,7 +130,7 @@
  * @param gc   PurpleConnection.
  * @param form Filled in GGPSearchForm.
  *
- * @return Sequence number of a search or 0 if an error occured.
+ * @return Sequence number of a search or 0 if an error occurred.
  */
 guint32
 ggp_search_start(PurpleConnection *gc, GGPSearchForm *form);
--- a/libpurple/protocols/jabber/buddy.c	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Tue Jun 17 09:06:41 2008 +0000
@@ -1793,22 +1793,6 @@
 	}
 }
 
-void jabber_buddy_get_info_chat(PurpleConnection *gc, int id,
-		const char *resource)
-{
-	JabberStream *js = gc->proto_data;
-	JabberChat *chat = jabber_chat_find_by_id(js, id);
-	char *full_jid;
-
-	if(!chat)
-		return;
-
-	full_jid = g_strdup_printf("%s@%s/%s", chat->room, chat->server, resource);
-	jabber_buddy_get_info_for_jid(js, full_jid);
-	g_free(full_jid);
-}
-
-
 static void jabber_buddy_set_invisibility(JabberStream *js, const char *who,
 		gboolean invisible)
 {
--- a/libpurple/protocols/jabber/buddy.h	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/protocols/jabber/buddy.h	Tue Jun 17 09:06:41 2008 +0000
@@ -96,8 +96,6 @@
 void jabber_buddy_remove_resource(JabberBuddy *jb, const char *resource);
 const char *jabber_buddy_get_status_msg(JabberBuddy *jb);
 void jabber_buddy_get_info(PurpleConnection *gc, const char *who);
-void jabber_buddy_get_info_chat(PurpleConnection *gc, int id,
-		const char *resource);
 
 GList *jabber_blist_node_menu(PurpleBlistNode *node);
 
--- a/libpurple/protocols/jabber/chat.c	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/protocols/jabber/chat.c	Tue Jun 17 09:06:41 2008 +0000
@@ -342,12 +342,18 @@
 {
 	JabberStream *js = gc->proto_data;
 	JabberChat *chat;
+	JabberChatMember *jcm;
 
 	chat = jabber_chat_find_by_id(js, id);
 
 	if(!chat)
 		return NULL;
 
+	jcm = g_hash_table_lookup(chat->members, who);
+	if (jcm != NULL && jcm->jid)
+		return g_strdup(jcm->jid);
+	
+
 	return g_strdup_printf("%s@%s/%s", chat->room, chat->server, who);
 }
 
--- a/libpurple/protocols/jabber/libxmpp.c	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/protocols/jabber/libxmpp.c	Tue Jun 17 09:06:41 2008 +0000
@@ -89,7 +89,7 @@
 	jabber_message_send_chat,		/* chat_send */
 	jabber_keepalive,				/* keepalive */
 	jabber_register_account,		/* register_user */
-	jabber_buddy_get_info_chat,		/* get_cb_info */
+	NULL,							/* get_cb_info */
 	NULL,							/* get_cb_away */
 	jabber_roster_alias_change,		/* alias_buddy */
 	jabber_roster_group_change,		/* group_buddy */
--- a/libpurple/protocols/jabber/pep.h	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/protocols/jabber/pep.h	Tue Jun 17 09:06:41 2008 +0000
@@ -57,7 +57,7 @@
  * @parameter id	The item id of the requested item (may be NULL)
  * @parameter cb	The callback to be used when this item is received
  *
- * The items element passed to the callback will be NULL if any error occured (like a permission error, node doesn't exist etc.)
+ * The items element passed to the callback will be NULL if any error occurred (like a permission error, node doesn't exist etc.)
  */
 void jabber_pep_request_item(JabberStream *js, const char *to, const char *node, const char *id, JabberPEPHandler cb);
 
--- a/libpurple/protocols/jabber/si.c	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/protocols/jabber/si.c	Tue Jun 17 09:06:41 2008 +0000
@@ -625,7 +625,7 @@
 		return;
 	else if(acceptfd == -1) {
 		purple_debug_warning("jabber", "accept: %s\n", g_strerror(errno));
-		/* TODO: This should cancel the ft */
+		/* Don't cancel the ft - allow it to fall to the next streamhost.*/
 		return;
 	}
 
@@ -661,8 +661,11 @@
 
 	jsx = xfer->data;
 
-	if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result"))
+	if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) {
+		if (type && !strcmp(type, "error"))
+			purple_xfer_cancel_remote(xfer);
 		return;
+	}
 
 	if(!(from = xmlnode_get_attrib(packet, "from")))
 		return;
@@ -720,14 +723,17 @@
 	JabberSIXfer *jsx;
 	JabberIq *iq;
 	xmlnode *query, *streamhost;
-	char *jid, port[6];
-	const char *local_ip, *public_ip, *ft_proxies;
+	const char *ft_proxies;
+	char port[6];
 	GList *tmp;
 	JabberBytestreamsStreamhost *sh, *sh2;
+	int streamhost_count = 0;
 
 	jsx = xfer->data;
 	jsx->listen_data = NULL;
 
+	/* I'm not sure under which conditions this can happen
+	 * (it seems like it shouldn't be possible */
 	if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL) {
 		purple_xfer_unref(xfer);
 		return;
@@ -735,13 +741,6 @@
 
 	purple_xfer_unref(xfer);
 
-	if (sock < 0) {
-		purple_xfer_cancel_local(xfer);
-		return;
-	}
-
-	jsx->local_streamhost_fd = sock;
-
 	iq = jabber_iq_new_query(jsx->js, JABBER_IQ_SET,
 			"http://jabber.org/protocol/bytestreams");
 	xmlnode_set_attrib(iq->node, "to", xfer->who);
@@ -749,41 +748,45 @@
 
 	xmlnode_set_attrib(query, "sid", jsx->stream_id);
 
-	jid = g_strdup_printf("%s@%s/%s", jsx->js->user->node,
+	/* If we successfully started listening locally */
+	if (sock >= 0) {
+		gchar *jid;
+		const char *local_ip, *public_ip;
+
+		jsx->local_streamhost_fd = sock;
+
+		jid = g_strdup_printf("%s@%s/%s", jsx->js->user->node,
 			jsx->js->user->domain, jsx->js->user->resource);
-	xfer->local_port = purple_network_get_port_from_fd(sock);
-	g_snprintf(port, sizeof(port), "%hu", xfer->local_port);
-
-	/* TODO: Should there be an option to not use the local host as a ft proxy?
-	 *       (to prevent revealing IP address, etc.) */
+		xfer->local_port = purple_network_get_port_from_fd(sock);
+		g_snprintf(port, sizeof(port), "%hu", xfer->local_port);
 
-	/* Include the localhost's IP (for in-network transfers) */
-	local_ip = purple_network_get_local_system_ip(jsx->js->fd);
-	if (strcmp(local_ip, "0.0.0.0") != 0)
-	{
-		streamhost = xmlnode_new_child(query, "streamhost");
-		xmlnode_set_attrib(streamhost, "jid", jid);
-		xmlnode_set_attrib(streamhost, "host", local_ip);
-		xmlnode_set_attrib(streamhost, "port", port);
+		/* Include the localhost's IP (for in-network transfers) */
+		local_ip = purple_network_get_local_system_ip(jsx->js->fd);
+		if (strcmp(local_ip, "0.0.0.0") != 0) {
+			streamhost_count++;
+			streamhost = xmlnode_new_child(query, "streamhost");
+			xmlnode_set_attrib(streamhost, "jid", jid);
+			xmlnode_set_attrib(streamhost, "host", local_ip);
+			xmlnode_set_attrib(streamhost, "port", port);
+		}
+
+		/* Include the public IP (assuming that there is a port mapped somehow) */
+		public_ip = purple_network_get_my_ip(jsx->js->fd);
+		if (strcmp(public_ip, local_ip) != 0 && strcmp(public_ip, "0.0.0.0") != 0) {
+			streamhost_count++;
+			streamhost = xmlnode_new_child(query, "streamhost");
+			xmlnode_set_attrib(streamhost, "jid", jid);
+			xmlnode_set_attrib(streamhost, "host", public_ip);
+			xmlnode_set_attrib(streamhost, "port", port);
+		}
+
+		g_free(jid);
+
+		/* The listener for the local proxy */
+		xfer->watcher = purple_input_add(sock, PURPLE_INPUT_READ,
+				jabber_si_xfer_bytestreams_send_connected_cb, xfer);
 	}
 
-	/* Include the public IP (assuming that there is a port mapped somehow) */
-	/* TODO: Check that it isn't the same as above and is a valid IP */
-	public_ip = purple_network_get_my_ip(jsx->js->fd);
-	if (strcmp(public_ip, local_ip) != 0)
-	{
-		streamhost = xmlnode_new_child(query, "streamhost");
-		xmlnode_set_attrib(streamhost, "jid", jid);
-		xmlnode_set_attrib(streamhost, "host", public_ip);
-		xmlnode_set_attrib(streamhost, "port", port);
-	}
-
-	g_free(jid);
-
-	/* The listener for the local proxy */
-	xfer->watcher = purple_input_add(sock, PURPLE_INPUT_READ,
-			jabber_si_xfer_bytestreams_send_connected_cb, xfer);
-
 	/* insert proxies here */
 	ft_proxies = purple_account_get_string(xfer->account, "ft_proxies", NULL);
 	if (ft_proxies) {
@@ -808,11 +811,12 @@
 
 			g_snprintf(port, sizeof(port), "%hu", portnum);
 
-			purple_debug_info("jabber", "jabber_si_xfer_bytestreams_listen_cb() will be looking at jsx %p: jsx->streamhosts %p and ft_proxy_list[%i] %p",
+			purple_debug_info("jabber", "jabber_si_xfer_bytestreams_listen_cb() will be looking at jsx %p: jsx->streamhosts %p and ft_proxy_list[%i] %p\n",
 							  jsx, jsx->streamhosts, i, ft_proxy_list[i]);
 			if(g_list_find_custom(jsx->streamhosts, ft_proxy_list[i], jabber_si_compare_jid) != NULL)
 				continue;
 
+			streamhost_count++;
 			streamhost = xmlnode_new_child(query, "streamhost");
 			xmlnode_set_attrib(streamhost, "jid", ft_proxy_list[i]);
 			xmlnode_set_attrib(streamhost, "host", ft_proxy_list[i]);
@@ -842,6 +846,7 @@
 		if(g_list_find_custom(jsx->streamhosts, sh->jid, jabber_si_compare_jid) != NULL)
 			continue;
 
+		streamhost_count++;
 		streamhost = xmlnode_new_child(query, "streamhost");
 		xmlnode_set_attrib(streamhost, "jid", sh->jid);
 		xmlnode_set_attrib(streamhost, "host", sh->host);
@@ -857,6 +862,14 @@
 		jsx->streamhosts = g_list_prepend(jsx->streamhosts, sh2);
 	}
 
+	/* We have no way of transferring, cancel the transfer */
+	if (streamhost_count == 0) {
+		jabber_iq_free(iq);
+		/* We should probably notify the target, but this really shouldn't ever happen */
+		purple_xfer_cancel_local(xfer);
+		return;
+	}
+
 	jabber_iq_set_callback(iq, jabber_si_connect_proxy_cb, xfer);
 
 	jabber_iq_send(iq);
@@ -871,13 +884,14 @@
 	purple_xfer_ref(xfer);
 
 	jsx = xfer->data;
+
+	/* TODO: Should there be an option to not use the local host as a ft proxy?
+	 *       (to prevent revealing IP address, etc.) */
 	jsx->listen_data = purple_network_listen_range(0, 0, SOCK_STREAM,
 				jabber_si_xfer_bytestreams_listen_cb, xfer);
 	if (jsx->listen_data == NULL) {
-		purple_xfer_unref(xfer);
-		/* XXX: couldn't open a port, we're fscked */
-		purple_xfer_cancel_local(xfer);
-		return;
+		/* We couldn't open a local port.  Perhaps we can use a proxy. */
+		jabber_si_xfer_bytestreams_listen_cb(-1, xfer);
 	}
 
 }
@@ -1224,9 +1238,6 @@
 
 	js = gc->proto_data;
 
-	if(!purple_find_buddy(gc->account, who) || !jabber_buddy_find(js, who, FALSE))
-		return;
-
 	xfer = jabber_si_new_xfer(gc, who);
 
 	if (file)
--- a/libpurple/protocols/myspace/user.c	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/protocols/myspace/user.c	Tue Jun 17 09:06:41 2008 +0000
@@ -635,7 +635,7 @@
 	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"
+				"An error occurred 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;
@@ -778,7 +778,7 @@
 	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"
+	errmsg = g_strdup("An error occurred 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.");
 	
--- a/libpurple/protocols/oscar/oscar.c	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Tue Jun 17 09:06:41 2008 +0000
@@ -2005,7 +2005,17 @@
 	}
 	else
 	{
-		purple_prpl_got_user_status(account, info->sn, status_id, NULL);
+		PurpleBuddy *b = purple_find_buddy(account, info->sn);
+		PurplePresence *presence = purple_buddy_get_presence(b);
+		PurpleStatus *old_status = purple_presence_get_active_status(presence);
+		PurpleStatus *new_status = purple_presence_get_status(presence, status_id);
+		
+		/* If our status_id would change with this update, pass it to the core.
+		 * However, if our status_id would not change, do nothing, as we would clear out any existing
+		 * attributes on the status prematurely. purple_got_infoblock() will update the message as needed.
+		 */
+		if (old_status != new_status)
+			purple_prpl_got_user_status(account, info->sn, status_id, NULL);
 	}
 
 	/* Login time stuff */
--- a/libpurple/protocols/qq/send_file.c	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/protocols/qq/send_file.c	Tue Jun 17 09:06:41 2008 +0000
@@ -155,7 +155,7 @@
 	gint size;
 	/* FIXME: It seems that the transfer never use a packet
 	 * larger than 1500 bytes, so if it happened to be a
-	 * larger packet, either error occured or protocol should
+	 * larger packet, either error occurred or protocol should
 	 * be modified
 	 */
 	ft_info *info;
--- a/libpurple/protocols/simple/simple.c	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/protocols/simple/simple.c	Tue Jun 17 09:06:41 2008 +0000
@@ -1898,7 +1898,7 @@
 	PurpleConnection *gc;
 	struct simple_account_data *sip;
 	gchar **userserver;
-	gchar *hosttoconnect;
+	const gchar *hosttoconnect;
 
 	const char *username = purple_account_get_username(account);
 	gc = purple_account_get_connection(account);
@@ -1934,14 +1934,13 @@
 	sip->status = g_strdup("available");
 
 	if(!purple_account_get_bool(account, "useproxy", FALSE)) {
-		hosttoconnect = g_strdup(sip->servername);
+		hosttoconnect = sip->servername;
 	} else {
-		hosttoconnect = g_strdup(purple_account_get_string(account, "proxy", sip->servername));
+		hosttoconnect = purple_account_get_string(account, "proxy", sip->servername);
 	}
 
 	sip->srv_query_data = purple_srv_resolve("sip",
 			sip->udp ? "udp" : "tcp", hosttoconnect, srvresolved, sip);
-	g_free(hosttoconnect);
 }
 
 static void simple_close(PurpleConnection *gc)
--- a/libpurple/prpl.h	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/prpl.h	Tue Jun 17 09:06:41 2008 +0000
@@ -31,6 +31,7 @@
 #define _PURPLE_PRPL_H_
 
 typedef struct _PurplePluginProtocolInfo PurplePluginProtocolInfo;
+/** @copydoc _PurpleAttentionType */
 typedef struct _PurpleAttentionType PurpleAttentionType;
 
 /**************************************************************************/
@@ -99,6 +100,9 @@
 	gboolean secret;
 };
 
+/** Represents "nudges" and "buzzes" that you may send to a buddy to attract
+ *  their attention (or vice-versa).
+ */
 struct _PurpleAttentionType
 {
 	const char *name;                  /**< Shown in GUI elements */
--- a/libpurple/roomlist.h	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/roomlist.h	Tue Jun 17 09:06:41 2008 +0000
@@ -30,6 +30,7 @@
 typedef struct _PurpleRoomlist PurpleRoomlist;
 typedef struct _PurpleRoomlistRoom PurpleRoomlistRoom;
 typedef struct _PurpleRoomlistField PurpleRoomlistField;
+/** @copydoc _PurpleRoomlistUiOps */
 typedef struct _PurpleRoomlistUiOps PurpleRoomlistUiOps;
 
 /**
--- a/libpurple/sound.h	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/sound.h	Tue Jun 17 09:06:41 2008 +0000
@@ -55,6 +55,9 @@
 
 } PurpleSoundEventID;
 
+/** Operations used by the core to request that particular sound files, or the
+ *  sound associated with a particular event, should be played.
+ */
 typedef struct _PurpleSoundUiOps
 {
 	void (*init)(void);
--- a/libpurple/util.c	Thu Jun 12 03:53:43 2008 +0000
+++ b/libpurple/util.c	Tue Jun 17 09:06:41 2008 +0000
@@ -832,6 +832,11 @@
 				if (offset_positive)
 					tzoff *= -1;
 			}
+			else if ((*c == 'Z') && (c = c + 1))
+			{
+				/* 'Z' = Zulu = UTC */
+				tzoff = 0;
+			}
 			else if (utc)
 			{
 				static struct tm tmptm;
--- a/pidgin/gtkconv.c	Thu Jun 12 03:53:43 2008 +0000
+++ b/pidgin/gtkconv.c	Tue Jun 17 09:06:41 2008 +0000
@@ -1537,7 +1537,7 @@
 	PurpleAccount *account;
 	PurpleConnection *gc;
 	PurplePluginProtocolInfo *prpl_info = NULL;
-	char *real_who;
+	gchar *real_who = NULL;
 
 	account = purple_conversation_get_account(conv);
 	g_return_if_fail(account != NULL);
@@ -1550,13 +1550,11 @@
 	if (prpl_info && prpl_info->get_cb_real_name)
 		real_who = prpl_info->get_cb_real_name(gc,
 				purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)), who);
-	else
-		real_who = g_strdup(who);
-
-	if(!real_who)
+
+	if(!who && !real_who)
 		return;
 
-	pidgin_dialogs_im_with_user(account, real_who);
+	pidgin_dialogs_im_with_user(account, real_who ? real_who : who);
 
 	g_free(real_who);
 }
@@ -1595,11 +1593,22 @@
 static void
 menu_chat_send_file_cb(GtkWidget *w, PidginConversation *gtkconv)
 {
+	PurplePluginProtocolInfo *prpl_info;
 	PurpleConversation *conv = gtkconv->active_conv;
 	const char *who = g_object_get_data(G_OBJECT(w), "user_data");
 	PurpleConnection *gc  = purple_conversation_get_gc(conv);
-
-	serv_send_file(gc, who, NULL);
+	gchar *real_who = NULL;
+
+	g_return_if_fail(gc != NULL);
+
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+
+	if (prpl_info && prpl_info->get_cb_real_name)
+		real_who = prpl_info->get_cb_real_name(gc,
+				purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)), who);
+
+	serv_send_file(gc, real_who ? real_who : who, NULL);
+	g_free(real_who);
 }
 
 static void
@@ -1715,23 +1724,34 @@
 
 		if (gc == NULL)
 			gtk_widget_set_sensitive(button, FALSE);
-
-		g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
+		else
+			g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
 
 
 		if (prpl_info && prpl_info->send_file)
 		{
+			gboolean can_receive_file = TRUE;
+
 			button = pidgin_new_item_from_stock(menu, _("Send File"),
 				PIDGIN_STOCK_TOOLBAR_SEND_FILE, G_CALLBACK(menu_chat_send_file_cb),
 				PIDGIN_CONVERSATION(conv), 0, 0, NULL);
 
-			if (gc == NULL || prpl_info == NULL ||
-			    !(!prpl_info->can_receive_file || prpl_info->can_receive_file(gc, who)))
-			{
+			if (gc == NULL || prpl_info == NULL)
+				can_receive_file = FALSE;
+			else {
+				gchar *real_who = NULL;
+				if (prpl_info->get_cb_real_name)
+					real_who = prpl_info->get_cb_real_name(gc,
+						purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)), who);
+				if (!(!prpl_info->can_receive_file || prpl_info->can_receive_file(gc, real_who ? real_who : who)))
+					can_receive_file = FALSE;
+				g_free(real_who);
+			}
+
+			if (!can_receive_file)
 				gtk_widget_set_sensitive(button, FALSE);
-			}
-
-			g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
+			else
+				g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
 		}
 
 
@@ -1744,8 +1764,8 @@
 
 		if (gc == NULL)
 			gtk_widget_set_sensitive(button, FALSE);
-
-		g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
+		else
+			g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
 	}
 
 	if (prpl_info && (prpl_info->get_info || prpl_info->get_cb_info)) {
@@ -1754,8 +1774,8 @@
 
 		if (gc == NULL)
 			gtk_widget_set_sensitive(button, FALSE);
-
-		g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
+		else
+			g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
 	}
 
 	if (prpl_info && prpl_info->get_cb_away) {
@@ -1764,8 +1784,8 @@
 
 		if (gc == NULL)
 			gtk_widget_set_sensitive(button, FALSE);
-
-		g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
+		else
+			g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
 	}
 
 	if (!is_me && prpl_info && !(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
@@ -1778,8 +1798,8 @@
 
 		if (gc == NULL)
 			gtk_widget_set_sensitive(button, FALSE);
-
-		g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
+		else
+			g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
 	}
 
 	button = pidgin_new_item_from_stock(menu, _("Last said"), GTK_STOCK_INDEX,
--- a/pidgin/gtkutils.c	Thu Jun 12 03:53:43 2008 +0000
+++ b/pidgin/gtkutils.c	Tue Jun 17 09:06:41 2008 +0000
@@ -1001,13 +1001,14 @@
 	}
 
 	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(conn->prpl);
+	if (prpl_info != NULL && prpl_info->get_cb_real_name)
+		who = prpl_info->get_cb_real_name(conn, chat, name);
 	if (prpl_info == NULL || prpl_info->get_cb_info == NULL) {
-		pidgin_retrieve_user_info(conn, name);
+		pidgin_retrieve_user_info(conn, who ? who : name);
+		g_free(who);
 		return;
 	}
 
-	if (prpl_info->get_cb_real_name)
-		who = prpl_info->get_cb_real_name(conn, chat, name);
 	show_retrieveing_info(conn, who ? who : name);
 	prpl_info->get_cb_info(conn, chat, name);
 	g_free(who);
--- a/pidgin/plugins/cap/cap.c	Thu Jun 12 03:53:43 2008 +0000
+++ b/pidgin/plugins/cap/cap.c	Tue Jun 17 09:06:41 2008 +0000
@@ -333,7 +333,7 @@
 
 static gboolean max_message_difference_cb(gpointer data) {
 	CapStatistics *stats = data;
-	purple_debug_info("cap", "Max Message Difference timeout occured\n");
+	purple_debug_info("cap", "Max Message Difference timeout occurred\n");
 	insert_cap_failure(stats);
 	stats->timeout_source_id = 0;
 	return FALSE;
--- a/po/de.po	Thu Jun 12 03:53:43 2008 +0000
+++ b/po/de.po	Tue Jun 17 09:06:41 2008 +0000
@@ -12,8 +12,8 @@
 msgstr ""
 "Project-Id-Version: de\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-06-09 20:56+0200\n"
-"PO-Revision-Date: 2008-06-09 20:55+0200\n"
+"POT-Creation-Date: 2008-06-12 18:33+0200\n"
+"PO-Revision-Date: 2008-06-12 18:32+0200\n"
 "Last-Translator: Jochen Kemnade <jochenkemnade@web.de>\n"
 "Language-Team: Deutsch <de@li.org>\n"
 "MIME-Version: 1.0\n"
@@ -6174,11 +6174,11 @@
 msgid "In local permit/deny"
 msgstr "In lokaler erlaubt/verboten-Liste"
 
-msgid "Too evil (sender)"
-msgstr "Zu boshaft (Sender)"
-
-msgid "Too evil (receiver)"
-msgstr "Zu boshaft (Empfänger)"
+msgid "Warning level too high (sender)"
+msgstr "Warnstufe zu hoch (Absender)"
+
+msgid "Warning level too high (receiver)"
+msgstr "Warnstufe zu hoch (Empfänger)"
 
 msgid "User temporarily unavailable"
 msgstr "Benutzer ist temporär nicht verfügbar"
@@ -6538,20 +6538,26 @@
 "überschritten wurde."
 
 #, c-format
-msgid "You missed %hu message from %s because he/she was too evil."
-msgid_plural "You missed %hu messages from %s because he/she was too evil."
+msgid ""
+"You missed %hu message from %s because his/her warning level is too high."
+msgid_plural ""
+"You missed %hu messages from %s because his/her warning level is too high."
 msgstr[0] ""
-"Sie haben %hu Nachricht von %s nicht erhalten, da er/sie zu boshaft war."
+"Sie haben %hu Nachricht von %s nicht erhalten, da seine/ihre Warnstufe zu "
+"hoch ist."
 msgstr[1] ""
-"Sie haben %hu Nachrichten von %s nicht erhalten,/sie zu boshaft war."
-
-#, c-format
-msgid "You missed %hu message from %s because you are too evil."
-msgid_plural "You missed %hu messages from %s because you are too evil."
+"Sie haben %hu Nachrichten von %s nicht erhalten, da seine/ihre Warnstufe zu "
+"hoch ist."
+
+#, c-format
+msgid "You missed %hu message from %s because your warning level is too high."
+msgid_plural ""
+"You missed %hu messages from %s because your warning level is too high."
 msgstr[0] ""
-"Sie haben %hu Nachricht von %s nicht erhalten, da Sie zu boshaft sind."
+"Sie haben %hu Nachricht von %s nicht erhalten, da Ihre Warnstufe zu hoch ist."
 msgstr[1] ""
-"Sie haben %hu Nachrichten von %s nicht erhalten, da Sie zu boshaft sind."
+"Sie haben %hu Nachrichten von %s nicht erhalten, da Ihre Warnstufe zu hoch "
+"ist."
 
 #, c-format
 msgid "You missed %hu message from %s for an unknown reason."
@@ -10263,9 +10269,6 @@
 msgid "/Tools/_Certificates"
 msgstr "/Werkzeuge/_Zertifikate"
 
-msgid "/Tools/Smile_y"
-msgstr "/Werkzeuge/Smile_y"
-
 msgid "/Tools/Plu_gins"
 msgstr "/Werkzeuge/Plu_gins"
 
@@ -10275,6 +10278,9 @@
 msgid "/Tools/Pr_ivacy"
 msgstr "/Werkzeuge/Pri_vatsphäre"
 
+msgid "/Tools/Smile_y"
+msgstr "/Werkzeuge/Smile_y"
+
 msgid "/Tools/_File Transfers"
 msgstr "/Werkzeuge/_Dateiübertragungen"
 
@@ -10508,6 +10514,12 @@
 msgid "Please enter the name of the group to be added."
 msgstr "Bitte geben Sie den Namen der Gruppe ein, die hinzugefügt werden soll."
 
+msgid "Enable Account"
+msgstr "Konten aktivieren"
+
+msgid "<PurpleMain>/Accounts/Enable Account"
+msgstr "<PurpleMain>/Konten/Konto aktivieren"
+
 msgid "<PurpleMain>/Accounts/"
 msgstr "<PurpleMain>/Konten/"
 
@@ -10520,12 +10532,6 @@
 msgid "_Disable"
 msgstr "_Deaktivieren"
 
-msgid "Enable Account"
-msgstr "Konten aktivieren"
-
-msgid "<PurpleMain>/Accounts/Enable Account"
-msgstr "<PurpleMain>/Konten/Konto aktivieren"
-
 msgid "/Tools"
 msgstr "/Werkzeuge"
 
@@ -11559,11 +11565,14 @@
 msgid "Insert Image"
 msgstr "Bild einfügen"
 
-msgid ""
-"This smiley is disabled because a custom smiley exists for this shortcut."
+#, c-format
+msgid ""
+"This smiley is disabled because a custom smiley exists for this shortcut:\n"
+" %s"
 msgstr ""
 "Dieser Smiley ist deaktiviert, da ein benutzerdefinierter Smiley für diese "
-"Tastenkombination existiert."
+"Tastenkombination existiert:\n"
+" %s"
 
 msgid "Smile!"
 msgstr "Lächeln!"
--- a/po/en_GB.po	Thu Jun 12 03:53:43 2008 +0000
+++ b/po/en_GB.po	Tue Jun 17 09:06:41 2008 +0000
@@ -2911,7 +2911,7 @@
 msgstr "Your current password is different from the one that you specified."
 
 msgid "Unable to change password. Error occurred.\n"
-msgstr "Unable to change password. An error occured.\n"
+msgstr "Unable to change password. An error occurred.\n"
 
 msgid "Change password for the Gadu-Gadu account"
 msgstr "Change password for the Gadu-Gadu account"
@@ -5270,7 +5270,7 @@
 msgstr "Message could not be sent because the user is offline:"
 
 msgid "Message could not be sent because a connection error occurred:"
-msgstr "Message could not be sent because a connection error occured:"
+msgstr "Message could not be sent because a connection error occurred:"
 
 msgid "Message could not be sent because we are sending too quickly:"
 msgstr "Message could not be sent because we are sending too quickly:"