pidgin/purple-plugin-pack

merge of '50af3299b6aaead836d1bfd9a89168a3a410726b'
org.guifications.plugins
2008-04-23, sadrul
8af9501f6312
merge of '50af3299b6aaead836d1bfd9a89168a3a410726b'
and '7775e4a7ba416a8e3da2560f8c1769581b430738'
--- a/ChangeLog Wed Apr 23 05:09:46 2008 -0400
+++ b/ChangeLog Wed Apr 23 05:10:02 2008 -0400
@@ -1,6 +1,12 @@
Version 2.4.0mtn:
* Merged the Autoprofile plugin into our build system.
* Fixed convbadger's failure to update on conversation switch.
+ * Added Ike Gingerich's colorize plugin
+ * Added Ike Gingerich's splitter plugin
+ * Fixed dewysiwygification's debug messages not properly ending lines.
+ * Added google plugin for "I'm Feeling Lucky" searches.
+ * Fixed aspell dependency in switchspell (fixes gentoo bug #196693)
+ * Added nodashi's manualsize plugin
Version 2.3.0: 03/17/08
* Fixed a typo in irc-more's source that allowed a potential double-free
--- a/Makefile.am Wed Apr 23 05:09:46 2008 -0400
+++ b/Makefile.am Wed Apr 23 05:10:02 2008 -0400
@@ -22,9 +22,13 @@
po/Makefile.in.in \
po/Makefile.mingw
+if INSTALL_I18N
+PO_DIR=po
+endif
+
DIST_SUBDIRS = common doc m4 po $(PP_PURPLE) $(PP_PIDGIN) $(PP_FINCH)
-SUBDIRS = common doc m4 po $(PP_PURPLE_BUILD) $(PP_PIDGIN_BUILD) $(PP_FINCH_BUILD)
+SUBDIRS = common doc m4 $(PO_DIR) $(PP_PURPLE_BUILD) $(PP_PIDGIN_BUILD) $(PP_FINCH_BUILD)
DISTCLEANFILES=\
pp_config.h \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/colorize/Makefile.am Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,26 @@
+EXTRA_DIST = .purple-plugin .build Makefile.mingw
+
+colorizedir = $(PURPLE_LIBDIR)
+
+colorize_la_LDFLAGS = -module -avoid-version
+
+if HAVE_PURPLE
+
+colorize_LTLIBRARIES = colorize.la
+
+colorize_la_SOURCES = \
+ colorize.c
+
+colorize_la_LIBADD = \
+ $(GLIB_LIBS) \
+ $(PURPLE_LIBS)
+
+endif
+
+AM_CPPFLAGS = \
+ -DLIBDIR=\"$(PURPLE_LIBDIR)\" \
+ -DDATADIR=\"$(PURPLE_DATADIR)\" \
+ -DPIXMAPSDIR=\"$(PURPLE_PIXMAPSDIR)\" \
+ $(DEBUG_CFLAGS) \
+ $(PURPLE_CFLAGS)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/colorize/Makefile.mingw Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,12 @@
+#
+# Makefile.mingw
+#
+# Description: Makefile for dice plugin.
+#
+
+PP_TOP := ..
+
+PP = colorize
+
+include $(PP_TOP)/win_pp.mak
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/colorize/colorize.c Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,298 @@
+/* Gaim Colorize Plug-in v0.2
+ *
+ * Colorizes outgoing text to a gradient of specified starting and
+ * and ending values.
+ *
+ * TODO:
+ * - echo color formatting to local color log
+ * - fix HTML-mixed messages (currently strips all HTML)
+ *
+ * Copyright (C) 2005, Ike Gingerich <ike_@users.sourceforge.net>
+ *
+ * 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 "../common/pp_internal.h"
+
+#include <version.h>
+#include <plugin.h>
+#include <util.h>
+#include <debug.h>
+
+#define PLUGIN_ID "core-plugin_pack-colorize"
+#define PLUGIN_AUTHOR "Ike Gingerich <ike_@users.sourceforge.net>"
+
+#define PREFS_PREFIX "/plugins/core/" PLUGIN_ID
+#define PREFS_I_RED PREFS_PREFIX "/initial_r"
+#define PREFS_I_GREEN PREFS_PREFIX "/initial_g"
+#define PREFS_I_BLUE PREFS_PREFIX "/initial_b"
+#define PREFS_T_RED PREFS_PREFIX "/target_r"
+#define PREFS_T_GREEN PREFS_PREFIX "/target_g"
+#define PREFS_T_BLUE PREFS_PREFIX "/target_b"
+
+static const guint8 default_initial_rgb[3] = { 0xFF, 0x00, 0x00 };
+static const guint8 default_target_rgb[3] = { 0x00, 0x00, 0x00 };
+
+/* set up preferences dialog */
+static PurplePluginPrefFrame *
+init_pref_frame(PurplePlugin *plugin) {
+ PurplePluginPrefFrame *frame;
+ PurplePluginPref *ppref;
+
+ frame = purple_plugin_pref_frame_new();
+
+ /* initial color */
+ ppref = purple_plugin_pref_new_with_label("Initial Color");
+ purple_plugin_pref_frame_add(frame, ppref);
+
+ /* initial red intensity */
+ ppref = purple_plugin_pref_new_with_name_and_label(PREFS_I_RED,
+ "Red intensity (0-255): ");
+ purple_plugin_pref_set_bounds(ppref, 0, 255);
+ purple_plugin_pref_frame_add(frame, ppref);
+
+ /* initial green intensity */
+ ppref = purple_plugin_pref_new_with_name_and_label(PREFS_I_GREEN,
+ "Green intensity (0-255): ");
+ purple_plugin_pref_set_bounds(ppref, 0, 255);
+ purple_plugin_pref_frame_add(frame, ppref);
+
+ /* initial blue intensity */
+ ppref = purple_plugin_pref_new_with_name_and_label(PREFS_I_BLUE,
+ "Blue intensity (0-255): ");
+ purple_plugin_pref_set_bounds(ppref, 0, 255);
+ purple_plugin_pref_frame_add(frame, ppref);
+
+ /* target color */
+ ppref = purple_plugin_pref_new_with_label("Target Color");
+ purple_plugin_pref_frame_add(frame, ppref);
+
+ /* target red intensity */
+ ppref = purple_plugin_pref_new_with_name_and_label(PREFS_T_RED,
+ "Red intensity (0-255): ");
+ purple_plugin_pref_set_bounds(ppref, 0, 255);
+ purple_plugin_pref_frame_add(frame, ppref);
+
+ /* target green intensity */
+ ppref = purple_plugin_pref_new_with_name_and_label(PREFS_T_GREEN,
+ "Green intensity (0-255): ");
+ purple_plugin_pref_set_bounds(ppref, 0, 255);
+ purple_plugin_pref_frame_add(frame, ppref);
+
+ /* target blue intensity */
+ ppref = purple_plugin_pref_new_with_name_and_label(PREFS_T_BLUE,
+ "Blue intensity (0-255): ");
+ purple_plugin_pref_set_bounds(ppref, 0, 255);
+ purple_plugin_pref_frame_add(frame, ppref);
+
+ return frame;
+}
+
+inline static guint8
+round_gfloat_to_guint8(gfloat f) {
+ return ((guchar)(f + 0.5f));
+}
+
+inline static gint32
+rgb_equals(guint8 a[3], gfloat b[3]) {
+ return ( a[0] == round_gfloat_to_guint8(b[0]) &&
+ a[1] == round_gfloat_to_guint8(b[1]) &&
+ a[2] == round_gfloat_to_guint8(b[2]) );
+}
+
+static void
+colorize_message(char **message) {
+ guint i, len;
+ gfloat d_grad[3], grad[3];
+ guint8 initial_rgb[3], target_rgb[3], last_rgb[3];
+ gchar *formatted_char, *tmp, *new_msg;
+
+ g_return_if_fail(message != NULL);
+ g_return_if_fail(*message != NULL);
+ g_return_if_fail(**message != '\0');
+
+ new_msg = g_strdup("");
+ len = strlen( *message );
+
+ /* get colors from preferences */
+ initial_rgb[0] = (guint8)purple_prefs_get_int(PREFS_I_RED);
+ initial_rgb[1] = (guint8)purple_prefs_get_int(PREFS_I_GREEN);
+ initial_rgb[2] = (guint8)purple_prefs_get_int(PREFS_I_BLUE);
+
+ target_rgb[0] = (guint8)purple_prefs_get_int(PREFS_T_RED);
+ target_rgb[1] = (guint8)purple_prefs_get_int(PREFS_T_GREEN);
+ target_rgb[2] = (guint8)purple_prefs_get_int(PREFS_T_BLUE);
+
+ /* initialize current gradient value */
+ grad[0] = (gfloat)initial_rgb[0];
+ grad[1] = (gfloat)initial_rgb[1];
+ grad[2] = (gfloat)initial_rgb[2];
+
+ /* determine the delta gradient value */
+ d_grad[0] = (gfloat)(target_rgb[0] - initial_rgb[0]) / (gfloat)len;
+ d_grad[1] = (gfloat)(target_rgb[1] - initial_rgb[1]) / (gfloat)len;
+ d_grad[2] = (gfloat)(target_rgb[2] - initial_rgb[2]) / (gfloat)len;
+
+ /* open initial font tag and format first character */
+ formatted_char = g_strdup_printf("<font color=\"#%02x%02x%02x\">%c",
+ round_gfloat_to_guint8(grad[0]),
+ round_gfloat_to_guint8(grad[1]),
+ round_gfloat_to_guint8(grad[2]),
+ *(*message));
+
+ /* create a new string with the newly formatted char and free the old one */
+ tmp = g_strconcat(new_msg, formatted_char, NULL);
+ g_free(formatted_char);
+ g_free(new_msg);
+
+ new_msg = tmp;
+
+ /* format each character one by one:
+ * (if it is not a space) AND
+ * (if it is not the same color as the last character)
+ */
+ for(i=1; i<len; i++)
+ {
+ /* store last color */
+ last_rgb[0] = round_gfloat_to_guint8(grad[0]);
+ last_rgb[1] = round_gfloat_to_guint8(grad[1]);
+ last_rgb[2] = round_gfloat_to_guint8(grad[2]);
+
+ /* increment the gradient */
+ grad[0] += d_grad[0];
+ grad[1] += d_grad[1];
+ grad[2] += d_grad[2];
+
+ /* format next character appropriately */
+ if( g_ascii_isspace ( *(*message+i) ) ||
+ rgb_equals(last_rgb, grad) )
+ formatted_char = g_strdup_printf("%c", *(*message+i));
+ else
+ formatted_char = g_strdup_printf("</font><font color=\"#%02x%02x%02x\">%c",
+ round_gfloat_to_guint8(grad[0]),
+ round_gfloat_to_guint8(grad[1]),
+ round_gfloat_to_guint8(grad[2]),
+ *(*message+i));
+
+
+ /* create a new string with the newly formatted char and free the old one */
+ tmp = g_strconcat(new_msg, formatted_char, NULL);
+ g_free(formatted_char);
+ g_free(new_msg);
+
+ new_msg = tmp;
+ }
+
+ /* close final font tag */
+ new_msg = g_strconcat(new_msg, "</font>", NULL);
+
+ /* return result */
+ g_free(*message);
+ *message = new_msg;
+}
+
+/* respond to a sending-im signal by replacing outgoing text
+ * with colorized version
+ */
+static void
+sending_im_msg(PurpleAccount *account, gchar *receiver, gchar **message) {
+ gchar *stripped_message;
+
+ /* strip any existing HTML */
+ stripped_message = purple_markup_strip_html(*message);
+ g_free(*message);
+
+ /* colorize the message with HTML font tags */
+ *message = stripped_message;
+ colorize_message(message);
+
+ /* todo: additional conversation manipulation is going to be required to
+ display the colorized version of the message locally */
+}
+
+/* register sendin-im signal */
+static gboolean
+plugin_load(PurplePlugin *plugin) {
+ purple_signal_connect(purple_conversations_get_handle(), "sending-im-msg",
+ plugin, PURPLE_CALLBACK(sending_im_msg), NULL);
+
+ return TRUE;
+}
+
+static gboolean
+plugin_unload(PurplePlugin *plugin) {
+ return TRUE;
+}
+
+static PurplePluginUiInfo prefs_info = {
+ init_pref_frame
+};
+
+static PurplePluginInfo info =
+{
+ PURPLE_PLUGIN_MAGIC,
+ PURPLE_MAJOR_VERSION,
+ PURPLE_MINOR_VERSION,
+ PURPLE_PLUGIN_STANDARD,
+ NULL,
+ 0,
+ NULL,
+ PURPLE_PRIORITY_DEFAULT,
+
+ PLUGIN_ID,
+ NULL,
+ PP_VERSION,
+ NULL,
+ NULL,
+ PLUGIN_AUTHOR,
+ PP_WEBSITE,
+
+ plugin_load,
+ plugin_unload,
+ NULL,
+
+ NULL,
+ NULL,
+ &prefs_info,
+ NULL
+};
+
+/* initialize default preferences */
+static void
+init_plugin(PurplePlugin *plugin) {
+#ifdef ENABLE_NLS
+ bindtextdomain(GETTEXT_PACKAGE, PP_LOCALEDIR);
+ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+#endif /* ENABLE_NLS */
+
+ info.name = _("Colorize");
+ info.summary = _("Colorizes outgoing message text.");
+ info.description = _("Colorizes outgoing message text to a gradient of "
+ "specified starting and ending RGB values.");
+
+ /* prefs */
+ purple_prefs_add_none(PREFS_PREFIX);
+
+ purple_prefs_add_int(PREFS_I_RED, default_initial_rgb[0]);
+ purple_prefs_add_int(PREFS_I_GREEN, default_initial_rgb[1]);
+ purple_prefs_add_int(PREFS_I_BLUE, default_initial_rgb[2]);
+
+ purple_prefs_add_int(PREFS_T_RED, default_target_rgb[0]);
+ purple_prefs_add_int(PREFS_T_GREEN, default_target_rgb[1]);
+ purple_prefs_add_int(PREFS_T_BLUE, default_target_rgb[2]);
+}
+
+PURPLE_INIT_PLUGIN(colorize, init_plugin, info)
--- a/configure.ac Wed Apr 23 05:09:46 2008 -0400
+++ b/configure.ac Wed Apr 23 05:10:02 2008 -0400
@@ -229,6 +229,8 @@
fi
# switchspell
+
+# check for gtkspell
gtkspell=yes
PKG_CHECK_MODULES(GTKSPELL, gtkspell-2.0 >= 2.0.2, [], [gtkspell=no])
AC_SUBST(GTKSPELL_CFLAGS)
@@ -243,6 +245,22 @@
BUILD_SWITCH_SPELL=no
fi
fi
+
+# check for aspell
+ASPELL_CFLAGS=""
+ASPELL_LIBS=""
+AC_CHECK_HEADER([aspell.h], HAVE_ASPELL_H=yes, AC_MSG_WARN([
+*** libaspell is required to build the switchspell plugin.])
+HAVE_ASPELL_H=no
+)
+
+if test x"$HAVE_ASPELL_H" = x"yes" ; then
+ AC_CHECK_LIB([aspell], [new_aspell_config], ASPELL_LIBS="-laspell", BUILD_SWITCH_SPELL=no)
+fi
+
+AC_SUBST(ASPELL_CFLAGS)
+AC_SUBST(ASPELL_LIBS)
+
AM_CONDITIONAL(BUILD_SWITCH_SPELL, test x"$BUILD_SWITCH_SPELL" = x"yes")
# xmmsremote
@@ -280,6 +298,13 @@
AC_CHECK_HEADERS(regex.h)
dnl #######################################################################
+dnl # Disable installation of translation files
+dnl #######################################################################
+AC_ARG_ENABLE(nls, AC_HELP_STRING([--enable-nls], [enable installation of translation files]), enable_i18n="$enableval", enable_i18n=yes)
+
+AM_CONDITIONAL(INSTALL_I18N, test "x$enable_i18n" = "xyes")
+
+dnl #######################################################################
dnl # Run our plugin checking
dnl #######################################################################
AM_BUILD_PLUGIN_LIST()
@@ -318,6 +343,7 @@
blistops/Makefile
buddytime/Makefile
chronic/Makefile
+ colorize/Makefile
convbadger/Makefile
dewysiwygification/Makefile
dice/Makefile
@@ -326,8 +352,9 @@
enhancedhist/Makefile
findip/Makefile
flip/Makefile
+ google/Makefile
+ gRIM/Makefile
groupmsg/Makefile
- gRIM/Makefile
hideconv/Makefile
highlight/Makefile
ignorance/Makefile
@@ -338,6 +365,8 @@
irssi/Makefile
lastseen/Makefile
listhandler/Makefile
+ manualsize/Makefile
+ msglen/Makefile
mystatusbox/Makefile
napster/Makefile
nicksaid/Makefile
@@ -349,6 +378,7 @@
simfix/Makefile
slashexec/Makefile
snpp/Makefile
+ splitter/Makefile
sslinfo/Makefile
stocker/Makefile
switchspell/Makefile
--- a/convbadger/convbadger.c Wed Apr 23 05:09:46 2008 -0400
+++ b/convbadger/convbadger.c Wed Apr 23 05:10:02 2008 -0400
@@ -105,7 +105,7 @@
* Callbacks
*****************************************************************************/
static void
-convbadger_conv_created_cb(PurpleConversation *conv, gpointer data) {
+conv_badger_conv_created_cb(PurpleConversation *conv, gpointer data) {
PidginConversation *pconv = PIDGIN_CONVERSATION(conv);
PidginWindow *win = pidgin_conv_get_window(pconv);
@@ -113,11 +113,11 @@
}
static void
-convbadger_conv_destroyed_cb(PurpleConversation *conv, gpointer data) {
+conv_badger_conv_destroyed_cb(PurpleConversation *conv, gpointer data) {
}
static void
-convbadger_conv_switched_cb(PurpleConversation *conv, gpointer data) {
+conv_badger_conv_switched_cb(PurpleConversation *conv, gpointer data) {
PidginConversation *pconv = PIDGIN_CONVERSATION(conv);
PidginWindow *win = pidgin_conv_get_window(pconv);
@@ -135,13 +135,13 @@
NULL, NULL);
purple_signal_connect(conv_handle, "conversation-created", plugin,
- PURPLE_CALLBACK(convbadger_conv_created_cb), NULL);
+ PURPLE_CALLBACK(conv_badger_conv_created_cb), NULL);
purple_signal_connect(conv_handle, "deleting-conversation", plugin,
- PURPLE_CALLBACK(convbadger_conv_destroyed_cb), NULL);
+ PURPLE_CALLBACK(conv_badger_conv_destroyed_cb), NULL);
purple_signal_connect(pidgin_conversations_get_handle(),
"conversation-switched", plugin,
- PURPLE_CALLBACK(convbadger_conv_switched_cb), NULL);
+ PURPLE_CALLBACK(conv_badger_conv_switched_cb), NULL);
return TRUE;
}
--- a/dewysiwygification/dewysiwygification.c Wed Apr 23 05:09:46 2008 -0400
+++ b/dewysiwygification/dewysiwygification.c Wed Apr 23 05:10:02 2008 -0400
@@ -50,7 +50,7 @@
g_free(*message);
*message = tmp;
- purple_debug_misc("dewysiwygification", "it's now: %s", tmp);
+ purple_debug_misc("dewysiwygification", "it's now: %s\n", tmp);
return FALSE;
}
@@ -67,7 +67,7 @@
g_free(*message);
*message = tmp;
- purple_debug_misc("dewysiwygification", "it's now: %s", tmp);
+ purple_debug_misc("dewysiwygification", "it's now: %s\n", tmp);
return FALSE;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/google/Makefile.am Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,26 @@
+EXTRA_DIST = .purple-plugin .build Makefile.mingw
+
+googledir = $(PURPLE_LIBDIR)
+
+google_la_LDFLAGS = -module -avoid-version
+
+if HAVE_PURPLE
+
+google_LTLIBRARIES = google.la
+
+google_la_SOURCES = \
+ google.c
+
+google_la_LIBADD = \
+ $(GLIB_LIBS) \
+ $(PURPLE_LIBS)
+
+endif
+
+AM_CPPFLAGS = \
+ -DLIBDIR=\"$(PURPLE_LIBDIR)\" \
+ -DDATADIR=\"$(PURPLE_DATADIR)\" \
+ -DPIXMAPSDIR=\"$(PURPLE_PIXMAPSDIR)\" \
+ $(DEBUG_CFLAGS) \
+ $(PURPLE_CFLAGS)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/google/Makefile.mingw Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,12 @@
+#
+# Makefile.mingw
+#
+# Description: Makefile for the google plugin.
+#
+
+PP_TOP := ..
+
+PP = google
+
+include $(PP_TOP)/win_pp.mak
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/google/google.c Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,325 @@
+/*
+ * Adds a command to return the first url for a google I'm feeling lucky search
+ * Copyright (C) 2008 Gary Kramlich <grim@reaperworld.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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA.
+ */
+
+#include "../common/pp_internal.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include <cmds.h>
+#include <conversation.h>
+#include <debug.h>
+#include <plugin.h>
+#include <proxy.h>
+#include <util.h>
+
+static PurpleCmdId google_cmd_id = 0;
+
+#define GOOGLE_URL_FORMAT "http://%s/search?q=%s&btnI=I%%27m+Feeling+Lucky"
+
+/******************************************************************************
+ * Structs
+ *****************************************************************************/
+typedef struct {
+ PurpleConversation *conv;
+ gchar *host;
+ gint port;
+ gchar *path;
+
+ gchar *request;
+ gsize request_written;
+
+ gint fd;
+ gint inpa;
+
+ GString *response;
+
+ PurpleProxyConnectData *conn_data;
+} GoogleFetchUrlData;
+
+/******************************************************************************
+ * GoogleFetchUrlData API
+ *****************************************************************************/
+static GoogleFetchUrlData *
+google_fetch_url_data_new(const gchar *url) {
+ GoogleFetchUrlData *gfud = g_new0(GoogleFetchUrlData, 1);
+
+ if(!purple_url_parse(url, &gfud->host, &gfud->port, &gfud->path, NULL,
+ NULL))
+ {
+ g_free(gfud);
+ return NULL;
+ }
+
+ gfud->response = g_string_new("");
+
+ return gfud;
+}
+
+static void
+google_fetch_url_data_free(GoogleFetchUrlData *gfud) {
+ g_free(gfud->host);
+ g_free(gfud->path);
+
+ g_free(gfud->request);
+
+ g_string_free(gfud->response, TRUE);
+
+ if(gfud->inpa > 0)
+ purple_input_remove(gfud->inpa);
+
+ if(gfud->fd >= 0)
+ close(gfud->fd);
+
+ if(gfud->conn_data)
+ purple_proxy_connect_cancel(gfud->conn_data);
+
+ g_free(gfud);
+}
+
+/******************************************************************************
+ * The final result (hiding in the middle, very sneaky)
+ *****************************************************************************/
+static void
+google_output_url(GoogleFetchUrlData *gfud) {
+ gchar *str = NULL, *url_s = NULL, *url_e = NULL;
+ gsize len = 0;
+ const gchar *needle = "Location: ";
+
+ /* if our conv has disappeared from under us, drop out */
+ if(!gfud->conv)
+ return;
+
+ str = gfud->response->str;
+ len = gfud->response->len;
+
+ url_s = g_strstr_len(str, len, needle);
+ if(!url_s)
+ return;
+
+ len = strlen(url_s);
+ url_s += strlen(needle);
+
+ url_e = g_strstr_len(url_s, len, "\r\n");
+ if(!url_e)
+ return;
+
+ *url_e = '\0';
+
+ if(gfud->conv->type == PURPLE_CONV_TYPE_IM)
+ purple_conv_im_send(PURPLE_CONV_IM(gfud->conv), url_s);
+ else if(gfud->conv->type == PURPLE_CONV_TYPE_CHAT)
+ purple_conv_chat_send(PURPLE_CONV_CHAT(gfud->conv), url_s);
+}
+
+/******************************************************************************
+ * URL Stuff
+ *****************************************************************************/
+static void
+im_feeling_lucky_recv_cb(gpointer data, gint source, PurpleInputCondition c) {
+ GoogleFetchUrlData *gfud = (GoogleFetchUrlData *)data;
+ gint len;
+ gchar buff[4096];
+
+ while((len = read(source, buff, sizeof(buff))) > 0)
+ gfud->response = g_string_append_len(gfud->response, buff, len);
+
+ if(len < 0) {
+ if(errno == EAGAIN)
+ return;
+
+ /* need to die here */
+
+ return;
+ }
+
+ if(len == 0) {
+ google_output_url(gfud);
+ google_fetch_url_data_free(gfud);
+ }
+}
+
+static void
+im_feeling_lucky_send_cb(gpointer data, gint source, PurpleInputCondition c) {
+ GoogleFetchUrlData *gfud = (GoogleFetchUrlData *)data;
+ gint len, total_len;
+
+ total_len = strlen(gfud->request);
+
+ len = write(gfud->fd, gfud->request + gfud->request_written,
+ total_len - gfud->request_written);
+
+ if(len < 0) {
+ if(errno == EAGAIN)
+ return;
+
+ /* need to die here */
+
+ return;
+ }
+
+ gfud->request_written += len;
+
+ if(gfud->request_written < total_len)
+ return;
+
+ /* done writing the request, now read the response */
+ purple_input_remove(gfud->inpa);
+ gfud->inpa = purple_input_add(gfud->fd, PURPLE_INPUT_READ,
+ im_feeling_lucky_recv_cb, gfud);
+}
+
+static void
+im_feeling_lucky_cb(gpointer data, gint source, const gchar *e) {
+ GoogleFetchUrlData *gfud = (GoogleFetchUrlData *)data;
+
+ gfud->conn_data = NULL;
+
+ if(source == -1) {
+ purple_debug_error("google", "unable to connect to %s: %s\n",
+ gfud->host, gfud->path);
+
+ google_fetch_url_data_free(gfud);
+
+ return;
+ }
+
+ gfud->fd = source;
+
+ gfud->request = g_strdup_printf(
+ "GET /%s HTTP/1.1\r\n"
+ "Host: %s\r\n"
+ "User-Agent: Purple/%u.%u.%u\r\n"
+ "Accept: */*\r\n"
+ "Connection: close\r\n"
+ "Referer: %s\r\n"
+ "\r\n",
+ gfud->path,
+ gfud->host,
+ purple_major_version, purple_minor_version, purple_micro_version,
+ gfud->host);
+
+ gfud->inpa = purple_input_add(gfud->fd, PURPLE_INPUT_WRITE,
+ im_feeling_lucky_send_cb, gfud);
+ im_feeling_lucky_send_cb(gfud, gfud->fd, PURPLE_INPUT_WRITE);
+}
+
+/******************************************************************************
+ * Command stuff
+ *****************************************************************************/
+static PurpleCmdRet
+im_feeling_lucky(PurpleConversation *conv, const gchar *cmd, gchar **args,
+ gchar *error, void *data)
+{
+ GoogleFetchUrlData *gfud = NULL;
+ PurplePlugin *plugin = (PurplePlugin *)data;
+ gchar *url = NULL;
+
+ url = g_strdup_printf(GOOGLE_URL_FORMAT, "www.google.com",
+ purple_url_encode(args[0]));
+ gfud = google_fetch_url_data_new(url);
+ g_free(url);
+
+ if(!gfud)
+ return PURPLE_CMD_RET_FAILED;
+
+ gfud->conv = conv;
+
+ /* now make the connection */
+ gfud->conn_data =
+ purple_proxy_connect(plugin, NULL, gfud->host, gfud->port,
+ im_feeling_lucky_cb, gfud);
+
+ if(!gfud->conn_data) {
+ google_fetch_url_data_free(gfud);
+
+ return PURPLE_CMD_RET_FAILED;
+ }
+
+ return PURPLE_CMD_RET_OK;
+}
+
+/******************************************************************************
+ * Plugin Stuff
+ *****************************************************************************/
+static gboolean
+plugin_load(PurplePlugin *plugin) {
+ google_cmd_id =
+ purple_cmd_register("google", "s", PURPLE_CMD_P_PLUGIN,
+ PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT,
+ NULL, PURPLE_CMD_FUNC(im_feeling_lucky),
+ _("Returns the url for a Google I'm feeling lucky "
+ "search"),
+ plugin);
+
+ return TRUE;
+}
+
+static gboolean
+plugin_unload(PurplePlugin *plugin) {
+ purple_cmd_unregister(google_cmd_id);
+
+ return TRUE;
+}
+
+static PurplePluginInfo info = {
+ PURPLE_PLUGIN_MAGIC,
+ PURPLE_MAJOR_VERSION,
+ PURPLE_MINOR_VERSION,
+ PURPLE_PLUGIN_STANDARD,
+ NULL,
+ 0,
+ NULL,
+ PURPLE_PRIORITY_DEFAULT,
+
+ "core-plugin_pack-google",
+ NULL,
+ PP_VERSION,
+ NULL,
+ NULL,
+ "Gary Kramlich <grim@reaperworld.com>",
+ PP_WEBSITE,
+
+ plugin_load,
+ plugin_unload,
+ NULL,
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static void
+init_plugin(PurplePlugin *plugin) {
+#ifdef ENABLE_NLS
+ bindtextdomain(GETTEXT_PACKAGE, PP_LOCALEDIR);
+ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+#endif /* ENABLE_NLS */
+
+ info.name = _("Google");
+ info.summary = _("Returns the url for a Google I'm feeling lucky search");
+ info.description = info.summary;
+}
+
+PURPLE_INIT_PLUGIN(google, init_plugin, info)
--- a/irc-more/irc-more.c Wed Apr 23 05:09:46 2008 -0400
+++ b/irc-more/irc-more.c Wed Apr 23 05:10:02 2008 -0400
@@ -51,13 +51,18 @@
{
/* So you think you can kick me? I'll show you! */
PurpleConversation *conv = data;
- char *command = g_strdup_printf("join %s", purple_conversation_get_name(conv));
- char *markup = g_markup_escape_text(command, -1);
- char *error = NULL;
- purple_cmd_do_command(conv, command, markup, &error); /* Do anything with the return value? */
- g_free(command);
- g_free(markup);
- g_free(error);
+ char *conv_name = NULL, *command = NULL, *markup = NULL, *error = NULL;
+
+ if(conv_name) {
+ command = g_strdup_printf("join %s", conv_name);
+ markup = g_markup_escape_text(command, -1);
+ error = NULL;
+ purple_cmd_do_command(conv, command, markup, &error); /* Do anything with the return value? */
+ g_free(command);
+ g_free(markup);
+ g_free(error);
+ }
+
return FALSE;
}
--- a/irssi/textfmt.c Wed Apr 23 05:09:46 2008 -0400
+++ b/irssi/textfmt.c Wed Apr 23 05:10:02 2008 -0400
@@ -60,7 +60,7 @@
if(!(account)->gc) \
return FALSE; \
\
- if(!(account)->gc->flags & PURPLE_CONNECTION_HTML) \
+ if(!((account)->gc->flags & PURPLE_CONNECTION_HTML)) \
return FALSE; \
\
if(!(message)) \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/manualsize/Makefile.am Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,27 @@
+EXTRA_DIST = .pidgin-plugin .build Makefile.mingw
+
+manualsizedir = $(PIDGIN_LIBDIR)
+
+manualsize_la_LDFLAGS = -module -avoid-version
+
+if HAVE_PIDGIN
+
+manualsize_LTLIBRARIES = manualsize.la
+
+manualsize_la_SOURCES = \
+ manualsize.c
+
+manualsize_la_LIBADD = \
+ $(GTK_LIBS) \
+ $(PIDGIN_LIBS)
+
+endif
+
+AM_CPPFLAGS = \
+ -DLIBDIR=\"$(PIDGIN_LIBDIR)\" \
+ -DDATADIR=\"$(PIDGIN_DATADIR)\" \
+ -DPIXMAPSDIR=\"$(PIDGIN_PIXMAPSDIR)\" \
+ $(DEBUG_CFLAGS) \
+ $(PIDGIN_CFLAGS) \
+ $(GTK_CFLAGS)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/manualsize/Makefile.mingw Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,12 @@
+#
+# Makefile.mingw
+#
+# Description: Makefile for manualsize plugin.
+#
+
+PP_TOP := ..
+
+PP = manualsize
+
+include $(PP_TOP)/win_pp.mak
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/manualsize/manualsize.c Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,329 @@
+/*
+ *
+ * Pidgin 2.4 manual entry area height sizing plugin
+ * License: GPL version 2 or later
+ *
+ * Copyright (C) 2008, Artemy Kapitula <dalt74@gmail.com>
+ *
+ */
+
+#include "../common/pp_internal.h"
+
+#include <pidgin.h>
+#include <gtkprefs.h>
+
+#include <conversation.h>
+#include <prefs.h>
+#include <signals.h>
+#include <version.h>
+#include <debug.h>
+
+#include <gtkplugin.h>
+#include <gtkutils.h>
+#include <gtkimhtml.h>
+
+#define NOTIFY_PLUGIN_ID "pidgin-entry-manual-height"
+
+#define PREF_PREFIX "/plugins/manualsize"
+#define PREF_CHAT_ENTRY_HEIGHT PREF_PREFIX "/chat_entry_height"
+#define PREF_IM_ENTRY_HEIGHT PREF_PREFIX "/im_entry_height"
+
+static gboolean page_added = FALSE; // The flag of page has been added.
+ // It's used to track a case when we add a second page and should to do some
+ // additional work to track a page resize issues
+
+static GList * books_connected = NULL;
+ // List of notebooks we connected to. When plugin is unloaded,
+ // we will disconnect our handler for a "page-added" signal
+
+/*
+ * Find a first "placed" objects (the object that has allocation with a height > 1)
+ * and it's internal height.
+ *
+ * It's required because when creating a non-first page in the notebook,
+ * the widget of the added page has allocation->heigth = 1, and we cannot
+ * use it as a base for evaluating position of separator in a GtkVPaned
+ */
+static GtkWidget *
+find_placed_object(GtkWidget *w, gint *client_height) {
+ GtkWidget * ret;
+ gint border_width;
+
+ border_width = gtk_container_get_border_width(GTK_CONTAINER(w));
+
+ if((w->allocation.height > 1) || (gtk_widget_get_parent(w)==NULL)) {
+ *client_height = w->allocation.height;
+ return w;
+ } else {
+ ret = find_placed_object(gtk_widget_get_parent(w), client_height);
+ *client_height = *client_height - border_width + 2;
+ return ret;
+ }
+}
+
+/*
+ * Find a GtkNotebook in the widget's parents
+ * It's used to find a GtkNotebook in a conversation window
+ * to attach a "page-added" signal handler
+ */
+static GtkWidget *
+get_notebook(GtkWidget * w) {
+ const gchar *name = NULL;
+
+ name = G_OBJECT_TYPE_NAME(w);
+
+ if (name && strcmp("GtkNotebook", name) == 0)
+ return w;
+
+ if(gtk_widget_get_parent(w) == NULL)
+ return NULL;
+
+ return get_notebook(gtk_widget_get_parent(w));
+}
+
+/*
+ * Signal handler. Triggers a page_added flag.
+ */
+static void
+on_page_add(GtkNotebook *book, GtkWidget *widget, guint page_num,
+ gpointer user_data)
+{
+ page_added = TRUE;
+ return;
+}
+
+/*
+ * When removing last page, forget this notebook
+ */
+static void
+on_page_remove(GtkNotebook *book, GtkWidget *widget, guint page_num,
+ gpointer user_data)
+{
+ if(gtk_notebook_get_n_pages(book) == 0) {
+ books_connected = g_list_remove(books_connected, book);
+ printf("Removed!\n");
+ }
+}
+
+/*
+ * Attach a handlers on a notebook if it is not already attached
+ * Adds a notebook into a tracked objects list
+ */
+static void
+connect_notebook_handler(GtkNotebook * notebook) {
+ GList * item = g_list_find(books_connected, notebook);
+
+ if(!item) {
+ g_signal_connect_after(notebook, "page-added",
+ G_CALLBACK(on_page_add), NULL);
+ g_signal_connect_after(notebook, "page-removed",
+ G_CALLBACK(on_page_remove), NULL);
+ books_connected = g_list_append( books_connected, notebook );
+ printf("Added!\n");
+ }
+}
+
+/*
+ * Rebuild conversation pane.
+ * Find a conversation pane ("pane")
+ * Find a parent for a pane ("top")
+ * Create GtkVPaned ("vpaned")
+ * Move "pane" from a "top" to the up of "vpaned"
+ * Move "lower_hbox" of conversation to the bottom "vpaned"
+ * Insert "vpaned" into a "top"
+ * Change "vpaned" divider position
+ */
+static void
+rebuild_container(PidginConversation *conv) {
+ GtkWidget * pane = gtk_widget_get_parent(GTK_WIDGET(conv->lower_hbox));
+ GtkWidget * top = gtk_widget_get_parent( pane );
+ GtkWidget * vpaned = gtk_vpaned_new();
+ GtkNotebook * notebook = GTK_NOTEBOOK(get_notebook(top));
+ gint handle_size = 0;
+ gint parent_area = 0;
+ gint border_size = 0;
+ gint new_pos;
+ GtkPositionType tabpos = -1;
+ GValue v = {0, };
+ gint stored_height = 0;
+
+ if(purple_conversation_get_type(conv->active_conv) == PURPLE_CONV_TYPE_CHAT)
+ stored_height = purple_prefs_get_int(PREF_CHAT_ENTRY_HEIGHT);
+ else
+ stored_height = purple_prefs_get_int(PREF_IM_ENTRY_HEIGHT);
+
+ if (stored_height < 0) stored_height = 128;
+
+ if (notebook) {
+ tabpos = gtk_notebook_get_tab_pos( notebook );
+ connect_notebook_handler( notebook );
+ }
+
+ g_value_init( &v, G_TYPE_BOOLEAN );
+
+ gtk_widget_show( vpaned );
+
+ g_value_set_boolean( &v, TRUE );
+ gtk_widget_reparent( pane, vpaned );
+ gtk_container_child_set_property( GTK_CONTAINER(vpaned), pane, "resize", &v );
+
+ g_value_set_boolean( &v, FALSE );
+ gtk_widget_reparent( conv->lower_hbox, vpaned );
+ gtk_container_child_set_property( GTK_CONTAINER(vpaned), conv->lower_hbox, "resize", &v );
+
+ g_value_unset( &v );
+
+ gtk_container_add( GTK_CONTAINER(top), vpaned );
+
+ gtk_widget_style_get( vpaned, "handle-size", &handle_size, NULL );
+
+ find_placed_object( top, &parent_area );
+ border_size = gtk_container_get_border_width(GTK_CONTAINER(top));
+
+ new_pos =
+ parent_area -
+ stored_height -
+ handle_size -
+ border_size * 2 -
+ (((page_added==TRUE)&&((tabpos==GTK_POS_TOP)||(tabpos==GTK_POS_BOTTOM)))?24:0);
+
+ gtk_paned_set_position( GTK_PANED(vpaned), new_pos );
+
+ page_added = FALSE;
+
+ gtk_widget_grab_focus( conv->entry );
+
+}
+
+/*
+ * Store input area size depending on a conversation type
+ */
+static void
+store_area_size(PidginConversation *gtkconv) {
+ GtkWidget *parent = NULL;
+ const gchar *name = NULL;
+
+ parent = gtk_widget_get_parent(GTK_WIDGET(gtkconv->lower_hbox));
+ name = G_OBJECT_TYPE_NAME(parent);
+
+ if(name && strcmp("GtkVPaned", name) == 0) {
+ PurpleConversation *conv = gtkconv->active_conv;
+
+ if(purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
+ purple_prefs_set_int(PREF_CHAT_ENTRY_HEIGHT,
+ gtkconv->lower_hbox->allocation.height);
+ } else {
+ purple_prefs_set_int(PREF_IM_ENTRY_HEIGHT,
+ gtkconv->lower_hbox->allocation.height);
+ }
+ }
+}
+
+/*
+ * Signal handler. Called when conversation created, and rebuilds a conversation pane
+ */
+static void
+on_display(gpointer data) {
+ PidginConversation *gtkconv = (PidginConversation *)data;
+
+ if(gtkconv)
+ rebuild_container(gtkconv);
+}
+
+/*
+ * Signal handler. Called when conversation destroyed, to store an input area size
+ */
+static void
+on_destroy(void * data) {
+ PurpleConversation *conv = (PurpleConversation*)data;
+ if(conv) {
+ PidginConversation * gtkconv = PIDGIN_CONVERSATION(conv);
+ if (gtkconv)
+ store_area_size(gtkconv);
+ }
+}
+
+/*
+ * Traverse connected notebooks and remove our signal handler
+ */
+static void
+cleanup_callback(gpointer data, gpointer user_data) {
+ g_signal_handlers_disconnect_by_func( data, on_page_add, NULL );
+ g_signal_handlers_disconnect_by_func( data, on_page_remove, NULL );
+}
+
+static gboolean
+plugin_load(PurplePlugin *plugin) {
+ void *gtk_conv_handle = pidgin_conversations_get_handle();
+ void *conv_handle = purple_conversations_get_handle();
+
+ purple_prefs_add_none(PREF_PREFIX);
+ purple_prefs_add_int(PREF_CHAT_ENTRY_HEIGHT, 128);
+ purple_prefs_add_int(PREF_IM_ENTRY_HEIGHT, 128);
+
+ purple_signal_connect(gtk_conv_handle, "conversation-displayed", plugin,
+ PURPLE_CALLBACK(on_display), NULL);
+ purple_signal_connect(conv_handle, "deleting-conversation", plugin,
+ PURPLE_CALLBACK(on_destroy), NULL);
+
+ return TRUE;
+}
+
+static gboolean
+plugin_unload(PurplePlugin *plugin) {
+ g_list_foreach(books_connected, cleanup_callback, NULL);
+ g_list_free(books_connected);
+
+ return TRUE;
+}
+
+static PurplePluginInfo info =
+{
+ PURPLE_PLUGIN_MAGIC,
+ PURPLE_MAJOR_VERSION,
+ PURPLE_MINOR_VERSION,
+ PURPLE_PLUGIN_STANDARD, /**< type */
+ PIDGIN_PLUGIN_TYPE, /**< ui_requirement */
+ 0, /**< flags */
+ NULL, /**< dependencies */
+ PURPLE_PRIORITY_DEFAULT, /**< priority */
+
+ NOTIFY_PLUGIN_ID, /**< id */
+ NULL, /**< name */
+ PP_VERSION, /**< version */
+
+ NULL, /** summary */
+ NULL, /** description */
+
+ "Artemy Kapitula <dalt74@gmail.com>", /**< author */
+ PP_WEBSITE, /**< homepage */
+
+ plugin_load, /**< load */
+ plugin_unload, /**< unload */
+ NULL, /**< destroy */
+
+ NULL, /**< ui_info */
+ NULL, /**< extra_info */
+ NULL,
+ NULL,
+
+ /* padding */
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static void
+init_plugin(PurplePlugin *plugin) {
+#ifdef ENABLE_NLS
+ bindtextdomain(GETTEXT_PACKAGE, PP_LOCALEDIR);
+ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+#endif /* ENABLE_NLS */
+
+ info.name = _("Entry area manual sizing");
+ info.summary = _("Allows you to change entry area height");
+ info.description = info.summary;
+}
+
+PURPLE_INIT_PLUGIN(manualsize, init_plugin, info)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/msglen/Makefile.am Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,27 @@
+EXTRA_DIST = .pidgin-plugin .incomplete Makefile.mingw
+
+msglendir = $(PIDGIN_LIBDIR)
+
+msglen_la_LDFLAGS = -module -avoid-version
+
+if HAVE_PIDGIN
+
+msglen_LTLIBRARIES = msglen.la
+
+msglen_la_SOURCES = \
+ msglen.c
+
+msglen_la_LIBADD = \
+ $(GTK_LIBS) \
+ $(PIDGIN_LIBS)
+
+endif
+
+AM_CPPFLAGS = \
+ -DLIBDIR=\"$(PIDGIN_LIBDIR)\" \
+ -DDATADIR=\"$(PIDGIN_DATADIR)\" \
+ -DPIXMAPSDIR=\"$(PIDGIN_PIXMAPSDIR)\" \
+ $(DEBUG_CFLAGS) \
+ $(PIDGIN_CFLAGS) \
+ $(GTK_CFLAGS)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/msglen/Makefile.mingw Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,12 @@
+#
+# Makefile.mingw
+#
+# Description: Makefile for convbadger plugin.
+#
+
+PP_TOP := ..
+
+PP = msglen
+
+include $(PP_TOP)/win_pp.mak
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/msglen/msglen.c Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,217 @@
+/*
+ * msglen - Adds the current message's length to the menutray of a conversation
+ * Copyright (C) 2008 Gary Kramlich <grim@reaperworld.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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA.
+ */
+
+/* If you can't figure out what this line is for, DON'T TOUCH IT. */
+#include "../common/pp_internal.h"
+
+#include <gtk/gtk.h>
+
+#include <conversation.h>
+#include <signals.h>
+
+#include <gtkconv.h>
+#include <gtkmenutray.h>
+#include <gtkplugin.h>
+#include <gtkutils.h>
+
+/******************************************************************************
+ * Structs
+ *****************************************************************************/
+typedef struct {
+ PurpleConversation *conv;
+ PidginWindow *win;
+ GtkWidget *label;
+} MsgLenData;
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+static GHashTable *data = NULL;
+
+/******************************************************************************
+ * helpers
+ *****************************************************************************/
+static void
+msg_len_data_free(MsgLenData *mld) {
+ mld->win = NULL;
+ mld->conv = NULL;
+
+ if(mld->label && GTK_IS_LABEL(mld->label))
+ gtk_widget_destroy(mld->label);
+
+ g_free(mld);
+
+ mld = NULL;
+}
+
+static void
+msg_len_data_free_helper(gpointer k, gpointer v, gpointer d) {
+ MsgLenData *mld = (MsgLenData *)v;
+
+ msg_len_data_free(mld);
+}
+
+static void
+msg_len_update(PidginWindow *win, PurpleConversation *conv) {
+ PidginConversation *gtkconv = NULL;
+ MsgLenData *mld = NULL;
+ gchar *text = NULL;
+ gint count = 0;
+
+ g_return_if_fail(win);
+ g_return_if_fail(conv);
+
+ mld = g_hash_table_lookup(data, conv);
+
+ if(mld == NULL) {
+ mld = g_new0(MsgLenData, 1);
+
+ mld->win = win;
+ mld->conv
+
+ mld->label = gtk_label_new("");
+ pidgin_menu_tray_append(PIDGIN_MENU_TRAY(win->menu.tray), mld->label,
+ NULL);
+ gtk_widget_show(mld->label);
+
+ g_signal_connect_swapped(G_OBJECT(mld->label), "destroy",
+ G_CALLBACK(g_nullify_pointer), &mld->label);
+ }
+
+ mld->conv = conv;
+
+ gtkconv = PIDGIN_CONVERSATION(conv);
+ count = gtk_text_buffer_get_char_count(gtkconv->entry_buffer);
+
+ text = g_strdup_printf("%d", count);
+ gtk_label_set_text(GTK_LABEL(mld->label), text);
+ g_free(text);
+
+ g_hash_table_insert(data, win, mld);
+}
+
+/******************************************************************************
+ * Callbacks
+ *****************************************************************************/
+static void
+msg_len_conv_created_cb(PurpleConversation *conv, gpointer data) {
+ PidginConversation *pconv = PIDGIN_CONVERSATION(conv);
+ PidginWindow *win = pidgin_conv_get_window(pconv);
+
+ purple_debug_info("msglen", "created\n");
+
+ msg_len_update(win, conv);
+}
+
+static void
+msg_len_conv_destroyed_cb(PurpleConversation *conv, gpointer data) {
+ purple_debug_info("msglen", "destroyed\n");
+}
+
+static void
+msg_len_conv_switched_cb(PurpleConversation *conv, gpointer data) {
+ PidginConversation *pconv = PIDGIN_CONVERSATION(conv);
+ PidginWindow *win = pidgin_conv_get_window(pconv);
+
+ purple_debug_info("msglen", "switched\n");
+
+ msg_len_update(win, conv);
+}
+
+/******************************************************************************
+ * Plugin Stuff
+ *****************************************************************************/
+static gboolean
+plugin_load(PurplePlugin *plugin) {
+ void *conv_handle = purple_conversations_get_handle();
+
+ data = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, NULL);
+
+ purple_signal_connect(conv_handle, "conversation-created", plugin,
+ PURPLE_CALLBACK(msg_len_conv_created_cb), NULL);
+ purple_signal_connect(conv_handle, "deleting-conversation", plugin,
+ PURPLE_CALLBACK(msg_len_conv_destroyed_cb), NULL);
+
+ purple_signal_connect(pidgin_conversations_get_handle(),
+ "conversation-switched", plugin,
+ PURPLE_CALLBACK(msg_len_conv_switched_cb), NULL);
+
+ return TRUE;
+}
+
+static gboolean
+plugin_unload(PurplePlugin *plugin) {
+ g_hash_table_foreach(data, msg_len_data_free_helper, NULL);
+
+ g_hash_table_destroy(data);
+
+ data = NULL;
+
+ return TRUE;
+}
+
+static PurplePluginInfo info = {
+ PURPLE_PLUGIN_MAGIC,
+ PURPLE_MAJOR_VERSION,
+ PURPLE_MINOR_VERSION,
+ PURPLE_PLUGIN_STANDARD,
+ PIDGIN_PLUGIN_TYPE,
+ 0,
+ NULL,
+ PURPLE_PRIORITY_DEFAULT,
+
+ "gtk-plugin_pack-msglen",
+ NULL,
+ PP_VERSION,
+ NULL,
+ NULL,
+ "Gary Kramlich <grim@reaperworld.com>",
+ PP_WEBSITE,
+
+ plugin_load,
+ plugin_unload,
+ NULL,
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+
+static void
+init_plugin(PurplePlugin *plugin) {
+#ifdef ENABLE_NLS
+ bindtextdomain(GETTEXT_PACKAGE, PP_LOCALEDIR);
+ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+#endif /* ENABLE_NLS */
+
+ info.name = _("Message Length");
+ info.summary = _("Shows the length of your current message in the menu "
+ "tray");
+ info.description = info.summary;
+}
+
+PURPLE_INIT_PLUGIN(msg_len, init_plugin, info)
--- a/po/POTFILES.in Wed Apr 23 05:09:46 2008 -0400
+++ b/po/POTFILES.in Wed Apr 23 05:10:02 2008 -0400
@@ -1,5 +1,22 @@
album/album.c
album/album-ui.c
+autoprofile/autoaway.c
+autoprofile/autoprofile.c
+autoprofile/autoreply.c
+autoprofile/comp_countdownup.c
+autoprofile/comp_executable.c
+autoprofile/comp_http.c
+autoprofile/comp_logstats.c
+autoprofile/comp_logstats_gtk.c
+autoprofile/comp_quotation.c
+autoprofile/comp_rss.c
+autoprofile/comp_textfile.c
+autoprofile/comp_timestamp.c
+autoprofile/comp_uptime.c
+autoprofile/gtk_actions.c
+autoprofile/gtk_away_msgs.c
+autoprofile/gtk_widget.c
+autoprofile/preferences.c
autoreply/autoreply.c
awaynotify/awaynotify.c
bash/bash.c
@@ -8,6 +25,7 @@
buddytime/buddytime.c
buddytime/gtkbuddytime.c
chronic/chronic.c
+colorize/colorize.c
common/purple_template.c
common/gtk_template.c
convbadger/convbadger.c
@@ -19,6 +37,7 @@
findip/findip.c
findip/findip.c
flip/flip.c
+google/google.c
gRIM/gRIM.c
groupmsg/groupmsg.c
hideconv/hideconv.c
@@ -57,6 +76,7 @@
simfix/simfix.c
slashexec/slashexec.c
snpp/snpp.c
+splitter/splitter.c
sslinfo/sslinfo.c
stocker/stocker.c
stocker/stocker_prefs.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/splitter/ChangeLog Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,71 @@
+splitter v0.95
+Ike Gingerich <ike_@users.sourceforge.net>
+
+2007-05-04 21:21:15 [v0.95 for 2.0.0]
+
+ * trimmed a good amount of unnecessary code and made with the
+ gaim -> pidgin conversion.
+
+2006-04-15 15:55:10 [v0.95]
+
+ * now using Pango to split the message appropriately in different languages
+
+2006-04-13 20:33:07 [v0.93]
+
+ * fixed a bug where border characters were sometimes eaten as whitespace
+ * no longer processes empty slices
+
+2006-04-13 16:47:22 [v0.92]
+
+ * replaced html slicing algorithm with a modified version of Gaim's
+ * corrected a non-static function to be static
+ * internal refactoring
+
+2006-04-11 09:52:29 [v0.91]
+
+ * fixed a bug with escaped HTML characters counting for more than one
+ character (thanks xx3nvyxx)
+
+2006-04-11 01:25:06 [v0.9]
+
+ * added continuing of HTML formatting between splits
+ * removed "split around whole words" option and made default behavior
+
+2005-10-04 23:39:59 [v0.8]
+
+ * fixed a tiny but lethal and frustrating crash related to word wrapping
+ (big thanks to itchysoft_ant and mgilb81)
+ * added additional NULL pointer checking
+
+2005-09-23 18:37:24 [v0.7]
+
+ * chat support added
+
+2005-09-23 09:37:24 [v0.6]
+
+ * you can now specify delay between message sends
+
+2005-09-12 04:40:16 [v0.5]
+
+ * splits on whitespace where possible
+ * preferences option added to mediate splitting on whitespace
+
+2005-07-27 00:19:21 [v0.4]
+
+ * sends messages in the same manner as gaim:
+ - emits "sent-im-msg" signal
+ - takes into consideration HTML preferences
+ * much more robust error checking
+
+2005-07-22 07:44:06 [v0.3]
+
+ * big memory allocation bug fixed that could cause a crash in certain situations
+
+2005-07-21 20:29:44 [v0.2]
+
+ * alias is displayed in conversation window instead of username
+ (thanks rageboy04)
+
+2005-07-21 03:50:14 [v0.1]
+
+ * initial release of plugin
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/splitter/Makefile.am Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,26 @@
+EXTRA_DIST = .purple-plugin .incomplete Makefile.mingw
+
+splitterdir = $(PURPLE_LIBDIR)
+
+splitter_la_LDFLAGS = -module -avoid-version
+
+if HAVE_PURPLE
+
+splitter_LTLIBRARIES = splitter.la
+
+splitter_la_SOURCES = \
+ splitter.c
+
+splitter_la_LIBADD = \
+ $(GLIB_LIBS) \
+ $(PURPLE_LIBS)
+
+endif
+
+AM_CPPFLAGS = \
+ -DLIBDIR=\"$(PURPLE_LIBDIR)\" \
+ -DDATADIR=\"$(PURPLE_DATADIR)\" \
+ -DPIXMAPSDIR=\"$(PURPLE_PIXMAPSDIR)\" \
+ $(DEBUG_CFLAGS) \
+ $(PURPLE_CFLAGS)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/splitter/Makefile.mingw Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,12 @@
+#
+# Makefile.mingw
+#
+# Description: Makefile for dice plugin.
+#
+
+PP_TOP := ..
+
+PP = splitter
+
+include $(PP_TOP)/win_pp.mak
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/splitter/README Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,91 @@
+Message Splitter Plugin v0.95
+Ike Gingerich <ike_@users.sourceforge.net>
+
+
+------------
+INTRODUCTION
+------------
+
+This is a simple plugin to split up outgoing messages that are larger
+than a specified threshold in characters.
+
+
+--------
+FEATURES
+--------
+
+ - The split size and delay between messages are configurable from the
+ plugin preferences menu.
+ - Splits yield valid and balanced HTML taking into account tags that may
+ have been opened or closed outside the split itself.
+ - Splitting is done using Pango to split the message as appropriate
+ according to the current locale.
+
+
+----
+TODO
+----
+
+ - fix conflicts with plugins like Slashexec that don't expect to be
+ supplied an empty message during the 'sending-im' signal.
+ - fix bug with characters disappearing when splitting heavily marked-up
+ lines.
+ - find any remaining bugs and memory leaks.
+
+------------
+INSTALLATION
+------------
+
+ - *NIX users:
+ $ make install
+
+ If you have build problems make sure you have the
+ appropriate pidgin-dev and build-essential files
+ installed.
+
+ Alternately you can copy spliter.c to
+ (unzipped-source)/pidgin/plugins and
+ after building Pidgin:
+
+ $ make splitter.so
+
+ then copy splitter.so to ~/.purple/plugins/ and launch Pidgin.
+
+
+ - Windows users:
+ I try to keep a pre-built current version of the plugin here:
+ <http://ikebo.hypermart.net/splitter/splitter-current.dll> and
+ on the Sourceforge message splitter plugin tracker.
+
+ Otherwise you must compile it manually with Cygwin:
+
+ copy splitter.c to the plugin directory where the Pidgin
+ source code is extracted to and type:
+
+ $ make -f Makefile.mingw splitter.dll
+
+ and copy splitter.dll to your plugin directory
+ (e.x. C:\Program Files\Pidgin\plugins)
+
+
+------------
+CONTRIBUTORS
+------------
+
+xx3nvyxx - caught disappearing text bug in v0.9
+
+itchysoft_ant - isolated crash in v0.7 and submitted backtrace logs
+ suggested delay/chat features for v0.6/v0.7
+
+mgilb81 - notified of crash in v0.7 and filed report
+
+rageboy04 - a number of other issues/feedback throughout
+ - notified/fixed alias issues for v0.2
+
+
+-------
+CONTACT
+-------
+
+Feel free to contact me at <ike_@users.sourceforge.net> about problems,
+suggestions, or contributions.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/splitter/splitter.c Wed Apr 23 05:10:02 2008 -0400
@@ -0,0 +1,533 @@
+/* Message Splitter Plugin v0.95
+ *
+ * Splits a large message into smaller messages and sends them away
+ * in its place.
+ *
+ * Copyright (C) 2005-2007, Ike Gingerich <ike_@users.sourceforge.net>
+ *
+ * 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.
+ */
+
+#define GETTEXT_PACKAGE "gtk20"
+#include <glib/gi18n-lib.h>
+
+#include <gtk/gtk.h>
+
+#include <string.h>
+#include <errno.h>
+
+#ifndef PURPLE_PLUGINS
+#define PURPLE_PLUGINS
+#endif
+
+#include <debug.h>
+#include <notify.h>
+#include <version.h>
+#include <util.h>
+
+#define WEBSITE "http://ikebo.hypermart.net/"
+#define PLUGIN_ID "core-ike-splitter"
+
+/* grr */
+#ifndef ENOTCONN
+#define ENOTCONN 107
+#endif
+
+/* plugin constants and structures */
+static const gint MIN_SPLIT_SIZE = 32;
+static const gint DEFAULT_SPLIT_SIZE = 786;
+static const gint MAX_SPLIT_SIZE = 8192;
+
+static const gint MIN_DELAY_MS = 0;
+static const gint DEFAULT_DELAY_MS = 500;
+static const gint MAX_DELAY_MS = 3600000;
+
+typedef struct
+{
+ char *sender_username;
+ char *sender_protocol_id;
+ GQueue *messages;
+
+ PurpleConversationType type;
+ union {
+ char *receiver; /* IM username */
+ int id; /* chat ID */
+ };
+} message_to_conv;
+
+typedef struct {
+ int start, end;
+} message_slice;
+
+/* plugin preference variables */
+static gint current_split_size;
+
+
+/* initialize preferences dialog */
+static PurplePluginPrefFrame *get_plugin_pref_frame(PurplePlugin *plugin)
+{
+ PurplePluginPrefFrame *frame;
+ PurplePluginPref *ppref;
+
+ frame = purple_plugin_pref_frame_new();
+ g_return_val_if_fail(frame != NULL, NULL);
+
+ ppref = purple_plugin_pref_new_with_label("Message split size");
+ g_return_val_if_fail(ppref != NULL, NULL);
+ purple_plugin_pref_frame_add(frame, ppref);
+ ppref = purple_plugin_pref_new_with_name_and_label("/plugins/core/splitter/split_size",
+ "Letter count: ");
+ g_return_val_if_fail(ppref != NULL, NULL);
+ purple_plugin_pref_set_bounds(ppref, MIN_SPLIT_SIZE, MAX_SPLIT_SIZE);
+ purple_plugin_pref_frame_add(frame, ppref);
+
+ ppref = purple_plugin_pref_new_with_label("Delay between messages");
+ g_return_val_if_fail(ppref != NULL, NULL);
+ purple_plugin_pref_frame_add(frame, ppref);
+ ppref = purple_plugin_pref_new_with_name_and_label("/plugins/core/splitter/delay_ms",
+ "ms: ");
+ g_return_val_if_fail(ppref != NULL, NULL);
+ purple_plugin_pref_set_bounds(ppref, MIN_DELAY_MS, MAX_DELAY_MS);
+ purple_plugin_pref_frame_add(frame, ppref);
+
+ return frame;
+}
+
+/**
+ * A function to send a chat or im message to the specific conversation
+ * without emitting "sending-im" or "sending-chat" signal, which would
+ * cause an infinite loop for this plugin.
+ *
+ * taken from conversation.c with signal emission removed.
+ */
+static void splitter_common_send(PurpleConversation *conv, const char *message, PurpleMessageFlags msgflags)
+{
+ PurpleConversationType type;
+ PurpleAccount *account;
+ PurpleConnection *gc;
+ char *displayed = NULL, *sent = NULL;
+ int err = 0;
+
+ if (strlen(message) == 0)
+ return;
+
+ account = purple_conversation_get_account(conv);
+ gc = purple_conversation_get_gc(conv);
+
+ g_return_if_fail(account != NULL);
+ g_return_if_fail(gc != NULL);
+
+ type = purple_conversation_get_type(conv);
+
+ /* Always linkfy the text for display */
+ displayed = purple_markup_linkify(message);
+
+ if ((conv->features & PURPLE_CONNECTION_HTML) &&
+ !(msgflags & PURPLE_MESSAGE_RAW))
+ {
+ sent = g_strdup(displayed);
+ }
+ else
+ sent = g_strdup(message);
+
+ msgflags |= PURPLE_MESSAGE_SEND;
+
+ if (type == PURPLE_CONV_TYPE_IM) {
+ PurpleConvIm *im = PURPLE_CONV_IM(conv);
+
+ if (sent != NULL && sent[0] != '\0') {
+
+ err = serv_send_im(gc, purple_conversation_get_name(conv),
+ sent, msgflags);
+
+ if ((err > 0) && (displayed != NULL))
+ purple_conv_im_write(im, NULL, displayed, msgflags, time(NULL));
+
+ purple_signal_emit(purple_conversations_get_handle(), "sent-im-msg",
+ account,
+ purple_conversation_get_name(conv), sent);
+ }
+ }
+ else {
+ if (sent != NULL && sent[0] != '\0') {
+ err = serv_chat_send(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)), sent, msgflags);
+
+ purple_signal_emit(purple_conversations_get_handle(), "sent-chat-msg",
+ account, sent,
+ purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)));
+ }
+ }
+
+ if (err < 0) {
+ const char *who;
+ const char *msg;
+
+ who = purple_conversation_get_name(conv);
+
+ if (err == -E2BIG) {
+ msg = _("Unable to send message: The message is too large.");
+
+ if (!purple_conv_present_error(who, account, msg)) {
+ char *msg2 = g_strdup_printf(_("Unable to send message to %s."), who);
+ purple_notify_error(gc, NULL, msg2, _("The message is too large."));
+ g_free(msg2);
+ }
+ }
+ else if (err == -ENOTCONN) {
+ purple_debug(PURPLE_DEBUG_ERROR, "conversation",
+ "Not yet connected.\n");
+ }
+ else {
+ msg = _("Unable to send message.");
+
+ if (!purple_conv_present_error(who, account, msg)) {
+ char *msg2 = g_strdup_printf(_("Unable to send message to %s."), who);
+ purple_notify_error(gc, NULL, msg2, NULL);
+ g_free(msg2);
+ }
+ }
+ }
+
+ g_free(displayed);
+ g_free(sent);
+}
+
+/* a timer based callback function that sends the next message in the queue */
+static gboolean send_message_timer_cb( message_to_conv *msg_to_conv )
+{
+ PurpleAccount *account;
+ PurpleConversation *conv;
+ gchar *msg;
+
+ g_return_val_if_fail(msg_to_conv != NULL, FALSE);
+ g_return_val_if_fail(msg_to_conv->messages != NULL, FALSE);
+ g_return_val_if_fail(msg_to_conv->sender_username != NULL, FALSE);
+ g_return_val_if_fail(msg_to_conv->sender_protocol_id != NULL, FALSE);
+
+ msg = g_queue_pop_head(msg_to_conv->messages);
+
+ if( msg == NULL )
+ {
+ /* clean up and terminate timer callback */
+ g_queue_free(msg_to_conv->messages);
+ g_free(msg_to_conv->sender_username);
+ g_free(msg_to_conv->sender_protocol_id);
+ if( msg_to_conv->type == PURPLE_CONV_TYPE_IM &&
+ msg_to_conv->receiver != NULL )
+ g_free(msg_to_conv->receiver);
+
+ g_free(msg_to_conv);
+
+ return FALSE;
+ }
+ else
+ {
+ /* find account info (it may have changed) and try and create a new
+ conversation window (it may have been closed) or find the existing
+ chat, and finally send the message */
+ account = purple_accounts_find(msg_to_conv->sender_username,
+ msg_to_conv->sender_protocol_id);
+ g_return_val_if_fail(account != NULL, FALSE);
+
+ if( msg_to_conv->type == PURPLE_CONV_TYPE_IM && msg_to_conv->receiver != NULL )
+ conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, msg_to_conv->receiver);
+ else if( msg_to_conv->type == PURPLE_CONV_TYPE_CHAT )
+ conv = purple_find_chat(account->gc, msg_to_conv->id);
+ else
+ conv = NULL;
+
+ g_return_val_if_fail(conv != NULL, FALSE);
+
+ splitter_common_send(conv, msg, PURPLE_MESSAGE_SEND);
+ g_free(msg);
+
+ return TRUE;
+ }
+}
+
+/* finds the first line-breakable character backwards starting from a[last] */
+static int find_last_break(PangoLogAttr *a, int last)
+{
+ for(; last > 0; last-- )
+ if( a[last].is_line_break == 1)
+ break;
+
+ return ( a[last].is_line_break == 1) ? last-1 : -1;
+}
+
+/* uses Pango to find all possible line break locations in a message and returns
+ a PangoLogAttr array which maps to each byte of the message of length
+ one larger than the message. This must be g_free()'d */
+static PangoLogAttr* find_all_breaks(const char *message)
+{
+ PangoContext *context;
+ PangoLogAttr *a;
+ GList *list;
+ int len, n_attr;
+
+ g_return_val_if_fail(message != NULL, NULL);
+
+ len = strlen(message);
+ n_attr = len+1;
+ a = g_new0(PangoLogAttr, n_attr);
+
+ /* init Pango */
+ context = gdk_pango_context_get();
+ g_return_val_if_fail(context != NULL, NULL);
+
+ list = pango_itemize(context, message, 0, len, NULL, NULL);
+
+ if (list != NULL && list->data != NULL)
+ pango_break(message, -1, &((PangoItem*)(list->data))->analysis, a, n_attr);
+
+ return a;
+}
+
+/* return a queue of message slices from a plain text message based on current_split_size using
+ Pango to determine possible line break locations */
+static GQueue* get_message_slices(const char *message)
+{
+ int current_break_start, last_break_start, break_pos, len;
+ message_slice *slice;
+ PangoLogAttr *a;
+ GQueue *q;
+
+ q = g_queue_new();
+ len = strlen(message);
+ a = find_all_breaks(message);
+ g_return_val_if_fail(a != NULL, NULL);
+
+ last_break_start = current_break_start = 0;
+
+ while(current_break_start + current_split_size < len)
+ {
+ break_pos = find_last_break(a + last_break_start, current_split_size);
+
+ if( break_pos > -1 ) current_break_start += break_pos;
+ else current_break_start += current_split_size;
+
+ slice = g_new0( message_slice, 1 );
+ slice->start = MAX( last_break_start, 0 );
+ slice->end = MIN( current_break_start, len );
+
+ if( slice->end > slice->start )
+ g_queue_push_tail(q, slice);
+ else g_free(slice);
+
+ if( break_pos > -1 )
+ current_break_start++;
+
+ last_break_start = current_break_start;
+ }
+
+ slice = g_new0( message_slice, 1 );
+ slice->start = last_break_start;
+ slice->end = len;
+ g_queue_push_tail(q, slice);
+
+ /* cleanup */
+ g_free(a);
+
+ return q;
+
+}
+
+/* takes a message, splits it up based on whitespace (ignoring HTML formatting),
+ requests HTMLized slices of the splits, and returns a queue of them. The
+ messages and the queue must be freed */
+static GQueue* create_message_queue(const char *message)
+{
+ GQueue *slices, *messages;
+ message_slice *slice;
+ char *stripped_message, *msg;
+ int stripped_len;
+
+ stripped_message = purple_markup_strip_html(message);
+ stripped_len = strlen(stripped_message);
+
+ messages = g_queue_new();
+ slices = get_message_slices(stripped_message);
+ g_return_val_if_fail(slices != NULL, NULL);
+
+ while( (slice = g_queue_pop_head(slices)) != NULL )
+ {
+ msg = purple_markup_slice(message, slice->start, slice->end);
+
+ if( msg != NULL )
+ g_queue_push_tail(messages, msg);
+
+ g_free(slice);
+ }
+
+ g_queue_free(slices);
+
+ /* cleanup */
+ g_free(stripped_message);
+
+ return messages;
+}
+
+/* create message queue and prepare timer callbacks */
+static void split_and_send(message_to_conv *msg_to_conv, const char **message)
+{
+ gint message_delay_ms;
+
+ g_return_if_fail( msg_to_conv != NULL );
+ g_return_if_fail( message != NULL );
+ g_return_if_fail( *message != NULL );
+
+ /* read and validate preferences */
+ current_split_size = purple_prefs_get_int("/plugins/core/splitter/split_size");
+ if( current_split_size > MAX_SPLIT_SIZE ) current_split_size = MAX_SPLIT_SIZE;
+ if( current_split_size < MIN_SPLIT_SIZE ) current_split_size = MIN_SPLIT_SIZE;
+
+ message_delay_ms = purple_prefs_get_int("/plugins/core/splitter/delay_ms");
+ if( message_delay_ms > MAX_DELAY_MS ) message_delay_ms = MAX_DELAY_MS;
+ if( message_delay_ms < MIN_DELAY_MS ) message_delay_ms = MIN_DELAY_MS;
+
+ /* prepare message queue */
+ msg_to_conv->messages = create_message_queue(*message);
+ g_return_if_fail( msg_to_conv->messages != NULL );
+
+ /* initialize message send timer */
+ purple_timeout_add( (g_queue_get_length(msg_to_conv->messages) > 1) ? message_delay_ms : 0,
+ (GSourceFunc)send_message_timer_cb,
+ msg_to_conv);
+
+ /* free the original message and ensure it does not get sent */
+ g_free((char*)*message);
+ *message = NULL;
+}
+
+/* initialize a chat message to potentially be split */
+static void sending_chat_msg_cb(PurpleAccount *account, const char **message, int id)
+{
+ message_to_conv *msg_to_conv;
+
+ purple_debug(PURPLE_DEBUG_MISC, "purple-splitter", "splitter plugin invoked\n");
+
+ g_return_if_fail(account != NULL);
+ g_return_if_fail(message != NULL);
+ g_return_if_fail(*message != NULL);
+
+ msg_to_conv = g_new0(message_to_conv, 1);
+ g_return_if_fail( msg_to_conv != NULL );
+
+ msg_to_conv->sender_username = g_strdup(account->username);
+ msg_to_conv->sender_protocol_id = g_strdup(account->protocol_id);
+ msg_to_conv->id = id;
+ msg_to_conv->type = PURPLE_CONV_TYPE_CHAT;
+
+ split_and_send(msg_to_conv, message);
+}
+
+/* initialize an IM message to potentially be split */
+static void sending_im_msg_cb(PurpleAccount *account, const char *receiver,
+ const char **message)
+{
+ message_to_conv *msg_to_conv;
+
+ purple_debug(PURPLE_DEBUG_MISC, "purple-splitter", "splitter plugin invoked\n");
+
+ g_return_if_fail(account != NULL);
+ g_return_if_fail(receiver != NULL);
+ g_return_if_fail(message != NULL);
+ g_return_if_fail(*message != NULL);
+
+ msg_to_conv = g_new0(message_to_conv, 1);
+ g_return_if_fail( msg_to_conv != NULL );
+
+ msg_to_conv->sender_username = g_strdup(account->username);
+ msg_to_conv->sender_protocol_id = g_strdup(account->protocol_id);
+ msg_to_conv->receiver = g_strdup(receiver);
+ msg_to_conv->type = PURPLE_CONV_TYPE_IM;
+
+ split_and_send(msg_to_conv, message);
+}
+
+/* register "sending" message signal callback */
+static gboolean plugin_load(PurplePlugin *plugin)
+{
+ purple_signal_connect(purple_conversations_get_handle(),
+ "sending-im-msg",
+ plugin,
+ PURPLE_CALLBACK(sending_im_msg_cb),
+ NULL);
+ purple_signal_connect(purple_conversations_get_handle(),
+ "sending-chat-msg",
+ plugin,
+ PURPLE_CALLBACK(sending_chat_msg_cb),
+ NULL);
+
+ return TRUE;
+}
+
+
+static gboolean plugin_unload(PurplePlugin *plugin)
+{
+ return TRUE;
+}
+
+static PurplePluginUiInfo prefs_info = {
+ get_plugin_pref_frame, 0, NULL, NULL, NULL, NULL, NULL
+};
+
+static PurplePluginInfo info =
+{
+ PURPLE_PLUGIN_MAGIC,
+ PURPLE_MAJOR_VERSION,
+ PURPLE_MINOR_VERSION,
+ PURPLE_PLUGIN_STANDARD, /**< type */
+ NULL, /**< ui_requirement */
+ 0, /**< flags */
+ NULL, /**< dependencies */
+ PURPLE_PRIORITY_DEFAULT, /**< priority */
+
+ PLUGIN_ID, /**< id */
+ N_("Message Splitter"), /**< name */
+ VERSION, /**< version */
+ /** summary */
+ N_("Splits a large outgoing message into smaller "
+ "messages of a specified size."),
+ /** description */
+ N_("Splits a large outgoing message into smaller "
+ "messages of a specified size."),
+ "Ike Gingerich <ike_@users.sourceforge.net>", /**< author */
+ WEBSITE, /**< homepage */
+
+ plugin_load, /**< load */
+ plugin_unload, /**< unload */
+ NULL, /**< destroy */
+
+ NULL, /**< ui_info */
+ NULL, /**< extra_info */
+ &prefs_info, /**< prefs_info */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+/* store initial preference values */
+static void init_plugin(PurplePlugin *plugin)
+{
+ purple_prefs_add_none("/plugins/core/splitter");
+ purple_prefs_add_int ("/plugins/core/splitter/split_size", DEFAULT_SPLIT_SIZE);
+ purple_prefs_add_int ("/plugins/core/splitter/delay_ms", DEFAULT_DELAY_MS);
+}
+
+PURPLE_INIT_PLUGIN(splitter, init_plugin, info)
--- a/switchspell/Makefile.am Wed Apr 23 05:09:46 2008 -0400
+++ b/switchspell/Makefile.am Wed Apr 23 05:10:02 2008 -0400
@@ -14,8 +14,9 @@
switchspell.c
switchspell_la_LIBADD = \
- $(PIDGIN_LIBS) \
- $(GTK_LIBS)
+ $(ASPELL_LIBS) \
+ $(GTK_LIBS) \
+ $(PIDGIN_LIBS)
endif # PIDGIN
@@ -23,6 +24,7 @@
-DLIBDIR=\"$(PIDGIN_LIBDIR)\" \
-DDATADIR=\"$(PIDGIN_DATADIR)\" \
-DPIXMAPSDIR=\"$(PIDGIN_PIXMAPSDIR)\" \
+ $(ASPELL_CFLAGS) \
$(GTK_CFLAGS) \
$(DEBUG_CFLAGS) \
$(PIDGIN_CFLAGS) \