changeset 15169:630b794db0c8

[gaim-migrate @ 17954] The first batch of plugins from the plugin pack to get moved into gaim proper. This batch includes ONLY the core plugins. I will be adding the gtk plugins shortly. committer: Tailor Script <tailor@pidgin.im>
author Gary Kramlich <grim@reaperworld.com>
date Mon, 11 Dec 2006 05:03:52 +0000
parents 7ad1e078ab55
children 8bc394797096
files libgaim/plugins/Makefile.am libgaim/plugins/Makefile.mingw libgaim/plugins/autoaccept.c libgaim/plugins/autoreply.c libgaim/plugins/buddynote.c libgaim/plugins/newline.c libgaim/plugins/offlinemsg.c
diffstat 7 files changed, 1177 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/libgaim/plugins/Makefile.am	Mon Dec 11 03:40:11 2006 +0000
+++ b/libgaim/plugins/Makefile.am	Mon Dec 11 05:03:52 2006 +0000
@@ -24,8 +24,13 @@
 
 plugindir = $(libdir)/gaim
 
+autoaccept_la_LDFLAGS       = -module -avoid-version
+autoreply_la_LDFLAGS        = -module -avoid-version
+buddynote_la_LDFLAGS        = -module -avoid-version
 idle_la_LDFLAGS             = -module -avoid-version
 log_reader_la_LDFLAGS       = -module -avoid-version
+newline_la_LDFLAGS          = -module -avoid-version
+offlinemsg_la_LDFLAGS       = -module -avoid-version
 psychic_la_LDFLAGS          = -module -avoid-version
 statenotify_la_LDFLAGS      = -module -avoid-version
 
@@ -35,20 +40,34 @@
 if PLUGINS
 
 plugin_LTLIBRARIES = \
+	autoaccept.la       \
+	autoreply.la        \
+	buddynote.la        \
 	idle.la             \
 	log_reader.la       \
+	newline.la          \
+	offlinemsg.la       \
 	psychic.la          \
 	statenotify.la      \
 	$(DBUS_LTLIB)
 
-
+autoaccept_la_SOURCES       = autoaccept.c
+autoreply_la_SOURCES        = autoreply.c
+buddynote_la_SOURCES        = buddynote.c
 idle_la_SOURCES             = idle.c
 log_reader_la_SOURCES       = log_reader.c
+newline_la_SOURCES          = newline.c
+offlinemsg_la_SOURCES       = offlinemsg.c
 psychic_la_SOURCES          = psychic.c
 statenotify_la_SOURCES      = statenotify.c
 
+autoaccept_la_LIBADD        = $(GLIB_LIBS)
+autoreply_la_LIBADD         = $(GLIB_LIBS)
+buddynote_la_LIBADD         = $(GLIB_LIBS)
 idle_la_LIBADD              = $(GLIB_LIBS)
 log_reader_la_LIBADD        = $(GLIB_LIBS)
+newline_la_LIBADD           = $(GLIB_LIBS)
+offlinemsg_la_LIBADD        = $(GLIB_LIBS)
 psychic_la_LIBADD           = $(GLIB_LIBS)
 statenotify_la_LIBADD       = $(GLIB_LIBS)
 
--- a/libgaim/plugins/Makefile.mingw	Mon Dec 11 03:40:11 2006 +0000
+++ b/libgaim/plugins/Makefile.mingw	Mon Dec 11 05:03:52 2006 +0000
@@ -60,8 +60,13 @@
 	$(CC) -shared $@.o $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -o $@
 
 plugins: \
+		autoaccept.dll \
+		autoreply.dll \
+		buddynote.dll \
 		idle.dll \
 		log_reader.dll \
+		newline.dll \
+		offlinemsg.dll \
 		psychic.dll \
 		statenotify.dll
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgaim/plugins/autoaccept.c	Mon Dec 11 05:03:52 2006 +0000
@@ -0,0 +1,273 @@
+/*
+ * Autoaccept - Auto-accept file transfers from selected users
+ * Copyright (C) 2006
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include "internal.h"
+
+#define PLUGIN_ID			"core-plugin_pack-autoaccept"
+#define PLUGIN_NAME			"Autoaccept"
+#define PLUGIN_STATIC_NAME	"Autoaccept"
+#define PLUGIN_SUMMARY		"Auto-accept file transfer requests from selected users."
+#define PLUGIN_DESCRIPTION	"Auto-accept file transfer requests from selected users."
+#define PLUGIN_AUTHOR		"Sadrul H Chowdhury <sadrul@users.sourceforge.net>"
+
+/* System headers */
+#include <glib.h>
+#if GLIB_CHECK_VERSION(2,6,0)
+#	include <glib/gstdio.h>
+#else
+#	include <sys/types.h>
+#	include <sys/stat.h>
+#	define	g_mkdir mkdir
+#endif
+
+/* Gaim headers */
+#include <plugin.h>
+#include <version.h>
+
+#include <blist.h>
+#include <conversation.h>
+#include <ft.h>
+#include <request.h>
+#include <notify.h>
+#include <util.h>
+
+#define PREF_PREFIX		"/plugins/core/" PLUGIN_ID
+#define PREF_PATH		PREF_PREFIX "/path"
+#define PREF_STRANGER	PREF_PREFIX "/reject_stranger"
+#define PREF_NOTIFY		PREF_PREFIX "/notify"
+
+typedef enum
+{
+	FT_ASK,
+	FT_ACCEPT,
+	FT_REJECT
+} AutoAcceptSetting;
+
+static gboolean
+ensure_path_exists(const char *dir)
+{
+	if (!g_file_test(dir, G_FILE_TEST_IS_DIR))
+	{
+		if (gaim_build_dir(dir, S_IRUSR | S_IWUSR | S_IXUSR))
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void
+auto_accept_complete_cb(GaimXfer *xfer, GaimXfer *my)
+{
+	if (xfer == my && gaim_prefs_get_bool(PREF_NOTIFY) &&
+			!gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, xfer->who, xfer->account))
+	{
+		char *message = g_strdup_printf(_("Autoaccepted file transfer of \"%s\" from \"%s\" completed."),
+					xfer->filename, xfer->who);
+		gaim_notify_info(NULL, _("Autoaccept complete"), message, NULL);
+		g_free(message);
+	}
+}
+
+static void
+file_recv_request_cb(GaimXfer *xfer, gpointer handle)
+{
+	GaimAccount *account;
+	GaimBlistNode *node;
+	const char *pref;
+	char *filename;
+	char *dirname;
+
+	account = xfer->account;
+	node = (GaimBlistNode *)gaim_find_buddy(account, xfer->who);
+
+	if (!node)
+	{
+		if (gaim_prefs_get_bool(PREF_STRANGER))
+			xfer->status = GAIM_XFER_STATUS_CANCEL_LOCAL;
+		return;
+	}
+
+	node = node->parent;
+	g_return_if_fail(GAIM_BLIST_NODE_IS_CONTACT(node));
+
+	pref = gaim_prefs_get_string(PREF_PATH);
+	switch (gaim_blist_node_get_int(node, "autoaccept"))
+	{
+		case FT_ASK:
+			break;
+		case FT_ACCEPT:
+			if (ensure_path_exists(pref))
+			{
+				dirname = g_build_filename(pref, xfer->who, NULL);
+
+				if (!ensure_path_exists(dirname))
+				{
+					g_free(dirname);
+					break;
+				}
+				
+				filename = g_build_filename(dirname, xfer->filename, NULL);
+
+				gaim_xfer_request_accepted(xfer, filename);
+
+				g_free(dirname);
+				g_free(filename);
+			}
+			
+			gaim_signal_connect(gaim_xfers_get_handle(), "file-recv-complete", handle,
+								GAIM_CALLBACK(auto_accept_complete_cb), xfer);
+			break;
+		case FT_REJECT:
+			xfer->status = GAIM_XFER_STATUS_CANCEL_LOCAL;
+			break;
+	}
+}
+
+static void
+save_cb(GaimBlistNode *node, int choice)
+{
+	if (GAIM_BLIST_NODE_IS_BUDDY(node))
+		node = node->parent;
+	g_return_if_fail(GAIM_BLIST_NODE_IS_CONTACT(node));
+	gaim_blist_node_set_int(node, "autoaccept", choice);
+}
+
+static void
+set_auto_accept_settings(GaimBlistNode *node, gpointer plugin)
+{
+	char *message;
+
+	if (GAIM_BLIST_NODE_IS_BUDDY(node))
+		node = node->parent;
+	g_return_if_fail(GAIM_BLIST_NODE_IS_CONTACT(node));
+
+	message = g_strdup_printf(_("When a file-transfer request arrives from %s"), 
+					gaim_contact_get_alias((GaimContact *)node));
+	gaim_request_choice(plugin, _("Set Autoaccept Setting"), message,
+						NULL, gaim_blist_node_get_int(node, "autoaccept"),
+						_("_Save"), G_CALLBACK(save_cb),
+						_("_Cancel"), NULL, node,
+						_("Ask"), FT_ASK,
+						_("Auto Accept"), FT_ACCEPT,
+						_("Auto Reject"), FT_REJECT,
+						NULL);
+	g_free(message);
+}
+
+static void
+context_menu(GaimBlistNode *node, GList **menu, gpointer plugin)
+{
+	GaimMenuAction *action;
+
+	if (!GAIM_BLIST_NODE_IS_BUDDY(node) && !GAIM_BLIST_NODE_IS_CONTACT(node))
+		return;
+
+	action = gaim_menu_action_new(_("Autoaccept File Transfers..."),
+					GAIM_CALLBACK(set_auto_accept_settings), plugin, NULL);
+	(*menu) = g_list_prepend(*menu, action);
+}
+
+static gboolean
+plugin_load(GaimPlugin *plugin)
+{
+	gaim_signal_connect(gaim_xfers_get_handle(), "file-recv-request", plugin,
+						GAIM_CALLBACK(file_recv_request_cb), plugin);
+	gaim_signal_connect(gaim_blist_get_handle(), "blist-node-extended-menu", plugin,
+						GAIM_CALLBACK(context_menu), plugin);
+	return TRUE;
+}
+
+static gboolean
+plugin_unload(GaimPlugin *plugin)
+{
+	return TRUE;
+}
+
+static GaimPluginPrefFrame *
+get_plugin_pref_frame(GaimPlugin *plugin)
+{
+	GaimPluginPrefFrame *frame;
+	GaimPluginPref *pref;
+
+	frame = gaim_plugin_pref_frame_new();
+
+	/* XXX: Is there a better way than this? There really should be. */
+	pref = gaim_plugin_pref_new_with_name_and_label(PREF_PATH, _("Path to save the files in\n"
+								"(Please provide the full path)"));
+	gaim_plugin_pref_frame_add(frame, pref);
+
+	pref = gaim_plugin_pref_new_with_name_and_label(PREF_STRANGER,
+					_("Automatically reject from users not in buddy list"));
+	gaim_plugin_pref_frame_add(frame, pref);
+
+	pref = gaim_plugin_pref_new_with_name_and_label(PREF_NOTIFY,
+					_("Notify with a popup when an autoaccepted file transfer is complete\n"
+					  "(only when there's no conversation with the sender)"));
+	gaim_plugin_pref_frame_add(frame, pref);
+
+	return frame;
+}
+
+static GaimPluginUiInfo prefs_info = {
+	get_plugin_pref_frame,
+	0,
+	NULL,
+};
+
+static GaimPluginInfo info = {
+	GAIM_PLUGIN_MAGIC,			/* Magic				*/
+	GAIM_MAJOR_VERSION,			/* Gaim Major Version	*/
+	GAIM_MINOR_VERSION,			/* Gaim Minor Version	*/
+	GAIM_PLUGIN_STANDARD,		/* plugin type			*/
+	NULL,						/* ui requirement		*/
+	0,							/* flags				*/
+	NULL,						/* dependencies			*/
+	GAIM_PRIORITY_DEFAULT,		/* priority				*/
+
+	PLUGIN_ID,					/* plugin id			*/
+	N_(PLUGIN_NAME),			/* name					*/
+	VERSION,					/* version				*/
+	N_(PLUGIN_SUMMARY),			/* summary				*/
+	N_(PLUGIN_DESCRIPTION),		/* description			*/
+	PLUGIN_AUTHOR,				/* author				*/
+	GAIM_WEBSITE,				/* website				*/
+
+	plugin_load,				/* load					*/
+	plugin_unload,				/* unload				*/
+	NULL,						/* destroy				*/
+
+	NULL,						/* ui_info				*/
+	NULL,						/* extra_info			*/
+	&prefs_info,				/* prefs_info			*/
+	NULL						/* actions				*/
+};
+
+static void
+init_plugin(GaimPlugin *plugin) {
+	char *dirname;
+
+	dirname = g_build_filename(gaim_user_dir(), "autoaccept", NULL);
+	gaim_prefs_add_none(PREF_PREFIX);
+	gaim_prefs_add_string(PREF_PATH, dirname);
+	gaim_prefs_add_bool(PREF_STRANGER, TRUE);
+	gaim_prefs_add_bool(PREF_NOTIFY, TRUE);
+	g_free(dirname);
+}
+
+GAIM_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgaim/plugins/autoreply.c	Mon Dec 11 05:03:52 2006 +0000
@@ -0,0 +1,435 @@
+/*
+ * Autoreply - Autoreply feature for all the protocols
+ * Copyright (C) 2005
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include "internal.h"
+
+#define PLUGIN_ID			"core-plugin_pack-autoreply"
+#define PLUGIN_NAME			"Autoreply"
+#define PLUGIN_STATIC_NAME	"Autoreply"
+#define PLUGIN_SUMMARY		"Autoreply for all the protocols"
+#define PLUGIN_DESCRIPTION	"This plugin lets you set autoreply message for any protocol. "\
+							"You can set the global autoreply message from the Plugin-options dialog. " \
+							"To set some specific autoreply message for a particular buddy, right click " \
+							"on the buddy in the buddy-list window. To set autoreply messages for some " \
+							"account, go to the `Advanced' tab of the Account-edit dialog."
+#define PLUGIN_AUTHOR		"Sadrul Habib Chowdhury <sadrul@users.sourceforge.net>"
+
+/* System headers */
+#include <glib.h>
+
+/* Gaim headers */
+#include <account.h>
+#include <accountopt.h>
+#include <blist.h>
+#include <conversation.h>
+#include <plugin.h>
+#include <pluginpref.h>
+#include <request.h>
+#include <savedstatuses.h>
+#include <status.h>
+#include <util.h>
+#include <version.h>
+
+#define	PREFS_PREFIX		"/core/" PLUGIN_ID
+#define	PREFS_IDLE			PREFS_PREFIX "/idle"
+#define	PREFS_AWAY			PREFS_PREFIX "/away"
+#define	PREFS_GLOBAL		PREFS_PREFIX "/global"
+#define	PREFS_MINTIME		PREFS_PREFIX "/mintime"
+#define	PREFS_MAXSEND		PREFS_PREFIX "/maxsend"
+#define	PREFS_USESTATUS		PREFS_PREFIX "/usestatus"
+
+typedef struct _GaimAutoReply GaimAutoReply;
+
+struct _GaimAutoReply
+{
+	GaimBuddy *buddy;
+	char *reply;
+};
+
+typedef enum
+{
+	STATUS_NEVER,
+	STATUS_ALWAYS,
+	STATUS_FALLBACK
+} UseStatusMessage;
+
+static GHashTable *options = NULL;
+
+/**
+ * Returns the auto-reply message for buddy
+ */
+static const char *
+get_autoreply_message(GaimBuddy *buddy, GaimAccount *account)
+{
+	const char *reply = NULL;
+	UseStatusMessage use_status;
+
+	use_status = gaim_prefs_get_int(PREFS_USESTATUS);
+	if (use_status == STATUS_ALWAYS)
+	{
+		GaimStatus *status = gaim_account_get_active_status(account);
+		GaimStatusType *type = gaim_status_get_type(status);
+		if (gaim_status_type_get_attr(type, "message") != NULL)
+			reply = gaim_status_get_attr_string(status, "message");
+		else
+			reply = gaim_savedstatus_get_message(gaim_savedstatus_get_current());
+	}
+
+	if (!reply && buddy)
+	{
+		/* Is there any special auto-reply for this buddy? */
+		reply = gaim_blist_node_get_string((GaimBlistNode*)buddy, "autoreply");
+
+		if (!reply && GAIM_BLIST_NODE_IS_BUDDY((GaimBlistNode*)buddy))
+		{
+			/* Anything for the contact, then? */
+			reply = gaim_blist_node_get_string(((GaimBlistNode*)buddy)->parent, "autoreply");
+		}
+	}
+
+	if (!reply)
+	{
+		/* Is there any specific auto-reply for this account? */
+		reply = gaim_account_get_string(account, "autoreply", NULL);
+	}
+
+	if (!reply)
+	{
+		/* Get the global auto-reply message */
+		reply = gaim_prefs_get_string(PREFS_GLOBAL);
+	}
+
+	if (*reply == ' ')
+		reply = NULL;
+
+	if (!reply && use_status == STATUS_FALLBACK)
+		reply = gaim_status_get_attr_string(gaim_account_get_active_status(account), "message");
+
+	return reply;
+}
+
+static void
+written_msg(GaimAccount *account, const char *who, const char *message,
+				GaimConversation *conv, GaimMessageFlags flags, gpointer null)
+{
+	GaimBuddy *buddy;
+	GaimPresence *presence;
+	const char *reply = NULL;
+	gboolean trigger = FALSE;
+
+	if (!(flags & GAIM_MESSAGE_RECV))
+		return;
+
+	if (!message || !*message)
+		return;
+
+	/* Do not send an autoreply for an autoreply */
+	if (flags & GAIM_MESSAGE_AUTO_RESP)
+		return;
+
+	g_return_if_fail(gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM);
+
+	presence = gaim_account_get_presence(account);
+
+	if (gaim_prefs_get_bool(PREFS_AWAY) && !gaim_presence_is_available(presence))
+		trigger = TRUE;
+	if (gaim_prefs_get_bool(PREFS_IDLE) && gaim_presence_is_idle(presence))
+	   trigger = TRUE;
+
+	if (!trigger)
+		return;	
+
+	buddy = gaim_find_buddy(account, who);
+	reply = get_autoreply_message(buddy, account);
+
+	if (reply)
+	{
+		GaimConnection *gc;
+		GaimMessageFlags flag = GAIM_MESSAGE_SEND;
+		time_t last_sent, now;
+		int count_sent, maxsend;
+
+		last_sent = GPOINTER_TO_INT(gaim_conversation_get_data(conv, "autoreply_lastsent"));
+		now = time(NULL);
+
+		/* Have we spent enough time after our last autoreply? */
+		if (now - last_sent >= (gaim_prefs_get_int(PREFS_MINTIME)*60))
+		{
+			count_sent = GPOINTER_TO_INT(gaim_conversation_get_data(conv, "autoreply_count"));
+			maxsend = gaim_prefs_get_int(PREFS_MAXSEND);
+
+			/* Have we sent the autoreply enough times? */
+			if (count_sent < maxsend || maxsend == -1)
+			{
+				gaim_conversation_set_data(conv, "autoreply_count", GINT_TO_POINTER(++count_sent));
+				gaim_conversation_set_data(conv, "autoreply_lastsent", GINT_TO_POINTER(now));
+				gc = gaim_account_get_connection(account);
+				if (gc->flags & GAIM_CONNECTION_AUTO_RESP)
+					flag |= GAIM_MESSAGE_AUTO_RESP;
+				serv_send_im(gc, who, reply, flag);
+				gaim_conv_im_write(GAIM_CONV_IM(conv), NULL, reply, flag, time(NULL));
+			}
+		}
+	}
+}
+
+static void
+set_auto_reply_cb(GaimBlistNode *node, char *message)
+{
+	if (!message || !*message)
+		message = " ";
+	gaim_blist_node_set_string(node, "autoreply", message);
+}
+
+static void
+set_auto_reply(GaimBlistNode *node, gpointer plugin)
+{
+	char *message;
+	GaimBuddy *buddy;
+	GaimAccount *account;
+	GaimConnection *gc;
+
+	if (GAIM_BLIST_NODE_IS_BUDDY(node))
+		buddy = (GaimBuddy *)node;
+	else
+		buddy = gaim_contact_get_priority_buddy((GaimContact*)node);
+
+	account = gaim_buddy_get_account(buddy);
+	gc = gaim_account_get_connection(account);
+
+	/* XXX: There should be a way to reset to the default/account-default autoreply */
+
+	message = g_strdup_printf(_("Set autoreply message for %s"),
+					gaim_buddy_get_contact_alias(buddy));
+	gaim_request_input(plugin, _("Set Autoreply Message"), message,
+					_("The following message will be sent to the buddy when "
+						"the buddy sends you a message and autoreply is enabled."),
+					get_autoreply_message(buddy, account), TRUE, FALSE,
+					(gc->flags & GAIM_CONNECTION_HTML) ? "html" : NULL,
+					_("_Save"), G_CALLBACK(set_auto_reply_cb),
+					_("_Cancel"), NULL, node);
+	g_free(message);
+}
+
+static void
+context_menu(GaimBlistNode *node, GList **menu, gpointer plugin)
+{
+	GaimMenuAction *action;
+
+	if (!GAIM_BLIST_NODE_IS_BUDDY(node) && !GAIM_BLIST_NODE_IS_CONTACT(node))
+		return;
+
+	action = gaim_menu_action_new(_("Set _Autoreply Message"),
+					GAIM_CALLBACK(set_auto_reply), plugin, NULL);
+	(*menu) = g_list_prepend(*menu, action);
+}
+
+static void
+add_option_for_protocol(GaimPlugin *plg)
+{
+	GaimPluginProtocolInfo *info = GAIM_PLUGIN_PROTOCOL_INFO(plg);
+	GaimAccountOption *option;
+
+	option = gaim_account_option_string_new(_("Autoreply message"), "autoreply", NULL);
+	info->protocol_options = g_list_append(info->protocol_options, option);
+
+	if (!g_hash_table_lookup(options, plg))
+		g_hash_table_insert(options, plg, option);
+}
+
+static void
+remove_option_for_protocol(GaimPlugin *plg)
+{
+	GaimPluginProtocolInfo *info = GAIM_PLUGIN_PROTOCOL_INFO(plg);
+	GaimAccountOption *option = g_hash_table_lookup(options, plg);
+
+	if (g_list_find(info->protocol_options, option))
+	{
+		info->protocol_options = g_list_remove(info->protocol_options, option);
+		gaim_account_option_destroy(option);
+		g_hash_table_remove(options, plg);
+	}
+}
+
+static void
+plugin_load_cb(GaimPlugin *plugin, gboolean load)
+{
+	if (plugin->info && plugin->info->type == GAIM_PLUGIN_PROTOCOL)
+	{
+		if (load)
+			add_option_for_protocol(plugin);
+		else
+			remove_option_for_protocol(plugin);
+	}
+}
+
+static gboolean
+plugin_load(GaimPlugin *plugin)
+{
+	GList *list;
+
+	gaim_signal_connect(gaim_conversations_get_handle(), "wrote-im-msg", plugin,
+						GAIM_CALLBACK(written_msg), NULL);
+	gaim_signal_connect(gaim_blist_get_handle(), "blist-node-extended-menu", plugin,
+						GAIM_CALLBACK(context_menu), plugin);
+	gaim_signal_connect(gaim_plugins_get_handle(), "plugin-load", plugin,
+						GAIM_CALLBACK(plugin_load_cb), GINT_TO_POINTER(TRUE));
+	gaim_signal_connect(gaim_plugins_get_handle(), "plugin-unload", plugin,
+						GAIM_CALLBACK(plugin_load_cb), GINT_TO_POINTER(FALSE));
+
+	/* Perhaps it's necessary to do this after making sure the prpl-s have been loaded? */
+	options = g_hash_table_new(g_direct_hash, g_direct_equal);
+	list = gaim_plugins_get_protocols();
+	while (list)
+	{
+		add_option_for_protocol(list->data);
+		list = list->next;
+	}
+	
+	return TRUE;
+}
+
+static gboolean
+plugin_unload(GaimPlugin *plugin)
+{
+	GList *list;
+
+	if (options == NULL)
+		return TRUE;
+
+	list = gaim_plugins_get_protocols();
+	while (list)
+	{
+		remove_option_for_protocol(list->data);
+		list = list->next;
+	}
+	g_hash_table_destroy(options);
+	options = NULL;
+
+	return TRUE;
+}
+
+static GaimPluginPrefFrame *
+get_plugin_pref_frame(GaimPlugin *plugin)
+{
+	GaimPluginPrefFrame *frame;
+	GaimPluginPref *pref;
+
+	frame = gaim_plugin_pref_frame_new();
+
+	pref = gaim_plugin_pref_new_with_label(_("Send autoreply messages when"));
+	gaim_plugin_pref_frame_add(frame, pref);
+
+	pref = gaim_plugin_pref_new_with_name_and_label(PREFS_AWAY,
+					_("When my account is _away"));
+	gaim_plugin_pref_frame_add(frame, pref);
+
+	pref = gaim_plugin_pref_new_with_name_and_label(PREFS_IDLE,
+					_("When my account is _idle"));
+	gaim_plugin_pref_frame_add(frame, pref);
+
+	pref = gaim_plugin_pref_new_with_name_and_label(PREFS_GLOBAL,
+					_("_Default reply"));
+	gaim_plugin_pref_set_type(pref, GAIM_PLUGIN_PREF_STRING_FORMAT);
+	gaim_plugin_pref_set_format_type(pref,
+				GAIM_STRING_FORMAT_TYPE_MULTILINE | GAIM_STRING_FORMAT_TYPE_HTML);
+	gaim_plugin_pref_frame_add(frame, pref);
+
+	pref = gaim_plugin_pref_new_with_label(_("Status message"));
+	gaim_plugin_pref_frame_add(frame, pref);
+
+	pref = gaim_plugin_pref_new_with_name_and_label(PREFS_USESTATUS,
+						_("Autoreply with status message"));
+	gaim_plugin_pref_set_type(pref, GAIM_PLUGIN_PREF_CHOICE);
+	gaim_plugin_pref_add_choice(pref, _("Never"),	
+						GINT_TO_POINTER(STATUS_NEVER));
+	gaim_plugin_pref_add_choice(pref, _("Always when there is a status message"),
+						GINT_TO_POINTER(STATUS_ALWAYS));
+	gaim_plugin_pref_add_choice(pref, _("Only when there's no autoreply message"),
+						GINT_TO_POINTER(STATUS_FALLBACK));
+
+	gaim_plugin_pref_frame_add(frame, pref);
+
+	pref = gaim_plugin_pref_new_with_label(_("Delay between autoreplies"));
+	gaim_plugin_pref_frame_add(frame, pref);
+
+	pref = gaim_plugin_pref_new_with_name_and_label(PREFS_MINTIME,
+					_("_Minimum delay (mins)"));
+	gaim_plugin_pref_set_bounds(pref, 0, 9999);
+	gaim_plugin_pref_frame_add(frame, pref);
+
+	pref = gaim_plugin_pref_new_with_label(_("Times to send autoreplies"));
+	gaim_plugin_pref_frame_add(frame, pref);
+
+	pref = gaim_plugin_pref_new_with_name_and_label(PREFS_MAXSEND,
+					_("Ma_ximum count"));
+	gaim_plugin_pref_set_bounds(pref, 0, 9999);
+	gaim_plugin_pref_frame_add(frame, pref);
+
+	return frame;
+}
+
+static GaimPluginUiInfo prefs_info = {
+	get_plugin_pref_frame,
+	0,
+	NULL
+};
+
+static GaimPluginInfo info = {
+	GAIM_PLUGIN_MAGIC,			/* Magic				*/
+	GAIM_MAJOR_VERSION,			/* Gaim Major Version	*/
+	GAIM_MINOR_VERSION,			/* Gaim Minor Version	*/
+	GAIM_PLUGIN_STANDARD,		/* plugin type			*/
+	NULL,						/* ui requirement		*/
+	0,							/* flags				*/
+	NULL,						/* dependencies			*/
+	GAIM_PRIORITY_DEFAULT,		/* priority				*/
+
+	PLUGIN_ID,					/* plugin id			*/
+	N_(PLUGIN_NAME),			/* name					*/
+	VERSION,					/* version				*/
+	N_(PLUGIN_SUMMARY),			/* summary				*/
+	N_(PLUGIN_DESCRIPTION),		/* description			*/
+	PLUGIN_AUTHOR,				/* author				*/
+	GAIM_WEBSITE,				/* website				*/
+
+	plugin_load,				/* load					*/
+	plugin_unload,				/* unload				*/
+	NULL,						/* destroy				*/
+
+	NULL,						/* ui_info				*/
+	NULL,						/* extra_info			*/
+	&prefs_info,				/* prefs_info			*/
+	NULL						/* actions				*/
+};
+
+static void
+init_plugin(GaimPlugin *plugin)
+{
+	gaim_prefs_add_none(PREFS_PREFIX);
+	gaim_prefs_add_bool(PREFS_IDLE, TRUE);
+	gaim_prefs_add_bool(PREFS_AWAY, TRUE);
+	gaim_prefs_add_string(PREFS_GLOBAL, _("I am currently not available. Please leave your message, "
+							"and I will get back to you as soon as possible."));
+	gaim_prefs_add_int(PREFS_MINTIME, 10);
+	gaim_prefs_add_int(PREFS_MAXSEND, 10);
+	gaim_prefs_add_int(PREFS_USESTATUS, STATUS_NEVER);
+}
+
+GAIM_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgaim/plugins/buddynote.c	Mon Dec 11 05:03:52 2006 +0000
@@ -0,0 +1,110 @@
+/*
+ * BuddyNote - Store notes on particular buddies
+ * Copyright (C) 2004 Stu Tomlinson <stu@nosnilmot.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include "internal.h"
+
+#include <debug.h>
+#include <notify.h>
+#include <request.h>
+#include <signals.h>
+#include <util.h>
+#include <version.h>
+
+static void
+dont_do_it_cb(GaimBlistNode *node, const char *note)
+{
+}
+
+static void
+do_it_cb(GaimBlistNode *node, const char *note)
+{
+	gaim_blist_node_set_string(node, "notes", note);
+}
+
+static void
+buddynote_edit_cb(GaimBlistNode *node, gpointer data)
+{
+	const char *note;
+
+	note = gaim_blist_node_get_string(node, "notes");
+
+	gaim_request_input(node, _("Notes"),
+					   _("Enter your notes below..."),
+					   NULL,
+					   note, TRUE, FALSE, "html",
+					   _("Save"), G_CALLBACK(do_it_cb),
+					   _("Cancel"), G_CALLBACK(dont_do_it_cb),
+					   node);
+}
+
+static void
+buddynote_extended_menu_cb(GaimBlistNode *node, GList **m)
+{
+	GaimMenuAction *bna = NULL;
+
+	*m = g_list_append(*m, bna);
+	bna = gaim_menu_action_new(_("Edit Notes..."), GAIM_CALLBACK(buddynote_edit_cb), NULL, NULL);
+	*m = g_list_append(*m, bna);
+}
+
+static gboolean
+plugin_load(GaimPlugin *plugin)
+{
+
+	gaim_signal_connect(gaim_blist_get_handle(), "blist-node-extended-menu",
+						plugin, GAIM_CALLBACK(buddynote_extended_menu_cb), NULL);
+
+	return TRUE;
+}
+
+static GaimPluginInfo info =
+{
+	GAIM_PLUGIN_MAGIC,
+	GAIM_MAJOR_VERSION,								/**< major version	*/
+	GAIM_MINOR_VERSION,
+	GAIM_PLUGIN_STANDARD,							/**< type			*/
+	NULL,											/**< ui_requirement	*/
+	0,												/**< flags			*/
+	NULL,											/**< dependencies	*/
+	GAIM_PRIORITY_DEFAULT,							/**< priority		*/
+
+	"core-plugin_pack-buddynote",					/**< id				*/
+	N_("Buddy Notes"),								/**< name			*/
+	VERSION,										/**< version		*/
+	N_("Store notes on particular buddies."),		/**  summary		*/
+	N_("Adds the option to store notes for buddies "
+	   "on your buddy list."),						/**  description	*/
+	"Stu Tomlinson <stu@nosnilmot.com>",			/**< author			*/
+	GAIM_WEBSITE,									/**< homepage		*/
+
+	plugin_load,									/**< load			*/
+	NULL,											/**< unload			*/
+	NULL,											/**< destroy		*/
+
+	NULL,											/**< ui_info		*/
+	NULL,											/**< extra_info		*/
+	NULL,											/**< prefs_info		*/
+	NULL											/**< actions		*/
+};
+
+
+static void
+init_plugin(GaimPlugin *plugin) {
+}
+
+GAIM_INIT_PLUGIN(buddynote, init_plugin, info)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgaim/plugins/newline.c	Mon Dec 11 05:03:52 2006 +0000
@@ -0,0 +1,95 @@
+/*
+ * Displays messages on a new line, below the nick
+ * Copyright (C) 2004 Stu Tomlinson <stu@nosnilmot.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include "internal.h"
+
+#include <string.h>
+
+#include <conversation.h>
+#include <debug.h>
+#include <plugin.h>
+#include <signals.h>
+#include <util.h>
+#include <version.h>
+
+static gboolean
+addnewline_msg_cb(GaimAccount *account, char *sender, char **message,
+					 GaimConversation *conv, int *flags, void *data)
+{
+	if (g_ascii_strncasecmp(*message, "/me ", strlen("/me "))) {
+		char *tmp = g_strdup_printf("\n%s", *message);
+		g_free(*message);
+		*message = tmp;
+	}
+
+	return FALSE;
+}
+
+static gboolean
+plugin_load(GaimPlugin *plugin)
+{
+	void *conversation = gaim_conversations_get_handle();
+
+	gaim_signal_connect(conversation, "displaying-im-msg",
+						plugin, GAIM_CALLBACK(addnewline_msg_cb), NULL);
+	gaim_signal_connect(conversation, "displaying-chat-msg",
+						plugin, GAIM_CALLBACK(addnewline_msg_cb), NULL);
+	gaim_signal_connect(conversation, "receiving-im-msg",
+						plugin, GAIM_CALLBACK(addnewline_msg_cb), NULL);
+	gaim_signal_connect(conversation, "receiving-chat-msg",
+						plugin, GAIM_CALLBACK(addnewline_msg_cb), NULL);
+
+	return TRUE;
+}
+
+static GaimPluginInfo info =
+{
+	GAIM_PLUGIN_MAGIC,								/**< magic			*/
+	GAIM_MAJOR_VERSION,								/**< major version	*/
+	GAIM_MINOR_VERSION,								/**< minor version	*/
+	GAIM_PLUGIN_STANDARD,							/**< type			*/
+	NULL,											/**< ui_requirement	*/
+	0,												/**< flags			*/
+	NULL,											/**< dependencies	*/
+	GAIM_PRIORITY_DEFAULT,							/**< priority		*/
+
+	"core-plugin_pack-newline",						/**< id				*/
+	N_("New Line"),									/**< name			*/
+	VERSION,										/**< version		*/
+	N_("Prepends a newline to displayed message."),	/**  summary		*/
+	N_("Prepends a newline to messages so that the "
+	   "test of the message appears below the "
+	   "screen name in the conversation window."),	/**  description	*/
+	"Stu Tomlinson <stu@nosnilmot.com>",			/**< author			*/
+	GAIM_WEBSITE,									/**< homepage		*/
+
+	plugin_load,									/**< load			*/
+	NULL,											/**< unload			*/
+	NULL,											/**< destroy		*/
+
+	NULL,											/**< ui_info		*/
+	NULL,											/**< extra_info		*/
+	NULL,											/**< prefs_info		*/
+	NULL											/**< actions		*/
+};
+
+static void
+init_plugin(GaimPlugin *plugin) {
+}
+
+GAIM_INIT_PLUGIN(lastseen, init_plugin, info)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgaim/plugins/offlinemsg.c	Mon Dec 11 05:03:52 2006 +0000
@@ -0,0 +1,239 @@
+/*
+ * Offline Message Emulation - Save messages sent to an offline user as pounce
+ * Copyright (C) 2004
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include "internal.h"
+
+#define PLUGIN_ID			"core-plugin_pack-offlinemsg"
+#define PLUGIN_NAME			"Offline Message Emulation"
+#define PLUGIN_STATIC_NAME	"offlinemsg"
+#define PLUGIN_SUMMARY		"Save messages sent to an offline user as pounce."
+#define PLUGIN_DESCRIPTION	"Save messages sent to an offline user as pounce."
+#define PLUGIN_AUTHOR		"Sadrul H Chowdhury <sadrul@users.sourceforge.net>"
+
+/* Gaim headers */
+#include <version.h>
+
+#include <blist.h>
+#include <conversation.h>
+#include <core.h>
+#include <debug.h>
+#include <pounce.h>
+#include <request.h>
+
+#define	PREF_PREFIX		"/plugins/core/" PLUGIN_ID
+#define	PREF_ALWAYS		PREF_PREFIX "/always"
+
+typedef struct _OfflineMsg OfflineMsg;
+
+typedef enum
+{
+	OFFLINE_MSG_NONE,
+	OFFLINE_MSG_YES,
+	OFFLINE_MSG_NO
+} OfflineMessageSetting;
+
+struct _OfflineMsg
+{
+	GaimAccount *account;
+	GaimConversation *conv;
+	char *who;
+	char *message;
+};
+
+static void
+discard_data(OfflineMsg *offline)
+{
+	g_free(offline->who);
+	g_free(offline->message);
+	g_free(offline);
+}
+
+static void
+cancel_poune(OfflineMsg *offline)
+{
+	gaim_conversation_set_data(offline->conv, "plugin_pack:offlinemsg",
+				GINT_TO_POINTER(OFFLINE_MSG_NO));
+	gaim_conv_im_send_with_flags(GAIM_CONV_IM(offline->conv), offline->message, 0);
+	discard_data(offline);
+}
+
+static void
+record_pounce(OfflineMsg *offline)
+{
+	GaimPounce *pounce;
+	GaimPounceEvent event;
+	GaimPounceOption option;
+	GaimConversation *conv;
+
+	event = GAIM_POUNCE_SIGNON;
+	option = GAIM_POUNCE_OPTION_NONE;
+
+	pounce = gaim_pounce_new(gaim_core_get_ui(), offline->account, offline->who,
+					event, option);
+
+	gaim_pounce_action_set_enabled(pounce, "send-message", TRUE);
+	gaim_pounce_action_set_attribute(pounce, "send-message", "message", offline->message);
+ 
+	conv = offline->conv;
+	if (!gaim_conversation_get_data(conv, "plugin_pack:offlinemsg"))
+		gaim_conversation_write(conv, NULL, _("The rest of the messages will be saved "
+							"as pounce. You can edit/delete the pounce from the `Buddy "
+							"Pounce' dialog."),
+							GAIM_MESSAGE_SYSTEM, time(NULL));
+	gaim_conversation_set_data(conv, "plugin_pack:offlinemsg",
+				GINT_TO_POINTER(OFFLINE_MSG_YES));
+
+	gaim_conv_im_write(GAIM_CONV_IM(conv), offline->who, offline->message,
+				GAIM_MESSAGE_SEND, time(NULL));
+
+	discard_data(offline);
+}
+
+static void
+sending_msg_cb(GaimAccount *account, const char *who, char **message, gpointer handle)
+{
+	GaimBuddy *buddy;
+	OfflineMsg *offline;
+	GaimConversation *conv;
+	OfflineMessageSetting setting;
+
+	buddy = gaim_find_buddy(account, who);
+	if (!buddy)
+		return;
+
+	if (gaim_presence_is_online(gaim_buddy_get_presence(buddy)))
+		return;
+
+	if (gaim_account_supports_offline_message(account, buddy))
+	{
+		gaim_debug_info("offlinemsg", "Account \"%s\" supports offline message.",
+					gaim_account_get_username(account));
+		return;
+	}
+
+	conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM,
+					who, account);
+
+	if (!conv)
+		return;
+
+	setting = GPOINTER_TO_INT(gaim_conversation_get_data(conv, "plugin_pack:offlinemsg"));
+	if (setting == OFFLINE_MSG_NO)
+		return;
+
+	offline = g_new0(OfflineMsg, 1);
+	offline->conv = conv;
+	offline->account = account;
+	offline->who = g_strdup(who);
+	offline->message = *message;
+	*message = NULL;
+
+	if (gaim_prefs_get_bool(PREF_ALWAYS) || setting == OFFLINE_MSG_YES)
+		record_pounce(offline);
+	else if (setting == OFFLINE_MSG_NONE)
+	{
+		char *ask;
+		ask = g_strdup_printf(_("\"%s\" is currently offline. Do you want to save the "
+						"rest of the messages in a pounce and automatically send them "
+						"when \"%s\" logs back in?"), who, who);
+	
+		gaim_request_action(handle, _("Offline Message"), ask,
+					_("You can edit/delete the pounce from the `Buddy Pounces' dialog"),
+					1, offline, 2,
+					_("Yes"), record_pounce,
+					_("No"), cancel_poune);
+		g_free(ask);
+	}
+}
+
+static gboolean
+plugin_load(GaimPlugin *plugin)
+{
+	gaim_signal_connect(gaim_conversations_get_handle(), "sending-im-msg",
+					plugin, GAIM_CALLBACK(sending_msg_cb), plugin);
+	return TRUE;
+}
+
+static gboolean
+plugin_unload(GaimPlugin *plugin)
+{
+	return TRUE;
+}
+
+static GaimPluginPrefFrame *
+get_plugin_pref_frame(GaimPlugin *plugin)
+{
+	GaimPluginPrefFrame *frame;
+	GaimPluginPref *pref;
+
+	frame = gaim_plugin_pref_frame_new();
+
+	pref = gaim_plugin_pref_new_with_label(_("Save offline messages in pounce"));
+	gaim_plugin_pref_frame_add(frame, pref);
+
+	pref = gaim_plugin_pref_new_with_name_and_label(PREF_ALWAYS,
+					_("Do not ask. Always save in pounce."));
+	gaim_plugin_pref_frame_add(frame, pref);
+
+	return frame;
+}
+
+static GaimPluginUiInfo prefs_info = {
+	get_plugin_pref_frame,
+	0,
+	NULL
+};
+
+static GaimPluginInfo info =
+{
+	GAIM_PLUGIN_MAGIC,			/* Magic				*/
+	GAIM_MAJOR_VERSION,			/* Gaim Major Version	*/
+	GAIM_MINOR_VERSION,			/* Gaim Minor Version	*/
+	GAIM_PLUGIN_STANDARD,		/* plugin type			*/
+	NULL,						/* ui requirement		*/
+	0,							/* flags				*/
+	NULL,						/* dependencies			*/
+	GAIM_PRIORITY_DEFAULT,		/* priority				*/
+
+	PLUGIN_ID,					/* plugin id			*/
+	N_(PLUGIN_NAME),			/* name					*/
+	VERSION,					/* version				*/
+	N_(PLUGIN_SUMMARY),			/* summary				*/
+	N_(PLUGIN_DESCRIPTION),		/* description			*/
+	PLUGIN_AUTHOR,				/* author				*/
+	GAIM_WEBSITE,				/* website				*/
+
+	plugin_load,				/* load					*/
+	plugin_unload,				/* unload				*/
+	NULL,						/* destroy				*/
+
+	NULL,						/* ui_info				*/
+	NULL,						/* extra_info			*/
+	&prefs_info,				/* prefs_info			*/
+	NULL						/* actions				*/
+};
+
+static void
+init_plugin(GaimPlugin *plugin)
+{
+	gaim_prefs_add_none(PREF_PREFIX);
+	gaim_prefs_add_bool(PREF_ALWAYS, FALSE);
+}
+
+GAIM_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info)