changeset 18152:af0b9c6cbeb8

merge of 'a044da71f197bdd564f0d38ebb02798e06d1997f' and 'e64c6a26887b59ce7ad568ea1c551938e673c7a0'
author Nathan Walp <nwalp@pidgin.im>
date Sun, 17 Jun 2007 05:09:21 +0000
parents f88c2a41200d (current diff) 428a3418bce5 (diff)
children 7f23135d9b68
files
diffstat 25 files changed, 367 insertions(+), 83 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog.API	Sun Jun 17 04:50:18 2007 +0000
+++ b/ChangeLog.API	Sun Jun 17 05:09:21 2007 +0000
@@ -13,8 +13,6 @@
 		    UIs can now use better scheduling for whole-second timers.  For
 		    example, clients based on the glib event loop can now use
 		    g_timeout_add_seconds.
-		* gtk_imhtml_setup_entry
-		* pidgin_create_window
 		* purple_blist_node_get_type
 		* purple_conversation_do_command
 		* purple_conversation_get_extended_menu
@@ -22,8 +20,6 @@
 		    This is for UIs to use to ensure only one copy is running.
 		* purple_dbus_is_owner
 		* purple_image_data_calculate_filename
-		* pidgin_retrieve_user_info, shows immediate feedback when getting
-		  information about a user.
 		* 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.
@@ -31,8 +27,7 @@
 		    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
-		* gtk_imhtml_animation_new
-		    Can be used for inserting an animated image into an IMHTML.
+		* purple_pounces_get_all_for_ui
 
 		Changed:
 		* The documentation of the following functions now properly
@@ -68,6 +63,14 @@
 		  GLists.  The passed list is still not modified or freed.
 
 	Pidgin:
+		Added:
+		* gtk_imhtml_setup_entry
+		* pidgin_create_window
+		* pidgin_retrieve_user_info, shows immediate feedback when getting
+		  information about a user.
+		* gtk_imhtml_animation_new
+		    Can be used for inserting an animated image into an IMHTML.
+
 		Changed:
 		* pidgin_append_menu_action returns the menuitem added to the menu.
 		* pidgin_separator returns the separator added to the menu.
--- a/finch/gntft.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/finch/gntft.c	Sun Jun 17 05:09:21 2007 +0000
@@ -411,7 +411,7 @@
 
 	size_str      = purple_str_size_to_units(purple_xfer_get_size(xfer));
 	remaining_str = purple_str_size_to_units(purple_xfer_get_bytes_remaining(xfer));
-	kbsec = g_strdup_printf(_("%.2f KB/s"), kbps);
+	kbsec = g_strdup_printf(_("%.2f KiB/s"), kbps);
 
 	gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_PROGRESS,
 			g_ascii_dtostr(prog_str, sizeof(prog_str), purple_xfer_get_progress(xfer) * 100.));
--- a/finch/gntpounce.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/finch/gntpounce.c	Sun Jun 17 05:09:21 2007 +0000
@@ -141,8 +141,8 @@
 
 	gnt_tree_remove_all(GNT_TREE(dialog->tree));
 
-	for (pounces = purple_pounces_get_all(); pounces != NULL;
-			pounces = g_list_next(pounces))
+	for (pounces = purple_pounces_get_all_for_ui(FINCH_UI); pounces != NULL;
+			pounces = g_list_delete_link(pounces, pounces))
 	{
 		add_pounce_to_treeview(GNT_TREE(dialog->tree), pounces->data);
 	}
--- a/finch/plugins/Makefile.am	Sun Jun 17 04:50:18 2007 +0000
+++ b/finch/plugins/Makefile.am	Sun Jun 17 05:09:21 2007 +0000
@@ -28,7 +28,7 @@
 
 endif # PLUGINS
 
-EXTRA_DIST = 
+EXTRA_DIST = pietray.py
 
 AM_CPPFLAGS = \
 	-DDATADIR=\"$(datadir)\" \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/finch/plugins/pietray.py	Sun Jun 17 05:09:21 2007 +0000
@@ -0,0 +1,183 @@
+#!/usr/bin/env python
+
+# This is a dbus script to show a docklet for Finch. This should work
+# for any 'compatible' purple client.
+#
+# By 'compatible', I mean any client that sets and updates the
+# "unseen-count" data on the conversations.
+#
+# It allows doing the following things:
+#    - It allows changing status.
+#    - It shows the current status and info about unread messages in
+#      the tooltip.
+#    - It can blink on unread IM/Chat messages, and it allows canging
+#      the preference for that.
+# 
+# It requires GTK+ 2.10 or above, since it uses GtkStatusIcon.
+# 
+# Sadrul <sadrul@pidgin.im>
+
+import pygtk
+pygtk.require("2.0")
+import gtk
+import dbus, gobject, dbus.glib
+import os # to get the pkg-config output
+
+bus = dbus.SessionBus()
+obj = bus.get_object(
+    "im.pidgin.purple.PurpleService", "/im/pidgin/purple/PurpleObject")
+purple = dbus.Interface(obj, "im.pidgin.purple.PurpleInterface")
+
+def pack_image_label(menu, image, label):
+	item = gtk.ImageMenuItem(label)
+	if image:
+		img = gtk.Image()
+		img.set_from_stock(image, 1)
+		item.set_image(img)
+	menu.append(item)
+	return item
+
+def activate_primitive_status(item, status):
+	saved = purple.PurpleSavedstatusFindTransientByTypeAndMessage(status, "")
+	if not saved:
+		saved = purple.PurpleSavedstatusNew("", status)
+	purple.PurpleSavedstatusActivate(saved)
+
+def activate_popular_status(item, time):
+	saved = purple.PurpleSavedstatusFindByCreationTime(time)
+	if saved:
+		purple.PurpleSavedstatusActivate(saved)
+
+def generate_status_menu(menu):
+	item = gtk.MenuItem("Available")
+	item.connect("activate", activate_primitive_status, 2)
+	menu.append(item)
+
+	item = gtk.MenuItem("Away")
+	item.connect("activate", activate_primitive_status, 5)
+	menu.append(item)
+
+	item = gtk.MenuItem("Invisible")
+	item.connect("activate", activate_primitive_status, 4)
+	menu.append(item)
+
+	item = gtk.MenuItem("Offline")
+	item.connect("activate", activate_primitive_status, 1)
+	menu.append(item)
+
+	menu.append(gtk.MenuItem())
+
+	popular = purple.PurpleSavedstatusesGetPopular(10)
+	for pop in popular:
+		title = purple.PurpleSavedstatusGetTitle(pop).replace('_', '__')
+		item = gtk.MenuItem(title)
+		item.set_data("timestamp", purple.PurpleSavedstatusGetCreationTime(pop))
+		item.connect("activate", activate_popular_status, purple.PurpleSavedstatusGetCreationTime(pop))
+		menu.append(item)
+
+def toggle_pref(item, pref):
+	purple.PurplePrefsSetBool(pref, item.get_active())
+
+def popup_menu(icon, button, tm, none):
+	menu = gtk.Menu()
+
+	item = gtk.CheckMenuItem("Blink for unread IM")
+	item.set_active(purple.PurplePrefsGetBool("/plugins/dbus/docklet/blink/im"))
+	item.connect("activate", toggle_pref, "/plugins/dbus/docklet/blink/im")
+	menu.append(item)
+
+	item = gtk.CheckMenuItem("Blink for unread Chats")
+	item.set_active(purple.PurplePrefsGetBool("/plugins/dbus/docklet/blink/chat"))
+	item.connect("activate", toggle_pref, "/plugins/dbus/docklet/blink/chat")
+	menu.append(item)
+
+	menu.append(gtk.MenuItem())
+
+	#item = pack_image_label(menu, None, "Change Status...")
+	item = gtk.MenuItem("Change Status...")
+	menu.append(item)
+	submenu = gtk.Menu()
+	item.set_submenu(submenu)
+	generate_status_menu(submenu)
+
+	menu.show_all()
+	menu.popup(None, None, None, button, tm)
+
+def get_status_message():
+	status = purple.PurpleSavedstatusGetCurrent()
+	msg = purple.PurpleSavedstatusGetMessage(status)
+	if msg and len(msg) > 0:
+		text = msg + " "
+	else:
+		text = ""
+	text = text + "(" + {
+		2: "Available",
+		5: "Away",
+		4: "Invisible",
+		1: "Offline"
+	}[purple.PurpleSavedstatusGetType(status)] + ")"
+	return text
+
+def detect_unread_conversations():
+	im = purple.PurplePrefsGetBool("/plugins/dbus/docklet/blink/im")
+	chat = purple.PurplePrefsGetBool("/plugins/dbus/docklet/blink/chat")
+	tooltip = ""
+	blink = False
+	if im and chat:
+		convs = purple.PurpleGetConversations()
+	elif im:
+		convs = purple.PurpleGetIms()
+	elif chat:
+		convs = purple.PurpleGetChats()
+	else:
+		convs = None
+	for conv in convs:
+		count = purple.PurpleConversationGetData(conv, "unseen-count")
+		if count and count > 0:
+			blink = True
+			tooltip = tooltip + "\n" + purple.PurpleConversationGetName(conv) + " (" + str(count) + ")"
+	t.set_from_file(path + "/share/pixmaps/pidgin.png")
+	if blink:
+		# I hate this icon
+		# t.set_from_file(path + "/share/pixmaps/pidgin/tray/22/tray-message.png")
+		tooltip = "\nUnread Messages:" + tooltip
+	# There's going to be some way to expose the client's display name in 2.1.0.
+	# Use that instead of hardcoding Finch here.
+	t.set_tooltip("Finch: " + get_status_message() + tooltip)
+	t.set_blinking(blink)
+
+def conversation_updated(conv, type):
+	detect_unread_conversations()
+
+def savedstatus_changed(new, old):
+	# Change the icon for status perhaps?
+	detect_unread_conversations()
+
+def init_prefs():
+	if not purple.PurplePrefsExists("/plugins/dbus/docklet/blink"):
+		purple.PurplePrefsAddNone("/plugins")
+		purple.PurplePrefsAddNone("/plugins/dbus")
+		purple.PurplePrefsAddNone("/plugins/dbus/docklet")
+		purple.PurplePrefsAddNone("/plugins/dbus/docklet/blink")
+		purple.PurplePrefsAddBool("/plugins/dbus/docklet/blink/im", True)
+		purple.PurplePrefsAddBool("/plugins/dbus/docklet/blink/chat", True)
+
+pkg = os.popen("pkg-config --variable=prefix pidgin")
+path = pkg.readline().rstrip()
+
+bus.add_signal_receiver(conversation_updated,
+  dbus_interface="im.pidgin.purple.PurpleInterface",
+  signal_name="ConversationUpdated")
+
+bus.add_signal_receiver(savedstatus_changed,
+  dbus_interface="im.pidgin.purple.PurpleInterface",
+  signal_name="SavedstatusChanged")
+
+t = gtk.StatusIcon()
+t.connect("popup-menu", popup_menu, None)
+
+init_prefs()
+detect_unread_conversations()
+
+gtk.main ()
+
--- a/libpurple/blist.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/libpurple/blist.c	Sun Jun 17 05:09:21 2007 +0000
@@ -35,8 +35,6 @@
 #include "value.h"
 #include "xmlnode.h"
 
-#define PATHSIZE 1024
-
 static PurpleBlistUiOps *blist_ui_ops = NULL;
 
 static PurpleBuddyList *purplebuddylist = NULL;
--- a/libpurple/core.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/libpurple/core.c	Sun Jun 17 05:09:21 2007 +0000
@@ -489,13 +489,33 @@
 			/* We're only going to duplicate a logs symlink. */
 			if (!strcmp(entry, "logs"))
 			{
+				char *link;
+#if GLIB_CHECK_VERSION(2,4,0)
+				GError *err = NULL;
+
+				if ((link = g_file_read_link(name, &err)) == NULL)
+				{
+					char *name_utf8 = g_filename_to_utf8(name, -1, NULL, NULL, NULL);
+					purple_debug_error("core", "Error reading symlink %s: %s. Please report this at http://developer.pidgin.im\n",
+					                   name_utf8 ? name_utf8 : name, err->message);
+					g_free(name_utf8);
+					g_error_free(err);
+					g_free(name);
+					g_dir_close(dir);
+					g_free(status_file);
+					g_free(old_user_dir);
+					return FALSE;
+				}
+#else
 				char buf[MAXPATHLEN];
 				size_t linklen;
 
 				if ((linklen = readlink(name, buf, sizeof(buf) - 1) == -1))
 				{
+					char *name_utf8 = g_filename_to_utf8(name);
 					purple_debug_error("core", "Error reading symlink %s: %s. Please report this at http://developer.pidgin.im\n",
-					                   name, strerror(errno));
+					                   name_utf8, strerror(errno));
+					g_free(name_utf8);
 					g_free(name);
 					g_dir_close(dir);
 					g_free(status_file);
@@ -504,13 +524,18 @@
 				}
 				buf[linklen] = '\0';
 
-				logs_dir = g_strconcat(user_dir, G_DIR_SEPARATOR_S "logs", NULL);
+				/* This way we don't have to GLIB_VERSION_CHECK every g_free(link) below. */
+				link = g_strdup(buf);
+#endif
 
-				if (!strcmp(buf, "../.purple/logs") || !strcmp(buf, logs_dir))
+				logs_dir = g_build_filename(user_dir, "logs", NULL);
+
+				if (!strcmp(link, "../.purple/logs") || !strcmp(link, logs_dir))
 				{
 					/* If the symlink points to the new directory, we're
 					 * likely just trying again after a failed migration,
 					 * so there's no need to fail here. */
+					g_free(link);
 					g_free(logs_dir);
 					continue;
 				}
@@ -522,12 +547,13 @@
 				g_unlink(logs_dir);
 
 				/* Relative links will most likely still be
-				 * valid from ~/.purple, though not it's not
+				 * valid from ~/.purple, though it's not
 				 * guaranteed.  Oh well. */
-				if (symlink(buf, logs_dir))
+				if (symlink(link, logs_dir))
 				{
 					purple_debug_error("core", "Error symlinking %s to %s: %s. Please report this at http://developer.pidgin.im\n",
-					                   logs_dir, buf, strerror(errno));
+					                   logs_dir, link, strerror(errno));
+					g_free(link);
 					g_free(name);
 					g_free(logs_dir);
 					g_dir_close(dir);
@@ -536,6 +562,7 @@
 					return FALSE;
 				}
 
+				g_free(link);
 				g_free(logs_dir);
 				continue;
 			}
--- a/libpurple/dbus-analyze-functions.py	Sun Jun 17 04:50:18 2007 +0000
+++ b/libpurple/dbus-analyze-functions.py	Sun Jun 17 05:09:21 2007 +0000
@@ -3,7 +3,7 @@
 import sys
 
 # types translated into "int"
-simpletypes = ["int", "gint", "guint", "gboolean"]
+simpletypes = ["int", "gint", "guint", "gboolean", "gpointer", "size_t", "gssize", "time_t"]
 
 # List "excluded" contains functions that shouldn't be exported via
 # DBus.  If you remove a function from this list, please make sure
@@ -119,21 +119,26 @@
 
     def processinput(self, type, name):
         const = False
+        unsigned = False
         if type[0] == "const":
             type = type[1:]
             const = True
 
+        if type[0] == "unsigned":
+            type = type[1:]
+            unsigned = True
+
         if len(type) == 1:
             # simple types (int, gboolean, etc.) and enums
             if (type[0] in simpletypes) or ((type[0].startswith("Purple") and not type[0].endswith("Callback"))):
-                return self.inputsimple(type, name)
+                return self.inputsimple(type, name, unsigned)
 
         # pointers ... 
         if (len(type) == 2) and (type[1] == pointer):
             # strings
             if type[0] in ["char", "gchar"]:
                 if const:
-                    return self.inputstring(type, name)
+                    return self.inputstring(type, name, unsigned)
                 else:
                     raise myexception
 
@@ -232,12 +237,18 @@
             print "typedef struct _%s %s;" % (type[0], type[0])
             self.knowntypes.append(type[0])
 
-    def inputsimple(self, type, name):
+    def inputsimple(self, type, name, us):
         self.paramshdr.append("%s %s" % (type[0], name))
-        self.inputparams.append(("G_TYPE_INT", name))
+        if us:
+            self.inputparams.append(("G_TYPE_UINT", name))
+        else:
+            self.inputparams.append(("G_TYPE_INT", name))
 
-    def inputstring(self, type, name):
-        self.paramshdr.append("const char *%s" % name)
+    def inputstring(self, type, name, us):
+        if us:
+            self.paramshdr.append("const unsigned char *%s" % name)
+        else:
+            self.paramshdr.append("const char *%s" % name)
         self.inputparams.append(("G_TYPE_STRING", name))
         
     def inputpurplestructure(self, type, name):
@@ -348,15 +359,23 @@
 
     # input parameters
 
-    def inputsimple(self, type, name):
-        self.cdecls.append("\tdbus_int32_t %s;" % name)
-        self.cparams.append(("INT32", name))
-        self.addintype("i", name)
+    def inputsimple(self, type, name, us):
+        if us:
+            self.cdecls.append("\tdbus_int32_t %s;" % name)
+            self.cparams.append(("INT32", name))
+            self.addintype("i", name)
+        else:
+            self.cdecls.append("\tdbus_uint32_t %s;" % name)
+            self.cparams.append(("UINT32", name))
+            self.addintype("u", name)
 
-    def inputstring(self, type, name):
-        self.cdecls.append("\tconst char *%s;" % name)
+    def inputstring(self, type, name, us):
+        if us:
+            self.cdecls.append("\tconst unsigned char *%s;" % name)
+        else:
+            self.cdecls.append("\tconst char *%s;" % name)
         self.cparams.append(("STRING", name))
-        self.ccode  .append("\tNULLIFY(%s);" % name)
+        self.ccode.append("\t%s = (%s && %s[0]) ? %s : NULL;" % (name,name,name,name))
         self.addintype("s", name)
 
     def inputhash(self, type, name):
--- a/libpurple/dbus-server.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/libpurple/dbus-server.c	Sun Jun 17 05:09:21 2007 +0000
@@ -120,7 +120,7 @@
 	if ((id == 0) && (node != NULL))
 	{
 		purple_debug_warning("dbus",
-				"Need to register an object with the dbus subsystem.\n");
+				"Need to register an object with the dbus subsystem. (If you are not a developer, please ignore this message.)\n");
 		return 0;
 	}
 	return id;
@@ -760,7 +760,7 @@
 	dbus_message_iter_init_append(signal, &iter);
 
 	if (purple_dbus_message_append_purple_values(&iter, num_values, values, vargs))
-		purple_debug_warning("dbus", "The signal \"%s\" caused some dbus error.\n", name);
+		purple_debug_warning("dbus", "The signal \"%s\" caused some dbus error. (If you are not a developer, please ignore this message.)\n", name);
 
 	dbus_connection_send(purple_dbus_connection, signal, NULL);
 
@@ -797,8 +797,18 @@
 void
 purple_dbus_uninit(void)
 {
-	/* Surely we must do SOME kind of uninitialization? */
+	DBusError error;
+	if (!purple_dbus_connection)
+		return;
 
+	dbus_error_init(&error);
+	dbus_connection_unregister_object_path(purple_dbus_connection, DBUS_PATH_PURPLE);
+	dbus_bus_release_name(purple_dbus_connection, DBUS_SERVICE_PURPLE, &error);
+	dbus_error_free(&error);
+	dbus_connection_unref(purple_dbus_connection);
+	purple_dbus_connection = NULL;
+	purple_signals_disconnect_by_handle(purple_dbus_get_handle());
 	g_free(init_error);
 	init_error = NULL;
 }
+
--- a/libpurple/internal.h	Sun Jun 17 04:50:18 2007 +0000
+++ b/libpurple/internal.h	Sun Jun 17 05:09:21 2007 +0000
@@ -111,16 +111,10 @@
 # include <unistd.h>
 #endif
 
-#ifndef MAXPATHLEN
-# define MAXPATHLEN 1024
-#endif
-
 #ifndef HOST_NAME_MAX
 # define HOST_NAME_MAX 255
 #endif
 
-#define PATHSIZE 1024
-
 #include <glib.h>
 #if !GLIB_CHECK_VERSION(2,4,0)
 #	define G_MAXUINT32 ((guint32) 0xffffffff)
--- a/libpurple/plugins/startup.py	Sun Jun 17 04:50:18 2007 +0000
+++ b/libpurple/plugins/startup.py	Sun Jun 17 05:09:21 2007 +0000
@@ -25,6 +25,13 @@
 import dbus
 import os
 
+if len(sys.argv) == 1:
+	print "Usage:", sys.argv[0], """<purple-client> [arguments]
+
+Example:
+	""", sys.argv[0], "pidgin -d -c /my/home"
+	sys.exit(1)
+
 home = os.path.expanduser('~/.purple/')
 for arg in range(1, len(sys.argv[1:])):
 	if sys.argv[arg] == "-c":
--- a/libpurple/pounce.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/libpurple/pounce.c	Sun Jun 17 05:09:21 2007 +0000
@@ -1014,6 +1014,20 @@
 	return pounces;
 }
 
+GList *purple_pounces_get_all_for_ui(const char *ui)
+{
+	GList *list = NULL, *iter;
+	g_return_val_if_fail(ui != NULL, NULL);
+
+	for (iter = pounces; iter; iter = iter->next) {
+		PurplePounce *pounce = iter->data;
+		if (pounce->ui_type && strcmp(pounce->ui_type, ui) == 0)
+			list = g_list_prepend(list, pounce);
+	}
+	list = g_list_reverse(list);
+	return list;
+}
+
 static void
 free_pounce_handler(gpointer user_data)
 {
--- a/libpurple/pounce.h	Sun Jun 17 04:50:18 2007 +0000
+++ b/libpurple/pounce.h	Sun Jun 17 05:09:21 2007 +0000
@@ -343,6 +343,17 @@
 GList *purple_pounces_get_all(void);
 
 /**
+ * Returns a list of registered buddy pounces for the ui-type.
+ *
+ * @param ui  The ID of the UI using the core.
+ *
+ * @return The list of buddy pounces. The list should be freed by
+ *         the caller when it's no longer used.
+ * @since  2.1.0
+ */
+GList *purple_pounces_get_all_for_ui(const char *ui);
+
+/**
  * Returns the buddy pounce subsystem handle.
  *
  * @return The subsystem handle.
--- a/libpurple/protocols/oscar/oscar.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Sun Jun 17 05:09:21 2007 +0000
@@ -2827,6 +2827,7 @@
 	va_list ap;
 	guint16 reason;
 	char *destn;
+	PurpleNotifyUserInfo *user_info;
 
 	va_start(ap, fr);
 	reason = (guint16) va_arg(ap, unsigned int);
@@ -2836,12 +2837,12 @@
 	if (destn == NULL)
 		return 1;
 
+	user_info = purple_notify_user_info_new();
 	buf = g_strdup_printf(_("User information not available: %s"), (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason."));
-	if (!purple_conv_present_error(destn, purple_connection_get_account((PurpleConnection*)od->gc), buf)) {
-		g_free(buf);
-		buf = g_strdup_printf(_("User information for %s unavailable:"), destn);
-		purple_notify_error(od->gc, NULL, buf, (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason."));
-	}
+	purple_notify_user_info_add_pair(user_info, NULL, buf);
+	purple_notify_userinfo(od->gc, destn, user_info, NULL, NULL);
+	purple_notify_user_info_destroy(user_info);
+	purple_conv_present_error(destn, purple_connection_get_account(od->gc), buf);
 	g_free(buf);
 
 	return 1;
--- a/libpurple/protocols/qq/group_im.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/libpurple/protocols/qq/group_im.c	Sun Jun 17 05:09:21 2007 +0000
@@ -341,7 +341,7 @@
 	read_packet_dw(data, cursor, data_len, &(im_group->member_uid));
 	read_packet_w(data, cursor, data_len, &unknown);	/* 0x0001? */
 	read_packet_w(data, cursor, data_len, &(im_group->msg_seq));
-	read_packet_dw(data, cursor, data_len, (guint32 *) & (im_group->send_time));
+	read_packet_time(data, cursor, data_len, &im_group->send_time);
 	read_packet_dw(data, cursor, data_len, &unknown4);	/* versionID */
 	/*
 	 * length includes font_attr
--- a/libpurple/protocols/qq/login_logout.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/libpurple/protocols/qq/login_logout.c	Sun Jun 17 05:09:21 2007 +0000
@@ -181,7 +181,7 @@
 	/* 031-032: server listening port */
 	bytes += read_packet_w(data, &cursor, len, &lrop.server_port);
 	/* 033-036: login time for current session */
-	bytes += read_packet_dw(data, &cursor, len, (guint32 *) &lrop.login_time);
+	bytes += read_packet_time(data, &cursor, len, &lrop.login_time);
 	/* 037-062: 26 bytes, unknown */
 	bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.unknown1, 26);
 	/* 063-066: unknown server1 ip address */
@@ -203,7 +203,7 @@
 	/* 123-126: login IP of last session */
 	bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.last_client_ip, 4);
 	/* 127-130: login time of last session */
-	bytes += read_packet_dw(data, &cursor, len, (guint32 *) &lrop.last_login_time);
+	bytes += read_packet_time(data, &cursor, len, &lrop.last_login_time);
 	/* 131-138: 8 bytes unknown */
 	bytes += read_packet_data(data, &cursor, len, (guint8 *) &lrop.unknown6, 8);
 
--- a/libpurple/protocols/qq/packet_parse.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/libpurple/protocols/qq/packet_parse.c	Sun Jun 17 05:09:21 2007 +0000
@@ -65,6 +65,19 @@
 	}
 }
 
+/* read four bytes as "time_t" from buf,
+ * return the number of bytes read if succeeds, otherwise return -1
+ * This function is a wrapper around read_packet_dw() to avoid casting. */
+gint read_packet_time(guint8 *buf, guint8 **cursor, gint buflen, time_t *t)
+{
+	guint32 time;
+	gint ret = read_packet_dw(buf, cursor, buflen, &time);
+	if (ret != -1 ) {
+		*t = time;
+	}
+	return ret;
+}
+
 /* read datalen bytes from buf, 
  * return the number of bytes read if succeeds, otherwise return -1 */
 gint read_packet_data(guint8 *buf, guint8 **cursor, gint buflen, guint8 *data, gint datalen) {
--- a/libpurple/protocols/qq/packet_parse.h	Sun Jun 17 04:50:18 2007 +0000
+++ b/libpurple/protocols/qq/packet_parse.h	Sun Jun 17 05:09:21 2007 +0000
@@ -39,6 +39,7 @@
 gint read_packet_b(guint8 *buf, guint8 **cursor, gint buflen, guint8 *b);
 gint read_packet_w(guint8 *buf, guint8 **cursor, gint buflen, guint16 *w);
 gint read_packet_dw(guint8 *buf, guint8 **cursor, gint buflen, guint32 *dw);
+gint read_packet_time(guint8 *buf, guint8 **cursor, gint buflen, time_t *t);
 gint read_packet_data(guint8 *buf, guint8 **cursor, gint buflen, guint8 *data, gint datalen);
 gint create_packet_b(guint8 *buf, guint8 **cursor, guint8 b);
 gint create_packet_w(guint8 *buf, guint8 **cursor, guint16 w);
--- a/libpurple/protocols/yahoo/yahoo_doodle.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/libpurple/protocols/yahoo/yahoo_doodle.c	Sun Jun 17 05:09:21 2007 +0000
@@ -491,7 +491,8 @@
 
 	/* g_debug_debug("yahoo", "doodle: yahoo_doodle_end()\n"); */
 
-	yahoo_doodle_command_send_shutdown(gc, wb->who);
+	if (gc)
+		yahoo_doodle_command_send_shutdown(gc, wb->who);
 
 	g_free(wb->proto_data);
 }
--- a/libpurple/protocols/zephyr/ZLocations.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/libpurple/protocols/zephyr/ZLocations.c	Sun Jun 17 05:09:21 2007 +0000
@@ -36,7 +36,8 @@
     return (Z_SendLocation(LOGIN_CLASS, LOGIN_USER_FLUSH, ZAUTH, ""));
 }
 
-static char host[MAXHOSTNAMELEN], mytty[MAXPATHLEN];
+static char host[MAXHOSTNAMELEN];
+static char *mytty = NULL;
 static int reenter = 0;
 
 Code_t Z_SendLocation(class, opcode, auth, format)
@@ -87,21 +88,20 @@
 	    }
 #ifndef X_DISPLAY_MISSING
 	    if ((display = getenv("DISPLAY")) && *display) {
-		    (void) strncpy(mytty, display, sizeof(mytty));
+		    mytty = g_strdup(display);
 	    } else {
 #endif
 #ifdef WIN32
-              	    strncpy(mytty, "WinPurple", sizeof(mytty));
+		    mytty = g_strdup("WinPurple");
 #else
 		    ttyp = ttyname(0);
 		    if (ttyp && *ttyp) {
 			p = strchr(ttyp + 1, '/');
-			strcpy(mytty, (p) ? p + 1 : ttyp);
+			mytty = g_strdup((p) ? p + 1 : ttyp);
 		    } else {
-			strncpy(mytty, "unknown", sizeof(mytty));
+			mytty = g_strdup("unknown");
 		    }
 #endif
-		    mytty[sizeof(mytty)-1] = '\0';
 #ifndef X_DISPLAY_MISSING
 	    }
 #endif
@@ -114,7 +114,6 @@
     bptr[1][strlen(bptr[1])-1] = '\0';
     bptr[2] = mytty;
 
-	
     if ((retval = ZSendList(&notice, bptr, 3, auth)) != ZERR_NONE)
 	return (retval);
 
--- a/libpurple/util.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/libpurple/util.c	Sun Jun 17 05:09:21 2007 +0000
@@ -66,8 +66,8 @@
 	unsigned long data_len;
 };
 
-static char custom_home_dir[MAXPATHLEN];
-static char home_dir[MAXPATHLEN] = "";
+static char *custom_user_dir = NULL;
+static char *home_dir = NULL;
 
 PurpleMenuAction *
 purple_menu_action_new(const char *label, PurpleCallback callback, gpointer data,
@@ -2396,27 +2396,22 @@
 const char *
 purple_user_dir(void)
 {
-	if (custom_home_dir != NULL && *custom_home_dir) {
-		strcpy ((char*) &home_dir, (char*) &custom_home_dir);
-	} else if (!*home_dir) {
-		const gchar *hd = purple_home_dir();
-
-		if (hd) {
-			g_strlcpy((char*) &home_dir, hd, sizeof(home_dir));
-			g_strlcat((char*) &home_dir, G_DIR_SEPARATOR_S ".purple",
-					sizeof(home_dir));
-		}
-	}
+	if (custom_user_dir != NULL)
+		return custom_user_dir;
+	else if (!home_dir)
+		home_dir = g_build_filename(purple_home_dir(), ".purple", NULL);
 
 	return home_dir;
 }
 
 void purple_util_set_user_dir(const char *dir)
 {
-	if (dir != NULL && strlen(dir) > 0) {
-		g_strlcpy((char*) &custom_home_dir, dir,
-				sizeof(custom_home_dir));
-	}
+	g_free(custom_user_dir);
+
+	if (dir != NULL && *dir)
+		custom_user_dir = g_strdup(dir);
+	else
+		custom_user_dir = NULL;
 }
 
 int purple_build_dir (const char *path, int mode)
@@ -3135,7 +3130,7 @@
 char *
 purple_str_size_to_units(size_t size)
 {
-	static const char *size_str[4] = { "bytes", "KB", "MB", "GB" };
+	static const char *size_str[4] = { "bytes", "KiB", "MiB", "GiB" };
 	float size_mag;
 	int size_index = 0;
 
--- a/pidgin/gtkft.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/pidgin/gtkft.c	Sun Jun 17 05:09:21 2007 +0000
@@ -130,7 +130,7 @@
 	kbps    = (elapsed > 0 ? (kb_sent / elapsed) : 0);
 
 	if (kbsec != NULL) {
-		*kbsec = g_strdup_printf(_("%.2f KB/s"), kbps);
+		*kbsec = g_strdup_printf(_("%.2f KiB/s"), kbps);
 	}
 
 	if (time_elapsed != NULL)
--- a/pidgin/gtkmain.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/pidgin/gtkmain.c	Sun Jun 17 05:09:21 2007 +0000
@@ -372,6 +372,7 @@
 		       "  -c, --config=DIR    use DIR for config files\n"
 		       "  -d, --debug         print debugging messages to stdout\n"
 		       "  -h, --help          display this help and exit\n"
+		       "  -m, --multiple      do not ensure single instance\n"
 		       "  -n, --nologin       don't automatically login\n"
 		       "  -l, --login[=NAME]  automatically login (optional argument NAME specifies\n"
 		       "                      account(s) to use, separated by commas)\n"
@@ -431,6 +432,7 @@
 	gboolean opt_login = FALSE;
 	gboolean opt_nologin = FALSE;
 	gboolean opt_version = FALSE;
+	gboolean opt_si = TRUE;     /* Check for single instance? */
 	char *opt_config_dir_arg = NULL;
 	char *opt_login_arg = NULL;
 	char *opt_session_arg = NULL;
@@ -457,6 +459,7 @@
 		{"debug",    no_argument,       NULL, 'd'},
 		{"help",     no_argument,       NULL, 'h'},
 		{"login",    optional_argument, NULL, 'l'},
+		{"multiple", no_argument,       NULL, 'm'},
 		{"nologin",  no_argument,       NULL, 'n'},
 		{"session",  required_argument, NULL, 's'},
 		{"version",  no_argument,       NULL, 'v'},
@@ -570,7 +573,7 @@
 	opterr = 1;
 	while ((opt = getopt_long(argc, argv,
 #ifndef _WIN32
-				  "c:dhnl::s:v",
+				  "c:dhmnl::s:v",
 #else
 				  "c:dhnl::v",
 #endif
@@ -602,6 +605,9 @@
 		case 'v':	/* version */
 			opt_version = TRUE;
 			break;
+		case 'm':   /* do not ensure single instance. */
+			opt_si = FALSE;
+			break;
 		case '?':	/* show terse help */
 		default:
 			show_usage(argv[0], TRUE);
@@ -728,7 +734,7 @@
 		abort();
 	}
 
-	if (!purple_core_ensure_single_instance()) {
+	if (opt_si && !purple_core_ensure_single_instance()) {
 		purple_core_quit();
 #ifdef HAVE_SIGNAL_H
 		g_free(segfault_message);
--- a/pidgin/gtkpounce.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/pidgin/gtkpounce.c	Sun Jun 17 05:09:21 2007 +0000
@@ -215,8 +215,8 @@
 
 	gtk_list_store_clear(dialog->model);
 
-	for (pounces = purple_pounces_get_all(); pounces != NULL;
-			pounces = g_list_next(pounces))
+	for (pounces = purple_pounces_get_all_for_ui(PIDGIN_UI); pounces != NULL;
+			pounces = g_list_delete_link(pounces, pounces))
 	{
 		add_pounce_to_treeview(dialog->model, pounces->data);
 	}
--- a/pidgin/gtkutils.c	Sun Jun 17 04:50:18 2007 +0000
+++ b/pidgin/gtkutils.c	Sun Jun 17 05:09:21 2007 +0000
@@ -525,7 +525,7 @@
 {
 	PurplePluginProtocolInfo *prpl_info;
 	const char *protoname = NULL;
-	char buf[MAXPATHLEN];
+	char *tmp;
 	char *filename = NULL;
 	GdkPixbuf *pixbuf;
 
@@ -541,12 +541,14 @@
 	 * Status icons will be themeable too, and then it will look up
 	 * protoname from the theme
 	 */
-	g_snprintf(buf, sizeof(buf), "%s.png", protoname);
+	tmp = g_strconcat(protoname, ".png", NULL);
 
 	filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols",
 				    size == PIDGIN_PRPL_ICON_SMALL ? "16" :
 				    size == PIDGIN_PRPL_ICON_MEDIUM ? "22" : "48",
-				    buf, NULL);
+				    tmp, NULL);
+	g_free(tmp);
+
 	pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
 	g_free(filename);