pidgin/purple-plugin-pack
Clone
Summary
Browse
Changes
Graph
Updating the ChangeLog, step 1 in release process.
2009-08-30, John Bailey
ebe69a8d5441
Updating the ChangeLog, step 1 in release process.
/*
* A neat little Purple plugin to integrate with GNU Talk Filters.
* http://www.hyperrealm.com/talkfilters/talkfilters.html
*
* Mark Lindner <markl@gnu.org> 1/6/04
* Updates for the purple plugin pack (C) 2005 by
* Peter Lawler <bleeter from users.sf.net>
*/
/* TODO:
-- slash commands (allowing it to be a one liner)
-- allow saving different filters for different buddies (or accounts)
*/
/* If you can't figure out what this line is for, DON'T TOUCH IT. */
#include
"../common/pp_internal.h"
#include
<stdio.h>
#include
<string.h>
#ifndef _WIN32
#include
<strings.h>
#endif
#include
<sys/types.h>
#include
<sys/stat.h>
#include
<debug.h>
#include
<signals.h>
#include
<util.h>
#include
<gtkplugin.h>
#include
<gtkutils.h>
#include
<talkfilters.h>
#define PREF_PREFIX "/plugins/gtk/bleeter/talkfilters"
#define PREF_ENABLED PREF_PREFIX "/enabled"
#define PREF_FILTER PREF_PREFIX "/filter"
#define PROP_FILTER "talkfilter::filter"
static
const
gtf_filter_t
*
current_filter
=
NULL
;
static
const
gtf_filter_t
*
filter_list
=
NULL
;
static
int
filter_count
=
0
;
static
void
translate_message
(
char
**
message
,
const
gtf_filter_t
*
filter
)
{
if
(
message
==
NULL
||
*
message
==
NULL
)
{
purple_debug_info
(
"talkfilters"
,
"Null message
\n
"
);
return
;
}
if
(
filter
!=
NULL
)
{
gchar
*
tmp
;
size_t
len
=
strlen
(
*
message
);
if
(
len
<
40
)
len
+=
40
;
else
len
*=
2
;
/* XXX: Is it always true, or are we just hoping it is? */
tmp
=
(
gchar
*
)
g_malloc
(
len
);
filter
->
filter
(
*
message
,
tmp
,
len
);
g_free
(
*
message
);
*
message
=
tmp
;
}
else
{
purple_debug_info
(
"talkfilters"
,
"No filter set
\n
"
);
}
}
static
void
translate_message_im
(
PurpleAccount
*
account
,
char
*
who
,
char
**
message
,
gpointer
dontcare
)
{
PurpleConversation
*
conv
;
PidginConversation
*
gtkconv
;
conv
=
purple_find_conversation_with_account
(
PURPLE_CONV_TYPE_IM
,
who
,
account
);
if
(
!
conv
)
return
;
gtkconv
=
PIDGIN_CONVERSATION
(
conv
);
if
(
!
gtkconv
)
return
;
translate_message
(
message
,
g_object_get_data
(
G_OBJECT
(
gtkconv
->
imhtml
),
PROP_FILTER
));
}
static
void
translate_message_chat
(
PurpleAccount
*
account
,
char
**
message
,
int
id
,
gpointer
dontcare
)
{
PurpleConversation
*
conv
;
PidginConversation
*
gtkconv
;
conv
=
purple_find_chat
(
account
->
gc
,
id
);
if
(
!
conv
)
return
;
gtkconv
=
PIDGIN_CONVERSATION
(
conv
);
if
(
!
gtkconv
)
return
;
translate_message
(
message
,
g_object_get_data
(
G_OBJECT
(
gtkconv
->
imhtml
),
PROP_FILTER
));
}
static
void
update_selected_filter
()
{
const
gtf_filter_t
*
filter
;
gint
ct
;
const
char
*
val
=
purple_prefs_get_string
(
PREF_FILTER
);
current_filter
=
NULL
;
ct
=
filter_count
;
for
(
filter
=
filter_list
;
ct
;
filter
++
,
ct
--
)
{
/* XXX: Is this overkill? Is strcmp enough? */
if
(
g_utf8_collate
(
val
,
filter
->
name
)
==
0
)
{
current_filter
=
filter
;
purple_debug_info
(
"talkfilters"
,
"found default filter
\"
%s
\"\n
"
,
filter
->
name
);
break
;
}
}
}
static
void
filter_changed_cb
(
const
char
*
name
,
PurplePrefType
type
,
gconstpointer
val
,
gpointer
dontcare
)
{
update_selected_filter
();
}
static
gboolean
writing_im_msg
(
PurpleAccount
*
account
,
const
char
*
who
,
char
**
message
,
PurpleConversation
*
conv
,
PurpleMessageFlags
flags
,
gpointer
dontcare
)
{
if
(
flags
&
PURPLE_MESSAGE_SEND
)
{
PidginConversation
*
gtkconv
=
PIDGIN_CONVERSATION
(
conv
);
if
(
!
gtkconv
)
return
FALSE
;
translate_message
(
message
,
g_object_get_data
(
G_OBJECT
(
gtkconv
->
imhtml
),
PROP_FILTER
));
}
return
FALSE
;
}
static
void
menu_filter_changed_cb
(
GtkWidget
*
w
,
PidginWindow
*
win
)
{
if
(
gtk_check_menu_item_get_active
(
GTK_CHECK_MENU_ITEM
(
w
)))
{
PidginConversation
*
gtkconv
=
pidgin_conv_window_get_active_gtkconv
(
win
);
g_object_set_data
(
G_OBJECT
(
gtkconv
->
imhtml
),
PROP_FILTER
,
g_object_get_data
(
G_OBJECT
(
w
),
PROP_FILTER
));
}
}
static
void
regenerate_talkfilter_menu
(
PidginConversation
*
gtkconv
)
{
PidginWindow
*
win
;
GtkWidget
*
menu
;
int
count
;
const
gtf_filter_t
*
filter
;
const
gtf_filter_t
*
curfilter
;
GtkWidget
*
mitem
,
*
item
;
GSList
*
list
=
NULL
;
if
(
gtkconv
==
NULL
)
return
;
win
=
pidgin_conv_get_window
(
gtkconv
);
if
(
win
==
NULL
)
return
;
mitem
=
g_object_get_data
(
G_OBJECT
(
win
->
window
),
PROP_FILTER
);
if
(
mitem
==
NULL
)
{
mitem
=
gtk_menu_item_new_with_mnemonic
(
_
(
"_Talkfilters"
));
/* XXX: or is it "Talk Filters"? */
gtk_menu_shell_insert
(
GTK_MENU_SHELL
(
win
->
menu
.
menubar
),
mitem
,
3
);
g_object_set_data
(
G_OBJECT
(
win
->
window
),
PROP_FILTER
,
mitem
);
gtk_widget_show
(
mitem
);
}
else
return
;
menu
=
gtk_menu_new
();
gtk_menu_item_set_submenu
(
GTK_MENU_ITEM
(
mitem
),
menu
);
curfilter
=
g_object_get_data
(
G_OBJECT
(
gtkconv
->
imhtml
),
PROP_FILTER
);
item
=
gtk_radio_menu_item_new_with_label
(
list
,
_
(
"(None)"
));
list
=
gtk_radio_menu_item_get_group
(
GTK_RADIO_MENU_ITEM
(
item
));
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
menu
),
item
);
g_signal_connect
(
G_OBJECT
(
item
),
"activate"
,
G_CALLBACK
(
menu_filter_changed_cb
),
win
);
for
(
count
=
filter_count
,
filter
=
filter_list
;
count
;
filter
++
,
count
--
)
{
item
=
gtk_radio_menu_item_new_with_label
(
list
,
filter
->
desc
);
g_object_set_data
(
G_OBJECT
(
item
),
PROP_FILTER
,
(
gpointer
)
filter
);
list
=
gtk_radio_menu_item_get_group
(
GTK_RADIO_MENU_ITEM
(
item
));
g_signal_connect
(
G_OBJECT
(
item
),
"activate"
,
G_CALLBACK
(
menu_filter_changed_cb
),
win
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
menu
),
item
);
}
gtk_widget_show_all
(
menu
);
}
static
void
update_talkfilter_selection
(
PidginConversation
*
gtkconv
)
{
PidginWindow
*
win
;
GtkWidget
*
menu
;
GList
*
item
;
const
gtf_filter_t
*
filter
;
if
(
gtkconv
==
NULL
)
return
;
win
=
pidgin_conv_get_window
(
gtkconv
);
if
(
win
==
NULL
)
return
;
menu
=
g_object_get_data
(
G_OBJECT
(
win
->
window
),
PROP_FILTER
);
if
(
menu
==
NULL
)
return
;
menu
=
gtk_menu_item_get_submenu
(
GTK_MENU_ITEM
(
menu
));
filter
=
g_object_get_data
(
G_OBJECT
(
gtkconv
->
imhtml
),
PROP_FILTER
);
for
(
item
=
gtk_container_get_children
(
GTK_CONTAINER
(
menu
));
item
;
item
=
item
->
next
)
{
if
(
filter
==
g_object_get_data
(
G_OBJECT
(
item
->
data
),
PROP_FILTER
))
{
gtk_check_menu_item_set_active
(
GTK_CHECK_MENU_ITEM
(
item
->
data
),
TRUE
);
break
;
}
}
}
static
void
conversation_switched_cb
(
PurpleConversation
*
conv
)
{
PidginConversation
*
gtkconv
=
PIDGIN_CONVERSATION
(
conv
);
regenerate_talkfilter_menu
(
gtkconv
);
update_talkfilter_selection
(
gtkconv
);
}
static
void
conversation_created_cb
(
PurpleConversation
*
conv
)
{
PidginConversation
*
gtkconv
=
PIDGIN_CONVERSATION
(
conv
);
/* hopefully fix a crash related to persistent convs */
if
(
gtkconv
==
NULL
)
return
;
g_object_set_data
(
G_OBJECT
(
gtkconv
->
imhtml
),
PROP_FILTER
,
(
gpointer
)
current_filter
);
update_talkfilter_selection
(
gtkconv
);
}
static
void
attach_talkfilter_menu
(
gpointer
data
,
gpointer
dontcare
)
{
PidginWindow
*
win
=
data
;
PidginConversation
*
gtkconv
;
gtkconv
=
pidgin_conv_window_get_active_gtkconv
(
win
);
regenerate_talkfilter_menu
(
gtkconv
);
update_talkfilter_selection
(
gtkconv
);
}
static
gboolean
plugin_load
(
PurplePlugin
*
plugin
)
{
void
*
conv_handle
=
purple_conversations_get_handle
();
filter_list
=
gtf_filter_list
();
filter_count
=
gtf_filter_count
();
update_selected_filter
();
purple_signal_connect
(
conv_handle
,
"sending-im-msg"
,
plugin
,
PURPLE_CALLBACK
(
translate_message_im
),
NULL
);
purple_signal_connect
(
conv_handle
,
"sending-chat-msg"
,
plugin
,
PURPLE_CALLBACK
(
translate_message_chat
),
NULL
);
/* XXX: This is necessary because the changed message isn't displayed locally.
* This doesn't always show the exact filtered message that is sent, but
* I guess it's better than no indication that the message was filtered.
* -- sadrul
*/
purple_signal_connect
(
conv_handle
,
"writing-im-msg"
,
plugin
,
PURPLE_CALLBACK
(
writing_im_msg
),
NULL
);
purple_prefs_connect_callback
(
plugin
,
PREF_FILTER
,
filter_changed_cb
,
NULL
);
/* Add a `Talkfilters' menu in the conversation window */
purple_signal_connect
(
conv_handle
,
"conversation-created"
,
plugin
,
PURPLE_CALLBACK
(
conversation_created_cb
),
NULL
);
purple_signal_connect
(
pidgin_conversations_get_handle
(),
"conversation-switched"
,
plugin
,
PURPLE_CALLBACK
(
conversation_switched_cb
),
NULL
);
g_list_foreach
(
pidgin_conv_windows_get_list
(),
attach_talkfilter_menu
,
NULL
);
return
TRUE
;
}
static
void
remove_talkfilter_menu
(
gpointer
data
,
gpointer
dontcare
)
{
PidginWindow
*
win
=
data
;
GtkWidget
*
menu
;
menu
=
g_object_get_data
(
G_OBJECT
(
win
->
window
),
PROP_FILTER
);
if
(
menu
)
{
gtk_widget_destroy
(
menu
);
g_object_set_data
(
G_OBJECT
(
win
->
window
),
PROP_FILTER
,
NULL
);
/* XXX: Do we need to set PROP_FILTER data to NULL for each gtkconv->imhtml as well?
* It doesn't seem to be necessary right now. The GTF library probably gets loaded
* at the very beginning when Purple starts, and not when this plugin is loaded. */
}
}
static
gboolean
plugin_unload
(
PurplePlugin
*
plugin
)
{
purple_prefs_disconnect_by_handle
(
plugin
);
g_list_foreach
(
pidgin_conv_windows_get_list
(),
remove_talkfilter_menu
,
NULL
);
return
TRUE
;
}
static
PurplePluginPrefFrame
*
get_plugin_pref_frame
(
PurplePlugin
*
plugin
)
{
PurplePluginPrefFrame
*
frame
;
PurplePluginPref
*
pref
;
const
gtf_filter_t
*
filter
;
gint
ct
;
frame
=
purple_plugin_pref_frame_new
();
pref
=
purple_plugin_pref_new_with_label
(
_
(
"Talk Filters"
));
purple_plugin_pref_frame_add
(
frame
,
pref
);
pref
=
purple_plugin_pref_new_with_name_and_label
(
PREF_FILTER
,
_
(
"Active filter:"
));
purple_plugin_pref_set_type
(
pref
,
PURPLE_PLUGIN_PREF_CHOICE
);
purple_plugin_pref_add_choice
(
pref
,
_
(
"(None)"
),
""
);
ct
=
filter_count
;
for
(
filter
=
filter_list
;
ct
;
filter
++
,
ct
--
)
{
purple_plugin_pref_add_choice
(
pref
,
filter
->
desc
,
(
gpointer
)
filter
->
name
);
}
purple_plugin_pref_frame_add
(
frame
,
pref
);
return
frame
;
}
static
PurplePluginUiInfo
prefs_info
=
{
get_plugin_pref_frame
,
0
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
};
static
PurplePluginInfo
talkfilters_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 */
"gtk-plugin_pack-talkfilters"
,
/* id */
NULL
,
/* name */
PP_VERSION
,
NULL
,
/* summary */
NULL
,
/* description */
"Mark Lindner <markl@gnu.org>, "
"Peter Lawler <bleeter@users.sf.net>"
,
PP_WEBSITE
,
plugin_load
,
plugin_unload
,
NULL
,
NULL
,
NULL
,
&
prefs_info
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
};
static
void
init_plugin
(
PurplePlugin
*
plugin
)
{
purple_prefs_add_none
(
"/plugins/gtk/bleeter"
);
purple_prefs_add_none
(
"/plugins/gtk/bleeter/talkfilters"
);
purple_prefs_add_bool
(
"/plugins/gtk/bleeter/talkfilters/enabled"
,
FALSE
);
purple_prefs_add_string
(
"/plugins/gtk/bleeter/talkfilters/filter"
,
""
);
talkfilters_info
.
name
=
_
(
"GNU Talk Filters"
);
talkfilters_info
.
summary
=
_
(
"Translates text in outgoing messages into humorous dialects."
);
talkfilters_info
.
description
=
_
(
"The GNU Talk Filters are filter programs that convert ordinary "
"English text into text that mimics a stereotyped or otherwise "
"humorous dialect. These filters have been in the public domain for "
"many years, and have been made available as a single integrated "
"package. The filters include austro, b1ff, brooklyn, chef, cockney, "
"drawl, dubya, fudd, funetak, jethro, jive, kraut, pansy, pirate, "
"postmodern, redneck, valspeak, and warez."
);
}
PURPLE_INIT_PLUGIN
(
talkfilters
,
init_plugin
,
talkfilters_info
)