changeset 21088:fc80a99f6f40

propagate from branch 'im.pidgin.pidgin' (head ef97aa9259d77504bb07c2dff5ec0750d498e847) to branch 'org.maemo.garage.pidgin.pidgin.dialog-transience' (head 0e5385979f58d6ee74f668bb9b5dfd1ae3b6043f)
author Gabriel Schulhof <nix@go-nix.ca>
date Wed, 10 Oct 2007 23:19:58 +0000
parents 8c9aad9479c0 (current diff) 38b12aff6d5a (diff)
children c3c85233eb4a 5e46cdf9ef2b
files libpurple/protocols/jabber/chat.c libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/usermood.c libpurple/protocols/msn/msn.c libpurple/protocols/oscar/oscar.c libpurple/protocols/qq/buddy_info.c libpurple/protocols/sametime/sametime.c pidgin/gtkaccount.c pidgin/gtkblist.c pidgin/gtklog.c pidgin/gtkutils.c
diffstat 56 files changed, 501 insertions(+), 191 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog.API	Wed Oct 10 22:57:51 2007 +0000
+++ b/ChangeLog.API	Wed Oct 10 23:19:58 2007 +0000
@@ -1,5 +1,12 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+Version 2.2.2 (??/??/????):
+	libpurple:
+		Changed:
+		* The size parameter of purple_util_write_data_to_file_absolute
+		  has been changed to gssize instead of a size_t to correctly
+		  indicate that -1 can be used for a nul-delimited string.
+
 Version 2.2.0 (09/13/2007):
 	libpurple:
 		Added:
@@ -89,9 +96,6 @@
 		* purple_timeout_add_seconds
 		    Callers should prefer this to purple_timeout_add for timers
 		    longer than 1 second away.  Be aware of the rounding, though.
-		* purple_timeout_add_seconds
-		    Callers should prefer this to purple_timeout_add for timers
-		    longer than 1 second away.  Be aware of the rounding, though.
 		* purple_xfer_get_remote_user
 		* purple_pounces_get_all_for_ui
 		* purple_prefs_get_children_names
--- a/doc/conversation-signals.dox	Wed Oct 10 22:57:51 2007 +0000
+++ b/doc/conversation-signals.dox	Wed Oct 10 23:19:58 2007 +0000
@@ -429,6 +429,7 @@
    conversation.
   @param conv   The conversation.
   @param list   A pointer to the list of actions.
+  @since 2.1.0
  @endsignaldef
 */
 // vim: syntax=c.doxygen tw=75 et
--- a/doc/gtkconv-signals.dox	Wed Oct 10 22:57:51 2007 +0000
+++ b/doc/gtkconv-signals.dox	Wed Oct 10 23:19:58 2007 +0000
@@ -127,6 +127,7 @@
   @signaldesc
    Emitted immediately before an existing conversation is hidden.
   @param gtkconv  The PidginConversation
+  @since 2.2.0
  @endsignaldef
 
  @signaldef conversation-displayed
@@ -136,6 +137,7 @@
   @signaldesc
    Emitted right after the Pidgin UI is attached to a new or a hidden conversation.
   @param gtkconv  The PidginConversation
+  @since 2.2.0
  @endsignaldef
 
 */
--- a/doc/notify-signals.dox	Wed Oct 10 22:57:51 2007 +0000
+++ b/doc/notify-signals.dox	Wed Oct 10 23:19:58 2007 +0000
@@ -35,6 +35,7 @@
   @param from      Who the email is from.
   @param to        Who the email is to.
   @param url       A url to view the email.
+  @since 2.1.0
  @endsignaldef
 
  @signaldef displaying-emails-notification
@@ -52,6 +53,7 @@
   @param tos        Who the emails are to.
   @param urls       The urls to view the emails.
   @param count      Number of emails being notified of.
+  @since 2.1.0
  @endsignaldef
 
 */
--- a/finch/gntaccount.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/finch/gntaccount.h	Wed Oct 10 23:19:58 2007 +0000
@@ -59,6 +59,8 @@
  * Show the edit dialog for an account.
  *
  * @param account  The account to edit, or @c NULL to create a new account.
+ *
+ * @since 2.2.0
  */
 void finch_account_dialog_show(PurpleAccount *account);
 
--- a/finch/gntblist.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/finch/gntblist.h	Wed Oct 10 23:19:58 2007 +0000
@@ -98,6 +98,8 @@
  * @param name   The user to get information about.
  *
  * @return  Returns the ui-handle for the userinfo notification.
+ *
+ * @since 2.1.0
  */
 gpointer finch_retrieve_user_info(PurpleConnection *conn, const char *name);
 
--- a/finch/gntsound.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/finch/gntsound.h	Wed Oct 10 23:19:58 2007 +0000
@@ -37,6 +37,8 @@
  * Get the name of the active sound profile.
  *
  * @return The name of the profile
+ *
+ * @since 2.1.0
  */
 const char *finch_sound_get_active_profile(void);
 
@@ -44,6 +46,8 @@
  * Set the active profile.  If the profile doesn't exist, nothing is changed.
  * 
  * @param name  The name of the profile
+ *
+ * @since 2.1.0
  */
 void finch_sound_set_active_profile(const char *name);
 
@@ -52,6 +56,8 @@
  *
  * @return A list of strings denoting sound profile names.
  *         Caller must free the list (but not the data).
+ *
+ * @since 2.1.0
  */
 GList *finch_sound_get_profiles(void);
 
@@ -60,6 +66,8 @@
  *
  * @return Returns FALSE if preference is set to 'No sound', or if volume is
  *         set to zero.
+ *
+ * @since 2.2.0
  */
 gboolean finch_sound_is_enabled(void);
 
@@ -67,11 +75,15 @@
  * Gets GNT sound UI ops.
  *
  * @return The UI operations structure.
+ *
+ * @since 2.1.0
  */
 PurpleSoundUiOps *finch_sound_get_ui_ops(void);
 
 /**
  * Show the sound settings dialog.
+ *
+ * @since 2.1.0
  */
 void finch_sounds_show_all(void);
 
--- a/finch/libgnt/gnt.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/finch/libgnt/gnt.h	Wed Oct 10 23:19:58 2007 +0000
@@ -62,6 +62,14 @@
  */
 gboolean gnt_ascii_only(void);
 
+/**
+ * Present a window. If the event was triggered because of user interaction,
+ * the window is moved to the foreground. Otherwise, the Urgent hint is set.
+ *
+ * @param window   The window the present.
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
+ */
 void gnt_window_present(GntWidget *window);
 /**
  * 
--- a/finch/libgnt/gntslider.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/finch/libgnt/gntslider.h	Wed Oct 10 23:19:58 2007 +0000
@@ -75,6 +75,8 @@
 
 /**
  * @return The GType for GntSlider
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 GType gnt_slider_get_gtype(void);
 
@@ -89,6 +91,8 @@
  * @param min    The minimum value for the slider
  *
  * @return  The newly created slider
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 GntWidget * gnt_slider_new(gboolean orient, int max, int min);
 
@@ -98,6 +102,8 @@
  * @param slider  The slider
  * @param max     The maximum value
  * @param min     The minimum value
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 void gnt_slider_set_range(GntSlider *slider, int max, int min);
 
@@ -106,6 +112,8 @@
  * 
  * @param slider  The slider
  * @param step    The amount for each step
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 void gnt_slider_set_step(GntSlider *slider, int step);
 
@@ -114,6 +122,8 @@
  * 
  * @param slider  The slider
  * @param step    The amount for a small step (for the slider)
+ *
+ * @since 2.2.0
  */
 void gnt_slider_set_small_step(GntSlider *slider, int step);
 
@@ -122,6 +132,8 @@
  * 
  * @param slider  The slider
  * @param step    The amount for a large step (for the slider)
+ *
+ * @since 2.2.0
  */
 void gnt_slider_set_large_step(GntSlider *slider, int step);
 
@@ -133,6 +145,8 @@
  *                 forward, negative to change backward
  *
  * @return   The value of the slider after the change
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 int gnt_slider_advance_step(GntSlider *slider, int steps);
 
@@ -141,6 +155,8 @@
  *
  * @param slider  The slider
  * @param value   The current value
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 void gnt_slider_set_value(GntSlider *slider, int value);
 
@@ -149,6 +165,8 @@
  *
  * @param slider The slider
  *
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 int gnt_slider_get_value(GntSlider *slider);
 
@@ -157,6 +175,8 @@
  *
  * @param slider   The slider
  * @param label    The label to update
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 void gnt_slider_reflect_label(GntSlider *slider, GntLabel *label);
 
--- a/finch/libgnt/gntstyle.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/finch/libgnt/gntstyle.h	Wed Oct 10 23:19:58 2007 +0000
@@ -53,6 +53,8 @@
  * @param key     The key
  *
  * @return  The value of the setting as a string, or @c NULL
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 char *gnt_style_get_from_name(const char *group, const char *key);
 
@@ -62,6 +64,8 @@
  *
  * @param value   The value of the boolean setting as a string
  * @return    The boolean value
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 gboolean gnt_style_parse_bool(const char *value);
 
--- a/finch/libgnt/gnttextview.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/finch/libgnt/gnttextview.h	Wed Oct 10 23:19:58 2007 +0000
@@ -204,6 +204,8 @@
  *
  * @param view  The textview widget
  * @param flag  The flag to set
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 void gnt_text_view_set_flag(GntTextView *view, GntTextViewFlag flag);
 
--- a/finch/libgnt/gnttree.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/finch/libgnt/gnttree.h	Wed Oct 10 23:19:58 2007 +0000
@@ -383,6 +383,8 @@
  *
  * @see gnt_tree_set_column_titles
  * @see gnt_tree_set_show_title
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 void gnt_tree_set_column_title(GntTree *tree, int index, const char *title);
 
@@ -486,6 +488,8 @@
  *
  * @see gnt_tree_set_col_width
  * @see gnt_tree_set_column_width_ratio
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 void gnt_tree_set_column_resizable(GntTree *tree, int col, gboolean res);
 
@@ -505,6 +509,8 @@
  * @param tree  The tree
  * @param col   The index of the column
  * @param right @c TRUE if the text in the column should be right aligned
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 void gnt_tree_set_column_is_right_aligned(GntTree *tree, int col, gboolean right);
 
@@ -519,6 +525,8 @@
  *
  * @see gnt_tree_set_col_width
  * @see gnt_tree_set_column_resizable
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 void gnt_tree_set_column_width_ratio(GntTree *tree, int cols[]);
 
@@ -527,6 +535,8 @@
  *
  * @param tree   The tree
  * @param col    The index of the column
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 void gnt_tree_set_search_column(GntTree *tree, int col);
 
@@ -535,6 +545,8 @@
  *
  * @param tree   The tree
  * @return  @c TRUE if the user is searching, @c FALSE otherwise.
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 gboolean gnt_tree_is_searching(GntTree *tree);
 
@@ -547,6 +559,8 @@
  *              string and the content of row in the search column.
  *              If the function returns @c TRUE, the row is dislayed,
  *              otherwise it's not.
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 void gnt_tree_set_search_function(GntTree *tree,
 		gboolean (*func)(GntTree *tree, gpointer key, const char *search, const char *current));
--- a/finch/libgnt/gntutils.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/finch/libgnt/gntutils.h	Wed Oct 10 23:19:58 2007 +0000
@@ -139,6 +139,8 @@
  * @param string   The XHTML string
  * @param tv       The GntTextView
  * @return  @c TRUE if the string was added to the textview properly, @c FALSE otherwise.
+ *
+ * @since 2.2.0
  */
 gboolean gnt_util_parse_xhtml_to_textview(const char *string, GntTextView *tv);
 
@@ -148,6 +150,8 @@
  * @param widget  The widget
  * @param key     The key to trigger the button
  * @param button  The button to trigger
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
  */
 void gnt_util_set_trigger_widget(GntWidget *wid, const char *text, GntWidget *button);
 
--- a/finch/libgnt/gntwm.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/finch/libgnt/gntwm.c	Wed Oct 10 23:19:58 2007 +0000
@@ -1717,12 +1717,11 @@
 void gnt_wm_window_close(GntWM *wm, GntWidget *widget)
 {
 	GntWS *s;
-	GntNode *node;
 	int pos;
 
 	s = gnt_wm_widget_find_workspace(wm, widget);
 
-	if ((node = g_hash_table_lookup(wm->nodes, widget)) == NULL)
+	if (g_hash_table_lookup(wm->nodes, widget) == NULL)
 		return;
 
 	g_signal_emit(wm, signals[SIG_CLOSE_WIN], 0, widget);
--- a/finch/libgnt/gntws.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/finch/libgnt/gntws.h	Wed Oct 10 23:19:58 2007 +0000
@@ -69,18 +69,112 @@
 
 G_BEGIN_DECLS
 
+/**
+ * @return The GType for GntWS.
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
+ */
 GType gnt_ws_get_gtype(void);
 
+/**
+ * Create a new workspace with the specified name.
+ *
+ * @param name  The desired name of the workspace, or @c NULL.
+ *
+ * @return The newly created workspace.
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
+ */
 GntWS *gnt_ws_new(const char *name);
+
+/**
+ * Set the name of a workspace.
+ *
+ * @param ws    The workspace to rename.
+ * @param name  The new name of the workspace.
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
+ */
 void gnt_ws_set_name(GntWS *ws, const gchar *name);
+
+/**
+ * Add a widget to a workspace.
+ *
+ * @param ws     The workspace.
+ * @param widget The widget to add.
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
+ */
 void gnt_ws_add_widget(GntWS *ws, GntWidget *widget);
+
+/**
+ * Remove a widget from a workspace.
+ *
+ * @param ws      The workspace
+ * @param widget  The widget to remove from the workspace.
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
+ */
 void gnt_ws_remove_widget(GntWS *ws, GntWidget *widget);
+
+/**
+ * Hide a widget in a workspace.
+ *
+ * @param widget  The widget to hide.
+ * @param nodes   A hashtable containing information about the widgets.
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
+ */
 void gnt_ws_widget_hide(GntWidget *widget, GHashTable *nodes);
+
+/**
+ * Show a widget in a workspace.
+ *
+ * @param widget   The widget to show.
+ * @param nodes   A hashtable containing information about the widgets.
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
+ */
 void gnt_ws_widget_show(GntWidget *widget, GHashTable *nodes);
+
+/**
+ * Draw the taskbar in a workspace.
+ *
+ * @param ws         The workspace.
+ * @param reposition Whether the workspace should reposition the taskbar.
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
+ */
 void gnt_ws_draw_taskbar(GntWS *ws, gboolean reposition);
+
+/**
+ * Hide a workspace.
+ *
+ * @param ws      The workspace to hide.
+ * @param table   A hashtable containing information about the widgets.
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
+ */
 void gnt_ws_hide(GntWS *ws, GHashTable *table);
+
+/**
+ * Show a workspace.
+ *
+ * @param ws      The workspace to hide.
+ * @param table   A hashtable containing information about the widgets.
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
+ */
 void gnt_ws_show(GntWS *ws, GHashTable *table);
 
+/**
+ * Get the name of a workspace.
+ *
+ * @param ws   The workspace.
+ * @return  The name of the workspace (can be @c NULL).
+ *
+ * @since 2.0.0 (gnt), 2.1.0 (pidgin)
+ */
 const char * gnt_ws_get_name(GntWS *ws);
 
 #endif
--- a/finch/libgnt/test/Makefile	Wed Oct 10 22:57:51 2007 +0000
+++ b/finch/libgnt/test/Makefile	Wed Oct 10 23:19:58 2007 +0000
@@ -1,5 +1,5 @@
 CC=gcc
-CFLAGS=`pkg-config --cflags gobject-2.0 gmodule-2.0` -g -I../ -DSTANDALONE
+CFLAGS=`pkg-config --cflags gobject-2.0 gmodule-2.0` -g -I../ -DSTANDALONE -I/usr/inclue/ncursesw/
 LDFLAGS=`pkg-config --libs gobject-2.0 gmodule-2.0 gnt` -pg
 
 EXAMPLES=combo focus tv multiwin keys menu parse
--- a/libpurple/certificate.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/certificate.h	Wed Oct 10 23:19:58 2007 +0000
@@ -2,6 +2,7 @@
  * @file certificate.h Public-Key Certificate API
  * @ingroup core
  * @see @ref certificate-signals
+ * @since 2.2.0
  */
 
 /*
--- a/libpurple/conversation.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/conversation.h	Wed Oct 10 23:19:58 2007 +0000
@@ -285,6 +285,8 @@
 
 /**
  * Description of a conversation message
+ *
+ * @since 2.2.0
  */
 struct _PurpleConvMessage
 {
@@ -670,6 +672,8 @@
  * @return  A GList of PurpleConvMessage's. The must not modify the list or the data within.
  *          The list contains the newest message at the beginning, and the oldest message at
  *          the end.
+ *
+ * @since 2.2.0
  */
 GList *purple_conversation_get_message_history(PurpleConversation *conv);
 
@@ -677,6 +681,8 @@
  * Clear the message history of a conversation.
  *
  * @param conv  The conversation
+ *
+ * @since 2.2.0
  */
 void purple_conversation_clear_message_history(PurpleConversation *conv);
 
@@ -686,6 +692,8 @@
  * @param msg   A PurpleConvMessage
  *
  * @return   The name of the sender of the message
+ *
+ * @since 2.2.0
  */
 const char *purple_conversation_message_get_sender(PurpleConvMessage *msg);
 
@@ -695,6 +703,8 @@
  * @param msg   A PurpleConvMessage
  *
  * @return   The name of the sender of the message
+ *
+ * @since 2.2.0
  */
 const char *purple_conversation_message_get_message(PurpleConvMessage *msg);
 
@@ -704,6 +714,8 @@
  * @param msg   A PurpleConvMessage
  *
  * @return   The name of the sender of the message
+ *
+ * @since 2.2.0
  */
 PurpleMessageFlags purple_conversation_message_get_flags(PurpleConvMessage *msg);
 
@@ -713,6 +725,8 @@
  * @param msg   A PurpleConvMessage
  *
  * @return   The name of the sender of the message
+ *
+ * @since 2.2.0
  */
 time_t purple_conversation_message_get_timestamp(PurpleConvMessage *msg);
 
@@ -1318,6 +1332,8 @@
  * @return  A list of PurpleMenuAction items, harvested by the
  *          chat-extended-menu signal. The list and the menuaction
  *          items should be freed by the caller.
+ *
+ * @since 2.1.0
  */
 GList * purple_conversation_get_extended_menu(PurpleConversation *conv);
 
@@ -1331,6 +1347,8 @@
  *                message, if not @c NULL. It must be freed by the caller with g_free().
  *
  * @return  @c TRUE if the command was executed successfully, @c FALSE otherwise.
+ *
+ * @since 2.1.0
  */
 gboolean purple_conversation_do_command(PurpleConversation *conv, const gchar *cmdline, const gchar *markup, gchar **error);
 
--- a/libpurple/eventloop.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/eventloop.h	Wed Oct 10 23:19:58 2007 +0000
@@ -138,6 +138,8 @@
  * @param data		data to pass to @a function.
  * @return A handle to the timer which can be passed to 
  *         purple_timeout_remove to remove the timer.
+ *
+ * @since 2.1.0
  */
 guint purple_timeout_add_seconds(guint interval, GSourceFunc function, gpointer data);
 
--- a/libpurple/ft.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/ft.h	Wed Oct 10 23:19:58 2007 +0000
@@ -242,6 +242,8 @@
  * @param xfer The file transfer.
  *
  * @return The name of the remote user.
+ *
+ * @since 2.1.0
  */
 const char *purple_xfer_get_remote_user(const PurpleXfer *xfer);
 
--- a/libpurple/pluginpref.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/pluginpref.h	Wed Oct 10 23:19:58 2007 +0000
@@ -35,16 +35,16 @@
  */
 typedef enum
 {
-	PURPLE_STRING_FORMAT_TYPE_NONE      = 0,
-	PURPLE_STRING_FORMAT_TYPE_MULTILINE = 1 << 0,
-	PURPLE_STRING_FORMAT_TYPE_HTML      = 1 << 1
+	PURPLE_STRING_FORMAT_TYPE_NONE      = 0,          /**< The string is plain text. */
+	PURPLE_STRING_FORMAT_TYPE_MULTILINE = 1 << 0,     /**< The string can have newlines. */
+	PURPLE_STRING_FORMAT_TYPE_HTML      = 1 << 1      /**< The string can be in HTML. */
 } PurpleStringFormatType;
 
 typedef enum {
 	PURPLE_PLUGIN_PREF_NONE,
 	PURPLE_PLUGIN_PREF_CHOICE,
-	PURPLE_PLUGIN_PREF_INFO,   /**< no-value label */
-	PURPLE_PLUGIN_PREF_STRING_FORMAT
+	PURPLE_PLUGIN_PREF_INFO,              /**< no-value label */
+	PURPLE_PLUGIN_PREF_STRING_FORMAT      /**< The preference has a string value. */
 } PurplePluginPrefType;
 
 #include <glib.h>
--- a/libpurple/plugins/log_reader.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/plugins/log_reader.c	Wed Oct 10 23:19:58 2007 +0000
@@ -1939,13 +1939,11 @@
 	g_return_val_if_fail(data->path != NULL, g_strdup(""));
 	g_return_val_if_fail(data->length > 0, g_strdup(""));
 
-	error = NULL;
-	
-	contents = g_malloc(data->length + 2);
-
 	file = g_fopen(data->path, "rb");
 	g_return_val_if_fail(file != NULL, g_strdup(""));
-	
+
+	contents = g_malloc(data->length + 2);
+
 	fseek(file, data->offset, SEEK_SET);
 	fread(contents, data->length, 1, file);
 	fclose(file);
@@ -2026,7 +2024,7 @@
 					g_string_append(formatted, "</font> ");
 
 					if (is_in_message) {
-						if (buddy_name != NULL && buddy->alias) {
+						if (buddy_name != NULL && buddy != NULL && buddy->alias) {
 							g_string_append_printf(formatted,
 								"<span style=\"color: #A82F2F;\">"
 								"<b>%s</b></span>: ", buddy->alias);
@@ -2056,7 +2054,9 @@
 				g_string_append(formatted, line);
 				g_string_append(formatted, "<br>");
 			}
-			line = ++c;
+
+			if (c)
+				line = ++c;
 		}
 	}
 	g_free(contents);
--- a/libpurple/plugins/ssl/ssl-gnutls.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/plugins/ssl/ssl-gnutls.c	Wed Oct 10 23:19:58 2007 +0000
@@ -884,7 +884,7 @@
 	gnutls_x509_crt crt_dat;
 	/* GnuTLS time functions return this on error */
 	const time_t errval = (time_t) (-1);
-
+	gboolean success = TRUE;
 
 	g_return_val_if_fail(crt, FALSE);
 	g_return_val_if_fail(crt->scheme == &x509_gnutls, FALSE);
@@ -893,16 +893,16 @@
 
 	if (activation) {
 		*activation = gnutls_x509_crt_get_activation_time(crt_dat);
+		if (*activation == errval)
+			success = FALSE;
 	}
 	if (expiration) {
 		*expiration = gnutls_x509_crt_get_expiration_time(crt_dat);
+		if (*expiration == errval)
+			success = FALSE;
 	}
 
-	if (*activation == errval || *expiration == errval) {
-		return FALSE;
-	}
-
-	return TRUE;
+	return success;
 }
 
 /* X.509 certificate operations provided by this plugin */
--- a/libpurple/prefs.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/prefs.h	Wed Oct 10 23:19:58 2007 +0000
@@ -291,6 +291,8 @@
  * @return A list of newly allocated strings denoting the names of the children.
  *         Returns @c NULL if there are no children or if pref doesn't exist.
  *         The caller must free all the strings and the list.
+ *
+ * @since 2.1.0
  */
 GList *purple_prefs_get_children_names(const char *name);
 
--- a/libpurple/protocols/bonjour/parser.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/bonjour/parser.c	Wed Oct 10 23:19:58 2007 +0000
@@ -64,7 +64,7 @@
 			char *attrib_ns = NULL;
 
 			if (attributes[i+2]) {
-				attrib_ns = g_strdup((char*)attributes[i+2]);;
+				attrib_ns = g_strdup((char*)attributes[i+2]);
 			}
 
 			memcpy(attrib, attributes[i+3], attrib_len);
--- a/libpurple/protocols/jabber/chat.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/jabber/chat.c	Wed Oct 10 23:19:58 2007 +0000
@@ -964,7 +964,7 @@
 static void jabber_chat_disco_traffic_cb(JabberStream *js, xmlnode *packet, gpointer data)
 {
 	JabberChat *chat;
-	xmlnode *query;
+	/*xmlnode *query;*/
 	int id = GPOINTER_TO_INT(data);
 
 	if(!(chat = jabber_chat_find_by_id(js, id)))
@@ -974,6 +974,8 @@
 	 * support this request */
 	chat->xhtml = TRUE;
 
+	/* disabling this until more MUC servers support
+	 * announcing this
 	if(xmlnode_get_child(packet, "error")) {
 		return;
 	}
@@ -981,8 +983,6 @@
 	if(!(query = xmlnode_get_child(packet, "query")))
 		return;
 
-	/* disabling this until more MUC servers support
-	 * announcing this
 	chat->xhtml = FALSE;
 
 	for(x = xmlnode_get_child(query, "feature"); x; x = xmlnode_get_next_twin(x)) {
--- a/libpurple/protocols/jabber/google.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/jabber/google.c	Wed Oct 10 23:19:58 2007 +0000
@@ -110,7 +110,7 @@
 		tos[i] = (to_name != NULL ?  to_name : "");
 		froms[i] = (from != NULL ?  from : "");
 		subjects[i] = (subject != NULL ? subject : g_strdup(""));
-		urls[i] = (url != NULL ? url : "");
+		urls[i] = url;
 
 		tid = xmlnode_get_attrib(message, "tid");
 		if (tid &&
--- a/libpurple/protocols/jabber/iq.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/jabber/iq.c	Wed Oct 10 23:19:58 2007 +0000
@@ -248,7 +248,6 @@
 	JabberIq *iq;
 	const char *type, *from, *id;
 	xmlnode *query;
-	char *os = NULL;
 
 	type = xmlnode_get_attrib(packet, "type");
 
@@ -256,6 +255,7 @@
 		GHashTable *ui_info;
 		const char *ui_name = NULL, *ui_version = NULL;
 #if 0
+		char *os = NULL;
 		if(!purple_prefs_get_bool("/plugins/prpl/jabber/hide_os")) {
 			struct utsname osinfo;
 
@@ -290,10 +290,12 @@
 			xmlnode_insert_data(xmlnode_new_child(query, "version"), VERSION, -1);
 		}
 
+#if 0
 		if(os) {
 			xmlnode_insert_data(xmlnode_new_child(query, "os"), os, -1);
 			g_free(os);
 		}
+#endif
 
 		jabber_iq_send(iq);
 	}
--- a/libpurple/protocols/jabber/jabber.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Wed Oct 10 23:19:58 2007 +0000
@@ -1914,7 +1914,7 @@
 			text = _("Authentication Failure");
 		}
 	} else if(!strcmp(packet->name, "stream:error") ||
-			 (!strcmp(packet->name, "error") &&
+			 (!strcmp(packet->name, "error") && xmlns &&
 				!strcmp(xmlns, "http://etherx.jabber.org/streams"))) {
 		if(xmlnode_get_child(packet, "bad-format")) {
 			text = _("Bad Format");
@@ -2189,55 +2189,67 @@
 	return PURPLE_CMD_RET_OK;
 }
 
+static gboolean _jabber_send_buzz(JabberStream *js, const char *username, char **error) {
+
+	JabberBuddy *jb;
+	JabberBuddyResource *jbr;
+	GList *iter;
+
+	if(!username)
+		return FALSE;
+
+	jb = jabber_buddy_find(js, username, FALSE);
+	if(!jb) {
+		*error = g_strdup_printf(_("Unable to buzz, because there is nothing known about user %s."), username);
+		return FALSE;
+	}
+
+	jbr = jabber_buddy_find_resource(jb, NULL);
+	if(!jbr) {
+		*error = g_strdup_printf(_("Unable to buzz, because user %s might be offline."), username);
+		return FALSE;
+	}
+
+	if(!jbr->caps) {
+		*error = g_strdup_printf(_("Unable to buzz, because there is nothing known about user %s."), username);
+		return FALSE;
+	}
+
+	for(iter = jbr->caps->features; iter; iter = g_list_next(iter)) {
+		if(!strcmp(iter->data, "http://www.xmpp.org/extensions/xep-0224.html#ns")) {
+			xmlnode *buzz, *msg = xmlnode_new("message");
+			gchar *to;
+
+			to = g_strdup_printf("%s/%s", username, jbr->name);
+			xmlnode_set_attrib(msg, "to", to);
+			g_free(to);
+
+			/* avoid offline storage */
+			xmlnode_set_attrib(msg, "type", "headline");
+
+			buzz = xmlnode_new_child(msg, "attention");
+			xmlnode_set_namespace(buzz, "http://www.xmpp.org/extensions/xep-0224.html#ns");
+
+			jabber_send(js, msg);
+			xmlnode_free(msg);
+
+			return TRUE;
+		}
+	}
+
+	*error = g_strdup_printf(_("Unable to buzz, because the user %s does not support it."), username);
+	return FALSE;
+}
+
 static PurpleCmdRet jabber_cmd_buzz(PurpleConversation *conv,
 		const char *cmd, char **args, char **error, void *data)
 {
 	JabberStream *js = conv->account->gc->proto_data;
-	xmlnode *msg, *buzz;
-	JabberBuddy *jb;
-	JabberBuddyResource *jbr;
-	char *to;
-	GList *iter;
 
 	if(!args || !args[0])
 		return PURPLE_CMD_RET_FAILED;
-	
-	jb = jabber_buddy_find(js, args[0], FALSE);
-	if(!jb) {
-		*error = g_strdup_printf(_("Unable to buzz, because there is nothing known about user %s."), args[0]);
-		return PURPLE_CMD_RET_FAILED;
-	}
-	
-	jbr = jabber_buddy_find_resource(jb, NULL);
-	if(!jbr) {
-		*error = g_strdup_printf(_("Unable to buzz, because user %s might be offline."), args[0]);
-		return PURPLE_CMD_RET_FAILED;
-	}
-	if(!jbr->caps) {
-		*error = g_strdup_printf(_("Unable to buzz, because there is nothing known about user %s."), args[0]);
-		return PURPLE_CMD_RET_FAILED;
-	}
-	for(iter = jbr->caps->features; iter; iter = g_list_next(iter)) {
-		if(!strcmp(iter->data, "http://www.xmpp.org/extensions/xep-0224.html#ns")) {
-			msg = xmlnode_new("message");
-			to = g_strdup_printf("%s/%s", args[0], jbr->name);
-			xmlnode_set_attrib(msg,"to",to);
-			g_free(to);
-			
-			/* avoid offline storage */
-			xmlnode_set_attrib(msg,"type","headline");
-			
-			buzz = xmlnode_new_child(msg,"attention");
-			xmlnode_set_namespace(buzz,"http://www.xmpp.org/extensions/xep-0224.html#ns");
-			
-			jabber_send(js,msg);
-			xmlnode_free(msg);
-			
-			return PURPLE_CMD_RET_OK;
-		}
-	}
-	*error = g_strdup_printf(_("Unable to buzz, because the user %s does not support it."), args[0]);
-	return PURPLE_CMD_RET_FAILED;
+
+	return _jabber_send_buzz(js, args[0], error)  ? PURPLE_CMD_RET_OK : PURPLE_CMD_RET_FAILED;
 }
 
 GList *jabber_attention_types(PurpleAccount *account)
@@ -2258,23 +2270,16 @@
 
 gboolean jabber_send_attention(PurpleConnection *gc, const char *username, guint code)
 {
-	PurpleConversation *conv;
-	char *error;
-	char *args[1];
-	PurpleCmdRet ret;
-
-	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, username, gc->account);
-
-	args[0] = (char *)username;
+	JabberStream *js = gc->proto_data;
+	gchar *error = NULL;
 
-	ret = jabber_cmd_buzz(conv, "buzz", args, &error, NULL);
-
-	if (ret == PURPLE_CMD_RET_FAILED) {
+	if (!_jabber_send_buzz(js, username, &error)) {
 		purple_debug_error("jabber", "jabber_send_attention: jabber_cmd_buzz failed with error: %s\n", error ? error : "(NULL)");
+		g_free(error);
 		return FALSE;
-	} else {
-		return TRUE;
 	}
+
+	return TRUE;
 }
 
 
--- a/libpurple/protocols/jabber/parser.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/jabber/parser.c	Wed Oct 10 23:19:58 2007 +0000
@@ -80,7 +80,7 @@
 			char *attrib_ns = NULL;
 
 			if (attributes[i+2]) {
-				attrib_ns = g_strdup((char*)attributes[i+2]);;
+				attrib_ns = g_strdup((char*)attributes[i+2]);
 			}
 
 			memcpy(attrib, attributes[i+3], attrib_len);
--- a/libpurple/protocols/jabber/roster.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/jabber/roster.c	Wed Oct 10 23:19:58 2007 +0000
@@ -403,12 +403,12 @@
 void jabber_roster_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
 		PurpleGroup *group) {
 	GSList *buddies = purple_find_buddies(gc->account, buddy->name);
-	GSList *groups = NULL;
 
 	buddies = g_slist_remove(buddies, buddy);
 	if(buddies != NULL) {
 		PurpleBuddy *tmpbuddy;
 		PurpleGroup *tmpgroup;
+		GSList *groups = NULL;
 
 		while(buddies) {
 			tmpbuddy = buddies->data;
@@ -418,6 +418,7 @@
 		}
 
 		jabber_roster_update(gc->proto_data, buddy->name, groups);
+		g_slist_free(groups);
 	} else {
 		JabberIq *iq = jabber_iq_new_query(gc->proto_data, JABBER_IQ_SET,
 				"jabber:iq:roster");
@@ -429,9 +430,4 @@
 
 		jabber_iq_send(iq);
 	}
-
-	if(buddies)
-		g_slist_free(buddies);
-	if(groups)
-		g_slist_free(groups);
 }
--- a/libpurple/protocols/jabber/usermood.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/jabber/usermood.c	Wed Oct 10 23:19:58 2007 +0000
@@ -26,6 +26,7 @@
 #include <string.h>
 #include "internal.h"
 #include "request.h"
+#include "debug.h"
 
 static const char *moodstrings[] = {
 	"afraid",
@@ -145,9 +146,26 @@
 }
 
 static void do_mood_set_from_fields(PurpleConnection *gc, PurpleRequestFields *fields) {
-	JabberStream *js = gc->proto_data;
-	
-	jabber_mood_set(js, moodstrings[purple_request_fields_get_choice(fields, "mood")], purple_request_fields_get_string(fields, "text"));
+	JabberStream *js;
+	int max_mood_idx;
+	int selected_mood = purple_request_fields_get_choice(fields, "mood");
+
+	if (!PURPLE_CONNECTION_IS_VALID(gc)) {
+		purple_debug_error("jabber", "Unable to set mood; account offline.\n");
+		return;
+	}
+
+	js = gc->proto_data;
+
+	/* This is ugly, but protects us from unexpected values. */
+	for (max_mood_idx = 0; moodstrings[max_mood_idx]; max_mood_idx++);
+
+	if (selected_mood < 0 || selected_mood >= max_mood_idx) {
+		purple_debug_error("jabber", "Invalid mood index (%d) selected.\n", selected_mood);
+		return;
+	}
+
+	jabber_mood_set(js, moodstrings[selected_mood], purple_request_fields_get_string(fields, "text"));
 }
 
 static void do_mood_set_mood(PurplePluginAction *action) {
--- a/libpurple/protocols/msn/contact.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/msn/contact.c	Wed Oct 10 23:19:58 2007 +0000
@@ -1177,7 +1177,7 @@
 		purple_debug_warning("MSN CL", "Unable to retrieve user %s from the userlist!\n", passport);
 	}
 
-	if (user->uid != NULL) {
+	if (user != NULL && user->uid != NULL) {
 		contact_xml = g_strdup_printf(MSN_CONTACT_ID_XML, user->uid);
 	} else {
 		contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport);
--- a/libpurple/protocols/msn/msn.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/msn/msn.c	Wed Oct 10 23:19:58 2007 +0000
@@ -943,7 +943,7 @@
 			imdata->msg = body_str;
 			imdata->flags = flags;
 			imdata->when = time(NULL);
-			g_idle_add(msn_send_me_im, imdata);
+			purple_timeout_add(0, msn_send_me_im, imdata);
 		}
 
 		msn_message_destroy(msg);
@@ -1103,7 +1103,7 @@
 	userlist = session->userlist;
 	who = msn_normalize(gc->account, buddy->name);
 
-	purple_debug_info("MSN","Add user:%s to group:%s\n", who, group->name);
+	purple_debug_info("MSN","Add user:%s to group:%s\n", who, (group && group->name) ? group->name : "(null)");
 	if (!session->logged_in)
 	{
 #if 0
--- a/libpurple/protocols/msn/notification.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/msn/notification.c	Wed Oct 10 23:19:58 2007 +0000
@@ -230,11 +230,9 @@
 {
 	MsnSession *session;
 	PurpleAccount *account;
-	PurpleConnection *gc;
 
 	session = cmdproc->session;
 	account = session->account;
-	gc = purple_account_get_connection(account);
 
 	if (!g_ascii_strcasecmp(cmd->params[1], "OK"))
 	{
@@ -1616,7 +1614,6 @@
 {
 	MsnSession *session;
 	PurpleAccount *account;
-	PurpleConnection *gc;
 	MsnUser *user;
 	const char *passport;
 	char *psm_str, *currentmedia_str, *str;
@@ -1626,7 +1623,6 @@
 
 	session = cmdproc->session;
 	account = session->account;
-	gc = purple_account_get_connection(account);
 
 	passport = cmd->params[0];
 	user = msn_userlist_find_user(session->userlist, passport);
--- a/libpurple/protocols/msn/oim.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/msn/oim.c	Wed Oct 10 23:19:58 2007 +0000
@@ -608,8 +608,9 @@
 	purple_debug_info("MSN OIM:OIM", "%s", xmlmsg);
 
 	node = xmlnode_from_str(xmlmsg, strlen(xmlmsg));
-	if (strcmp(node->name, "MD") != 0) {
-		xmlnode_free(node);
+	if (!node || !node->name || strcmp(node->name, "MD") != 0) {
+		if (node)
+			xmlnode_free(node);
 		return;
 	}
 
--- a/libpurple/protocols/msn/userlist.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/msn/userlist.c	Wed Oct 10 23:19:58 2007 +0000
@@ -227,11 +227,8 @@
 	}
 	else if (list_id == MSN_LIST_RL)
 	{
-		PurpleConnection *gc;
 		PurpleConversation *convo;
 
-		gc = purple_account_get_connection(account);
-
 		purple_debug_info("msn",
 						"%s has added you to his or her buddy list.\n",
 						passport);
--- a/libpurple/protocols/myspace/markup.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/myspace/markup.c	Wed Oct 10 23:19:58 2007 +0000
@@ -400,6 +400,8 @@
 msim_markup_tag_to_html(MsimSession *session, xmlnode *root, gchar **begin, 
 		gchar **end)
 {
+	g_return_if_fail(root != NULL);
+
 	if (g_str_equal(root->name, "f")) {
 		msim_markup_f_to_html(session, root, begin, end);
 	} else if (g_str_equal(root->name, "a")) {
@@ -415,7 +417,7 @@
 	} else {
 		purple_debug_info("msim", "msim_markup_tag_to_html: "
 				"unknown tag name=%s, ignoring", 
-				(root && root->name) ? root->name : "(NULL)");
+				root->name ? root->name : "(NULL)");
 		*begin = g_strdup("");
 		*end = g_strdup("");
 	}
--- a/libpurple/protocols/myspace/message.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/myspace/message.c	Wed Oct 10 23:19:58 2007 +0000
@@ -314,7 +314,7 @@
 	MsimMessageElement *elem;
 	MsimMessage **new;
 	gpointer new_data;
-				
+
 	GString *gs;
 	MsimMessage *dict;
 
@@ -349,7 +349,7 @@
 
 		default:
 			purple_debug_info("msim", "msim_msg_clone_element: unknown type %d\n", elem->type);
-			g_return_if_fail(NULL);
+			g_return_if_reached();
 	}
 
 	/* Append cloned data. Note that the 'name' field is a static string, so it
@@ -905,7 +905,7 @@
 
 		default:
 			g_free(data_string);
-			g_return_if_fail(FALSE);
+			g_return_if_reached();
 			break;
 	}
 
--- a/libpurple/protocols/myspace/myspace.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Wed Oct 10 23:19:58 2007 +0000
@@ -2035,18 +2035,14 @@
 msim_do_postprocessing(MsimMessage *msg, const gchar *uid_before, 
 		const gchar *uid_field_name, guint uid)
 {
+	MsimMessageElement *elem;
 	msim_msg_dump("msim_do_postprocessing msg: %s\n", msg);
 
 	/* First, check - if the field already exists, replace <uid> within it */
-	if (msim_msg_get(msg, uid_field_name)) {
-		MsimMessageElement *elem;
+	if ((elem = msim_msg_get(msg, uid_field_name)) != NULL) {
 		gchar *fmt_string;
 		gchar *uid_str, *new_str;
 
-		/* Warning: this is a delicate, but safe, operation */
-
-		elem = msim_msg_get(msg, uid_field_name);
-
 		/* Get the packed element, flattening it. This allows <uid> to be
 		 * replaced within nested data structures, since the replacement is done
 		 * on the linear, packed data, not on a complicated data structure.
--- a/libpurple/protocols/oscar/oscar.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Wed Oct 10 23:19:58 2007 +0000
@@ -1128,8 +1128,10 @@
 	aim_clientready(od, conn);
 
 	chatcon = find_oscar_chat_by_conn(gc, conn);
-	chatcon->id = id;
-	chatcon->conv = serv_got_joined_chat(gc, id++, chatcon->show);
+	if (chatcon) {
+		chatcon->id = id;
+		chatcon->conv = serv_got_joined_chat(gc, id++, chatcon->show);
+	}
 }
 
 static void
--- a/libpurple/protocols/qq/buddy_info.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/qq/buddy_info.c	Wed Oct 10 23:19:58 2007 +0000
@@ -306,12 +306,10 @@
 	g_free(mid);
 }
 
-static gchar *parse_field(GList **list, gboolean choice)
+static gchar *parse_field(PurpleRequestField *field, gboolean choice)
 {
 	gchar *value;
-	PurpleRequestField *field;
 
-	field = (PurpleRequestField *) (*list)->data;
 	if (choice) {
 		value = g_strdup_printf("%d", purple_request_field_choice_get_value(field));
 	} else {
@@ -321,7 +319,6 @@
 		else
 			value = utf8_to_qq(value, QQ_CHARSET_DEFAULT);
 	}
-	*list = g_list_remove_link(*list, *list);
 
 	return value;
 }
@@ -331,7 +328,7 @@
 {
 	PurpleConnection *gc;
 	qq_data *qd;
-	GList *list,  *groups;
+	GList *groups;
 	contact_info *info;
 
 	gc = mid->gc;
@@ -341,33 +338,76 @@
 	info = mid->info;
 
 	groups = purple_request_fields_get_groups(fields);
-	list = purple_request_field_group_get_fields(groups->data);
-	info->uid = parse_field(&list, FALSE);
-	info->nick = parse_field(&list, FALSE);
-	info->name = parse_field(&list, FALSE);
-	info->age = parse_field(&list, FALSE);
-	info->gender = parse_field(&list, TRUE);
-	info->country = parse_field(&list, FALSE);
-	info->province = parse_field(&list, FALSE);
-	info->city = parse_field(&list, FALSE);
-	groups = g_list_remove_link(groups, groups);
-	list = purple_request_field_group_get_fields(groups->data);
-	info->horoscope = parse_field(&list, TRUE);
-	info->occupation = parse_field(&list, FALSE);
-	info->zodiac = parse_field(&list, TRUE);
-	info->blood = parse_field(&list, TRUE);
-	info->college = parse_field(&list, FALSE);
-	info->email = parse_field(&list, FALSE);
-	info->address = parse_field(&list, FALSE);
-	info->zipcode = parse_field(&list, FALSE);
-	info->hp_num = parse_field(&list, FALSE);
-	info->tel = parse_field(&list, FALSE);
-	info->homepage = parse_field(&list, FALSE);
-	groups = g_list_remove_link(groups, groups);
-	list = purple_request_field_group_get_fields(groups->data);
-	info->intro = parse_field(&list, FALSE);
-	groups = g_list_remove_link(groups, groups);
+	while (groups != NULL) {
+		PurpleRequestFieldGroup *group = groups->data;
+		const char *g_name = purple_request_field_group_get_title(group);
+		GList *fields = purple_request_field_group_get_fields(group);
+
+		if (g_name == NULL)
+			continue;
+
+		while (fields != NULL) {
+			PurpleRequestField *field = fields->data;
+			const char *f_id = purple_request_field_get_id(field);
+
+			if (!strcmp(QQ_PRIMARY_INFORMATION, g_name)) {
+
+				if (!strcmp(f_id, "uid"))
+					info->uid = parse_field(field, FALSE);
+				else if (!strcmp(f_id, "nick"))
+					info->nick = parse_field(field, FALSE);
+				else if (!strcmp(f_id, "name"))
+					info->name = parse_field(field, FALSE);
+				else if (!strcmp(f_id, "age"))
+					info->age = parse_field(field, FALSE);
+				else if (!strcmp(f_id, "gender"))
+					info->gender = parse_field(field, TRUE);
+				else if (!strcmp(f_id, "country"))
+					info->country = parse_field(field, FALSE);
+				else if (!strcmp(f_id, "province"))
+					info->province = parse_field(field, FALSE);
+				else if (!strcmp(f_id, "city"))
+					info->city = parse_field(field, FALSE);
+
+			} else if (!strcmp(QQ_ADDITIONAL_INFORMATION, g_name)) {
 
+				if (!strcmp(f_id, "horoscope"))
+					info->horoscope = parse_field(field, TRUE);
+				else if (!strcmp(f_id, "occupation"))
+					info->occupation = parse_field(field, FALSE);
+				else if (!strcmp(f_id, "zodiac"))
+					info->zodiac = parse_field(field, TRUE);
+				else if (!strcmp(f_id, "blood"))
+					info->blood = parse_field(field, TRUE);
+				else if (!strcmp(f_id, "college"))
+					info->college = parse_field(field, FALSE);
+				else if (!strcmp(f_id, "email"))
+					info->email = parse_field(field, FALSE);
+				else if (!strcmp(f_id, "address"))
+					info->address = parse_field(field, FALSE);
+				else if (!strcmp(f_id, "zipcode"))
+					info->zipcode = parse_field(field, FALSE);
+				else if (!strcmp(f_id, "hp_num"))
+					info->hp_num = parse_field(field, FALSE);
+				else if (!strcmp(f_id, "tel"))
+					info->tel = parse_field(field, FALSE);
+				else if (!strcmp(f_id, "homepage"))
+					info->homepage = parse_field(field, FALSE);
+
+			} else if (!strcmp(QQ_INTRO, g_name)) {
+
+				if (!strcmp(f_id, "intro"))
+					info->intro = parse_field(field, FALSE);
+
+			}
+
+			fields = fields->next;
+		}
+
+		groups = groups->next;
+	}
+
+	/* This casting looks like a horrible idea to me -DAA */
 	qq_send_packet_modify_info(gc, (gchar **) info);
 
 	g_strfreev((gchar **) mid->info);
@@ -437,6 +477,7 @@
 		add_string_field_to_group(group, "country", QQ_COUNTRY, info->country);
 		add_string_field_to_group(group, "province", QQ_PROVINCE, info->province);
 		add_string_field_to_group(group, "city", QQ_CITY, info->city);
+
 		group = setup_field_group(fields, QQ_ADDITIONAL_INFORMATION);
 		add_choice_field_to_group(group, "horoscope", QQ_HOROSCOPE, info->horoscope, horoscope_names, QQ_HOROSCOPE_SIZE);
 		add_string_field_to_group(group, "occupation", QQ_OCCUPATION, info->occupation);
--- a/libpurple/protocols/sametime/sametime.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/sametime/sametime.c	Wed Oct 10 23:19:58 2007 +0000
@@ -5563,7 +5563,7 @@
     msgA = _("No matches");
     msgB = _("The identifier '%s' did not match any users in your"
 	     " Sametime community.");
-    msg = g_strdup_printf(msgB, NSTR(res->name));
+    msg = g_strdup_printf(msgB, (res && res->name) ? NSTR(res->name) : "");
 
     purple_notify_error(gc, _("No Matches"), msgA, msg);
 
--- a/libpurple/protocols/yahoo/yahoo_aliases.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/protocols/yahoo/yahoo_aliases.c	Wed Oct 10 23:19:58 2007 +0000
@@ -117,7 +117,7 @@
 					if (alias != NULL) {
 						serv_got_alias(cb->gc, yid, alias);
 						purple_debug_info("yahoo","Fetched alias '%s' (%s)\n",alias,id);
-					} else if (g_strcasecmp((alias!=NULL?alias:""),(b->alias!=NULL?b->alias:"")) != 0) {
+					} else if (b->alias != alias && strcmp(b->alias, "") != 0) {
 					/* Or if we have an alias that Yahoo doesn't, send it up */
 						yahoo_update_alias(cb->gc, yid, b->alias);
 						purple_debug_info("yahoo","Sent alias '%s'\n", b->alias);
@@ -216,7 +216,7 @@
 	struct callback_data *cb;
 	PurpleBuddy *buddy;
 	PurpleUtilFetchUrlData *url_data;
-   
+
 	g_return_if_fail(alias!= NULL);
 	g_return_if_fail(who!=NULL);
 	g_return_if_fail(gc!=NULL);
@@ -224,7 +224,7 @@
 	purple_debug_info("yahoo", "Sending '%s' as new alias for user '%s'.\n",alias, who);
 
 	buddy = purple_find_buddy(gc->account, who);
-	if (buddy->proto_data == NULL) {
+	if (buddy == NULL || buddy->proto_data == NULL) {
 		purple_debug_info("yahoo", "Missing proto_data (get_yahoo_aliases must have failed), bailing out\n");
 		return;
 	}
--- a/libpurple/sslconn.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/sslconn.h	Wed Oct 10 23:19:58 2007 +0000
@@ -204,17 +204,19 @@
  									   void *data);
 
 /**
-  * Makes a SSL connection using an already open file descriptor.
-  *
-  * @param account    The account making the connection.
-  * @param fd         The file descriptor.
-  * @param func       The SSL input handler function.
-  * @param error_func The SSL error handler function.
-  * @param host       The hostname of the other peer (to verify the CN)
-  * @param data       User-defined data.
-  *
-  * @return The SSL connection handle.
-  */
+ * Makes a SSL connection using an already open file descriptor.
+ *
+ * @param account    The account making the connection.
+ * @param fd         The file descriptor.
+ * @param func       The SSL input handler function.
+ * @param error_func The SSL error handler function.
+ * @param host       The hostname of the other peer (to verify the CN)
+ * @param data       User-defined data.
+ *
+ * @return The SSL connection handle.
+ *
+ * @since 2.2.0
+ */
 PurpleSslConnection *purple_ssl_connect_with_host_fd(PurpleAccount *account, int fd,
                                            PurpleSslInputFunction func,
                                            PurpleSslErrorFunction error_func,
@@ -268,6 +270,8 @@
  *
  * @return The peer certificate chain, in the order of certificate, issuer,
  *         issuer's issuer, etc. @a NULL if no certificates have been provided,
+ *
+ * @since 2.2.0
  */
 GList * purple_ssl_get_peer_certificates(PurpleSslConnection *gsc);
 
--- a/libpurple/util.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/util.c	Wed Oct 10 23:19:58 2007 +0000
@@ -2548,15 +2548,14 @@
 
 	filename_full = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", user_dir, filename);
 
-	ret = purple_util_write_data_to_file_absolute(filename_full,
-						      data,size);
+	ret = purple_util_write_data_to_file_absolute(filename_full, data, size);
 
 	g_free(filename_full);
 	return ret;
 }
 
 gboolean
-purple_util_write_data_to_file_absolute(const char *filename_full, const char *data, size_t size)
+purple_util_write_data_to_file_absolute(const char *filename_full, const char *data, gssize size)
 {
 	gchar *filename_temp;
 	FILE *file;
--- a/libpurple/util.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/util.h	Wed Oct 10 23:19:58 2007 +0000
@@ -607,7 +607,7 @@
  *
  */
 gboolean
-purple_util_write_data_to_file_absolute(const char *filename_full, const char *data, size_t size);
+purple_util_write_data_to_file_absolute(const char *filename_full, const char *data, gssize size);
 
 /**
  * Read the contents of a given file and parse the results into an
--- a/libpurple/xmlnode.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/libpurple/xmlnode.c	Wed Oct 10 23:19:58 2007 +0000
@@ -131,7 +131,7 @@
 		if(attr_node->type == XMLNODE_TYPE_ATTRIB &&
 				!strcmp(attr_node->name, attr))
 		{
-			if(node->child == attr_node) {
+			if(sibling == NULL) {
 				node->child = attr_node->next;
 			} else {
 				sibling->next = attr_node->next;
@@ -146,6 +146,19 @@
 	}
 }
 
+/* Compare two nullable xmlns strings.
+ * They are considered equal if they're both NULL or the strings are equal
+ */
+static gboolean _xmlnode_compare_xmlns(const char *xmlns1, const char *xmlns2) {
+	gboolean equal = FALSE;
+
+	if (xmlns1 == NULL && xmlns2 == NULL)
+		equal = TRUE;
+	else if (xmlns1 != NULL && xmlns2 != NULL && !strcmp(xmlns1, xmlns2))
+		equal = TRUE;
+
+	return equal;
+}
 
 void
 xmlnode_remove_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns)
@@ -159,9 +172,9 @@
 	{
 		if(attr_node->type == XMLNODE_TYPE_ATTRIB &&
 		   !strcmp(attr_node->name, attr) &&
-		   !strcmp(attr_node->xmlns, xmlns))
+		   _xmlnode_compare_xmlns(xmlns, attr_node->xmlns))
 		{
-			if(node->child == attr_node) {
+			if(sibling == NULL) {
 				node->child = attr_node->next;
 			} else {
 				sibling->next = attr_node->next;
@@ -238,7 +251,8 @@
 
 	for(x = node->child; x; x = x->next) {
 		if(x->type == XMLNODE_TYPE_ATTRIB &&
-		   !strcmp(attr, x->name) && !strcmp(x->xmlns, xmlns)) {
+		   !strcmp(attr, x->name) &&
+		   _xmlnode_compare_xmlns(xmlns, x->xmlns)) {
 			return x->data;
 		}
 	}
@@ -326,6 +340,7 @@
 	child_name = names[1];
 
 	for(x = parent->child; x; x = x->next) {
+		/* XXX: Is it correct to ignore the namespace for the match if none was specified? */
 		const char *xmlns = NULL;
 		if(ns)
 			xmlns = xmlnode_get_namespace(x);
@@ -673,6 +688,7 @@
 	g_return_val_if_fail(node->type == XMLNODE_TYPE_TAG, NULL);
 
 	for(sibling = node->next; sibling; sibling = sibling->next) {
+		/* XXX: Is it correct to ignore the namespace for the match if none was specified? */
 		const char *xmlns = NULL;
 		if(ns)
 			xmlns = xmlnode_get_namespace(sibling);
--- a/pidgin/gtkaccount.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/pidgin/gtkaccount.c	Wed Oct 10 23:19:58 2007 +0000
@@ -1328,8 +1328,9 @@
 					break;
 
 				case PURPLE_PREF_STRING_LIST:
-					gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter);
-					gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(widget)), &iter, 1, &value2, -1);
+					value2 = NULL;
+					if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter))
+						gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(widget)), &iter, 1, &value2, -1);
 					purple_account_set_string(account, setting, value2);
 					break;
 
--- a/pidgin/gtkblist.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/pidgin/gtkblist.c	Wed Oct 10 23:19:58 2007 +0000
@@ -5300,7 +5300,7 @@
 static void buddy_node(PurpleBuddy *buddy, GtkTreeIter *iter, PurpleBlistNode *node)
 {
 	PurplePresence *presence;
-	GdkPixbuf *status, *avatar, *emblem;
+	GdkPixbuf *status, *avatar, *emblem, *prpl_icon;
 	char *mark;
 	char *idle = NULL;
 	gboolean expanded = ((struct _pidgin_blist_node *)(node->parent->ui_data))->contact_expanded;
@@ -5310,7 +5310,7 @@
 
 	if (editing_blist)
 		return;
-	
+
 	status = pidgin_blist_get_status_icon((PurpleBlistNode*)buddy,
 						PIDGIN_STATUS_ICON_SMALL);
 
@@ -5357,6 +5357,8 @@
 		}
 	}
 
+	prpl_icon = pidgin_create_prpl_icon(buddy->account, PIDGIN_PRPL_ICON_SMALL);
+
 	gtk_tree_store_set(gtkblist->treemodel, iter,
 			   STATUS_ICON_COLUMN, status,
 			   STATUS_ICON_VISIBLE_COLUMN, TRUE,
@@ -5367,7 +5369,7 @@
 			   BUDDY_ICON_VISIBLE_COLUMN, biglist,
 			   EMBLEM_COLUMN, emblem,
 			   EMBLEM_VISIBLE_COLUMN, (emblem != NULL),
-			   PROTOCOL_ICON_COLUMN, pidgin_create_prpl_icon(buddy->account, PIDGIN_PRPL_ICON_SMALL),
+			   PROTOCOL_ICON_COLUMN, prpl_icon,
 			   PROTOCOL_ICON_VISIBLE_COLUMN, purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons"),
 			   BGCOLOR_COLUMN, NULL,
 			   CONTACT_EXPANDER_COLUMN, NULL,
@@ -5383,6 +5385,8 @@
 		g_object_unref(status);
 	if(avatar)
 		g_object_unref(avatar);
+	if(prpl_icon)
+		g_object_unref(prpl_icon);
 }
 
 /* This is a variation on the original gtk_blist_update_contact. Here we
@@ -5503,9 +5507,7 @@
 
 	if(purple_account_is_connected(chat->account)) {
 		GtkTreeIter iter;
-		GdkPixbuf *status;
-		GdkPixbuf *avatar;
-		GdkPixbuf *emblem;
+		GdkPixbuf *status, *avatar, *emblem, *prpl_icon;
 		char *mark;
 		gboolean showicons = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons");
 		PidginBlistNode *ui;
@@ -5536,6 +5538,8 @@
 			mark = bold;
 		}
 
+		prpl_icon = pidgin_create_prpl_icon(chat->account, PIDGIN_PRPL_ICON_SMALL);
+
 		gtk_tree_store_set(gtkblist->treemodel, &iter,
 				STATUS_ICON_COLUMN, status,
 				STATUS_ICON_VISIBLE_COLUMN, TRUE,
@@ -5543,7 +5547,7 @@
 				BUDDY_ICON_VISIBLE_COLUMN,  purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons"),
 				EMBLEM_COLUMN, emblem,
 				EMBLEM_VISIBLE_COLUMN, emblem != NULL,
-				PROTOCOL_ICON_COLUMN, pidgin_create_prpl_icon(chat->account, PIDGIN_PRPL_ICON_SMALL),
+				PROTOCOL_ICON_COLUMN, prpl_icon,
 				PROTOCOL_ICON_VISIBLE_COLUMN, purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons"),
 				NAME_COLUMN, mark,
 				GROUP_EXPANDER_VISIBLE_COLUMN, FALSE,
@@ -5556,6 +5560,8 @@
 			g_object_unref(status);
 		if(avatar)
 			g_object_unref(avatar);
+		if(prpl_icon)
+			g_object_unref(prpl_icon);
 	} else {
 		pidgin_blist_hide_node(list, node, TRUE);
 	}
--- a/pidgin/gtkblist.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/pidgin/gtkblist.h	Wed Oct 10 23:19:58 2007 +0000
@@ -371,6 +371,8 @@
  * @param selected  Whether this buddy is selected. If TRUE, the markup will not change the color.
  * @param aliased  TRUE to return the appropriate alias of this buddy, FALSE to return its screenname and status information
  * @return The markup for this buddy
+ *
+ * @since 2.1.0
  */
 gchar *pidgin_blist_get_name_markup(PurpleBuddy *buddy, gboolean selected, gboolean aliased);
 
@@ -382,11 +384,15 @@
  *
  * @param node The buddy list node to show a tooltip for
  * @param widget The widget to draw the tooltip on
+ *
+ * @since 2.1.0
  */
 void pidgin_blist_draw_tooltip(PurpleBlistNode *node, GtkWidget *widget);
 
 /**
  * Destroys the current (if any) Buddy List tooltip
+ *
+ * @since 2.1.0
  */
 void pidgin_blist_tooltip_destroy(void);
 
--- a/pidgin/gtkconv.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/pidgin/gtkconv.h	Wed Oct 10 23:19:58 2007 +0000
@@ -253,6 +253,8 @@
  * @param conv  The conversation.
  *
  * @return  Wheter Pidgin UI was successfully attached.
+ *
+ * @since 2.2.0
  */
 gboolean pidgin_conv_attach_to_conversation(PurpleConversation *conv);
 
--- a/pidgin/gtkimhtml.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/pidgin/gtkimhtml.h	Wed Oct 10 23:19:58 2007 +0000
@@ -441,6 +441,8 @@
  * @param id       The id to associate with the image.
  *
  * @return A new IM/HTML Scalable object with an image.
+ *
+ * @since 2.1.0
  */
 /*
  * TODO: All this animation code could be combined much better with
@@ -837,6 +839,8 @@
  *
  * @param imhtml  The GTK+ IM/HTML.
  * @param flags   The connection flag which describes the allowed types of formatting.
+ *
+ * @since 2.1.0
  */
 void gtk_imhtml_setup_entry(GtkIMHtml *imhtml, PurpleConnectionFlags flags);
 
--- a/pidgin/gtklog.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/pidgin/gtklog.c	Wed Oct 10 23:19:58 2007 +0000
@@ -684,6 +684,7 @@
 	PidginLogViewer *lv = NULL;
 	const char *name = screenname;
 	char *title;
+	GdkPixbuf *prpl_icon;
 
 	g_return_if_fail(account != NULL);
 	g_return_if_fail(screenname != NULL);
@@ -721,9 +722,14 @@
 		title = g_strdup_printf(_("Conversations with %s"), name);
 	}
 
+	prpl_icon = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_MEDIUM);
+
 	display_log_viewer(parent, ht, purple_log_get_logs(type, screenname, account),
-			title, gtk_image_new_from_pixbuf(pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_MEDIUM)), 
+			title, gtk_image_new_from_pixbuf(prpl_icon),
 			purple_log_get_total_size(type, screenname, account));
+
+	if (prpl_icon)
+		g_object_unref(prpl_icon);
 	g_free(title);
 }
 
--- a/pidgin/gtkutils.c	Wed Oct 10 22:57:51 2007 +0000
+++ b/pidgin/gtkutils.c	Wed Oct 10 23:19:58 2007 +0000
@@ -111,19 +111,20 @@
 		desc = pango_font_description_from_string(font);
 	} else if (purple_running_gnome()) {
 		/* Use the GNOME "document" font, if applicable */
-		char *path, *font;
+		char *path;
 
 		if ((path = g_find_program_in_path("gconftool-2"))) {
+			char *font = NULL;
 			g_free(path);
-			if (!g_spawn_command_line_sync(
+			if (g_spawn_command_line_sync(
 					"gconftool-2 -g /desktop/gnome/interface/document_font_name",
-					&font, NULL, NULL, NULL))
-				return;
+					&font, NULL, NULL, NULL)) {
+				desc = pango_font_description_from_string(font);
+			}
+			g_free(font);
 		}
-		desc = pango_font_description_from_string(font);
-		g_free(font);
 	}
-	
+
 	if (desc) {
 		gtk_widget_modify_font(imhtml, desc);
 		pango_font_description_free(desc);
--- a/pidgin/gtkutils.h	Wed Oct 10 22:57:51 2007 +0000
+++ b/pidgin/gtkutils.h	Wed Oct 10 23:19:58 2007 +0000
@@ -376,6 +376,8 @@
  *
  * @param conn   The connection to get information from.
  * @param name   The user to get information about.
+ *
+ * @since 2.1.0
  */
 void pidgin_retrieve_user_info(PurpleConnection *conn, const char *name);
 
@@ -385,6 +387,8 @@
  * @param conn   The connection to get information from.
  * @param name   The user to get information about.
  * @param chatid The chat id.
+ *
+ * @since 2.1.0
  */
 void pidgin_retrieve_user_info_in_chat(PurpleConnection *conn, const char *name, int chatid);
 
@@ -423,6 +427,8 @@
  *
  * @param w The widget that we want to label.
  * @param l A GtkLabel that we want to use as the label for the widget.
+ *
+ * @since 2.2.0
  */
 void pidgin_set_accessible_relations(GtkWidget *w, GtkWidget *l);
 
@@ -437,6 +443,8 @@
  *        where the menu shall be drawn. This is an output parameter.
  * @param push_in This is an output parameter?
  * @param data Not used by this particular position function.
+ *
+ * @since 2.1.0
  */
 void pidgin_menu_position_func_helper(GtkMenu *menu, gint *x, gint *y,
 										gboolean *push_in, gpointer data);
@@ -671,6 +679,8 @@
  *
  * @return               A newly created text GtkComboBox containing a GtkEntry
  *                       child.
+ *
+ * @since 2.2.0
  */
 GtkWidget *pidgin_text_combo_box_entry_new(const char *default_item, GList *items);
 
@@ -680,6 +690,8 @@
  * @param widget         The simple text GtkComboBoxEntry equivalent widget
  *
  * @return               The text in the widget's entry. It must not be freed
+ *
+ * @since 2.2.0
  */
 const char *pidgin_text_combo_box_entry_get_text(GtkWidget *widget);
 
@@ -688,6 +700,8 @@
  *
  * @param widget         The simple text GtkComboBoxEntry equivalent widget
  * @param text           The text to set
+ *
+ * @since 2.2.0
  */
 void pidgin_text_combo_box_entry_set_text(GtkWidget *widget, const char *text);