Last active
August 29, 2015 13:56
-
-
Save nattster/9287482 to your computer and use it in GitHub Desktop.
anti-msn-spam
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Anti MSN Spam plugin (for pidgin) | |
Author: Natt Piyapramote <nattster at googlemail dot com> | |
modified from message-filter.c written by Huy Phan <dachuy@gmail.com> | |
*/ | |
#ifdef HAVE_CONFIG_H | |
# include <config.h> | |
#endif | |
#ifndef PURPLE_PLUGINS | |
# define PURPLE_PLUGINS | |
#endif | |
#include <glib.h> | |
#include "debug.h" | |
#include "internal.h" | |
#include "plugin.h" | |
#include "pluginpref.h" | |
#include "prefs.h" | |
#include "version.h" | |
#define PLUGIN_ID "core-nattster-anti_msn_spam" | |
typedef struct { | |
GTimeVal timestamp; // timestamp of last message received | |
gint num_msg; // number of normal messages (i.e. message with no URL) | |
} HVal; | |
static GHashTable* msg_hash; | |
static int spam_blocked = 0; | |
static PurplePluginPrefFrame * | |
get_plugin_pref_frame(PurplePlugin *plugin) { | |
PurplePluginPrefFrame *frame; | |
PurplePluginPref *ppref; | |
frame = purple_plugin_pref_frame_new(); | |
ppref = purple_plugin_pref_new_with_name_and_label("/plugins/core/anti_msn_spam/spam_blocked", | |
_("Spams blocked")); | |
purple_plugin_pref_frame_add(frame, ppref); | |
return frame; | |
} | |
static gboolean | |
receiving_im_msg_cb(PurpleAccount *account, char **sender, char **buffer, | |
PurpleConversation *conv, PurpleMessageFlags *flags, void *data) | |
{ | |
HVal* val; | |
gchar* sender_dup; | |
GTimeVal now; | |
gint normal_msg = 1; | |
// test if incoming message contain URL? | |
if(g_regex_match_simple(".*(http://|www).*", *buffer, G_REGEX_CASELESS, G_REGEX_MATCH_NOTEMPTY)) | |
{ | |
normal_msg = 0; | |
} else if(g_strrstr(*buffer, "has nudged you!")) // nudge? | |
{ | |
return TRUE; // reject it and don't count it as normal msg | |
} | |
// get hash table HVal of sender | |
val = g_hash_table_lookup(msg_hash, *sender); | |
if(val == NULL) | |
{ | |
sender_dup = g_strdup(*sender); | |
val = g_new(HVal, 1); | |
val->num_msg = 0; | |
g_hash_table_insert(msg_hash, sender_dup, val); | |
} | |
// update num_msg and timestamp | |
if(normal_msg) | |
{ | |
val->num_msg++; | |
g_get_current_time(&(val->timestamp)); | |
} else { | |
g_get_current_time(&now); | |
if(val->num_msg == 0 || now.tv_sec - val->timestamp.tv_sec > 3600) | |
{ | |
purple_debug_info(PLUGIN_ID, "caught SPAM from %s - %s\n", *sender, *buffer); | |
spam_blocked++; | |
return TRUE; // reject the message | |
} | |
} | |
return FALSE; // accept it | |
} | |
static gboolean | |
plugin_load(PurplePlugin *plugin) | |
{ | |
void *conv_handle = purple_conversations_get_handle(); | |
spam_blocked = purple_prefs_get_int("/plugins/core/anti_msn_spam/spam_blocked"); | |
msg_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
purple_signal_connect(conv_handle, "receiving-im-msg", plugin, PURPLE_CALLBACK(receiving_im_msg_cb), NULL); | |
return TRUE; | |
} | |
static gboolean | |
plugin_unload(PurplePlugin *plugin) | |
{ | |
purple_debug_info(PLUGIN_ID, "unloading...\n"); | |
purple_prefs_set_int("/plugins/core/anti_msn_spam/spam_blocked", spam_blocked); | |
g_hash_table_destroy(msg_hash); | |
return TRUE; | |
} | |
static PurplePluginUiInfo prefs_info = { | |
get_plugin_pref_frame, | |
0, /* page_num (Reserved) */ | |
NULL, /* frame (Reserved) */ | |
/* Padding */ | |
NULL, | |
NULL, | |
NULL, | |
NULL | |
}; | |
static PurplePluginInfo info = { | |
PURPLE_PLUGIN_MAGIC, /* Plugin magic, this must always be | |
PURPLE_PLUGIN_MAGIC.*/ | |
PURPLE_MAJOR_VERSION, /* This is also defined in libpurple. It helps | |
libpurple's plugin system determine which version | |
of libpurple this plugin was compiled for, and | |
whether loading it will cause problems. */ | |
PURPLE_MINOR_VERSION, /* See previous */ | |
PURPLE_PLUGIN_STANDARD, /* PurplePluginType: There are 4 different values for | |
this field. The first is PURPLE_PLUGIN_UNKNOWN, | |
which should not be used. The second is | |
PURPLE_PLUGIN_STANDARD; this is the value most | |
plugins will use. Next, we have PURPLE_PLUGIN_LOADER; | |
this is the type you want to use if your plugin will | |
make it possible to load non-native plugins. For | |
example, the Perl and Tcl loader plugins are of this | |
type. Last, we have PURPLE_PLUGIN_PROTOCOL. If your | |
plugin is going to allow the user to connect to | |
another network, this is the type you'd want to use. */ | |
NULL, /* This field is the UI requirement. If you're writing | |
a core plugin, this must be NULL and the plugin must | |
not contain any UI code. If you're writing a Pidgin | |
plugin, you need to use PIDGIN_PLUGIN_TYPE. If you | |
are writing a Finch plugin, you would use | |
FINCH_PLUGIN_TYPE.*/ | |
0, /* This field is for plugin flags. Currently, the only | |
flag available to plugins is invisible | |
(PURPLE_PLUGIN_FLAG_INVISIBLE). It causes the plugin | |
NOT to appear in the list of plugins. */ | |
NULL, /* This is a GList of plugin dependencies. In other words, | |
it's a GList of plugin id's that your plugin depends on. | |
Set this value to NULL no matter what. If your plugin | |
has dependencies, set them at run-time in the | |
plugin_init function. */ | |
PURPLE_PRIORITY_DEFAULT,/* This is the priority libpurple will give your plugin. | |
There are three possible values for this field, | |
PURPLE_PRIORITY_DEFAULT, PURPLE_PRIORITY_HIGHEST, and | |
PURPLE_PRIORITY_LOWEST. */ | |
PLUGIN_ID, /* This is your plugin's id. There is a whole page dedicated | |
to this in the Related Pages section of the API docs. */ | |
"Anti MSN Spam", /* This is your plugin's name. This is what will be | |
displayed for your plugin in the UI. */ | |
"1.0", /* This is the version of your plugin. */ | |
"MSN spam filter", /* This is the summary of your plugin. It should be a short | |
blurb. The UI determines where, if at all, to display | |
this. */ | |
"MSN spam filter, check for unwanted SPAM messages and block them", /* This is the description of your plugin. It can be as long | |
and as descriptive as you like. And like the summary, | |
it's up to the UI where, if at all, to display this (and | |
how much to display). */ | |
"Natt Piyapramote <nattster@googlemail.com>", /* This is where you can put your name and e-mail | |
address. */ | |
"http://nattster.siamdev.net",/* This is the website for the plugin. This tells users | |
where to find new versions, report bugs, etc. */ | |
plugin_load, /* This is a pointer to a function for libpurple to call when | |
it is loading the plugin. It should be of the type: | |
gboolean plugin_load(PurplePlugin *plugin) | |
Returning FALSE will stop the loading of the plugin. | |
Anything else would evaluate as TRUE and the plugin will | |
continue to load. */ | |
plugin_unload, /* Same as above except it is called when libpurple tries to | |
unload your plugin. It should be of the type: | |
gboolean plugin_unload(PurplePlugin *plugin) | |
Returning TRUE will tell libpurple to continue unloading | |
while FALSE will stop the unloading of your plugin. */ | |
NULL, /* Similar to the two above members, except this is called | |
when libpurple tries to destory the plugin. This is | |
generally only called when for some reason or another the | |
plugin fails to probe correctly. It should be of the type: | |
void plugin_destroy(PurplePlugin *plugin) */ | |
NULL, /* This is a pointer to a UI-specific struct. For a Pidgin | |
plugin it will be a pointer to a PidginPluginUiInfo | |
struct, for example. */ | |
NULL, /* This is a pointer to either a PurplePluginLoaderInfo | |
struct or a PurplePluginProtocolInfo struct, and is | |
beyond the scope of this document. */ | |
&prefs_info, /* This is a pointer to a PurplePluginUiInfo struct. It is | |
a core/ui split way for core plugins to have a UI | |
configuration frame. You can find an example of this | |
code in libpurple/plugins/pluginpref_example.c */ | |
NULL, /* This is a function pointer where you can define "plugin | |
actions". The UI controls how they're displayed. It | |
should be of the type: | |
GList *function_name(PurplePlugin *plugin, | |
gpointer context) | |
It must return a GList of PurplePluginActions. */ | |
NULL, | |
NULL, | |
NULL, | |
NULL | |
}; | |
static void | |
init_plugin(PurplePlugin *plugin) | |
{ | |
purple_prefs_add_none("/plugins/core/anti_msn_spam"); | |
purple_prefs_add_int("/plugins/core/anti_msn_spam/spam_blocked", 0); | |
} | |
PURPLE_INIT_PLUGIN(anti_msn_spam, init_plugin, info) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
Anti MSN Spam for Pidgin | |
version 1.0 | |
by Natt Piyapramote <nattster at gmail dot com> | |
-------------------------------------------------------------- | |
How it works? | |
it will classify all messages received into 2 categories. | |
1. IM that contains URL | |
2. Normal IM | |
This script will count number of Normal IM for each user in your contact list. | |
If someone that didn't send you any "Normal IM", but send you an "IM that contains URL" as a first message. Then, this IM is most likely to be a SPAM. This software will reject. | |
""" | |
# Anti MSN spam for pidgin | |
import time | |
import re | |
url_re = re.compile('.*(http://|www.).*') | |
purple = None | |
last_normal = {} # timestamp of last Normal IMs | |
num_normal = {} # number of Normal IMs | |
def receiving_msg(account, sender, message, conversation, flags): | |
"Receiving message handler" | |
global purple, last_normal, num_normal, url_re | |
# Initialize or reset last_normal, num_normal values | |
if not last_normal.has_key(sender): | |
last_normal[sender] = 0 | |
if not num_normal.has_key(sender) or time.time() - last_normal[sender] > 3600: | |
num_normal[sender] = 0 | |
# test if message contains URL | |
m = message.replace("\n", "").replace("\r", "") | |
if url_re.match(m): | |
# it's an URL message | |
if num_normal[sender] == 0: | |
# if first message contains URL, it's most likely to be a SPAM | |
purple.PurpleConversationDestroy(conversation) | |
print 'message ', message, ' from ', sender, ' canceled' | |
else: | |
# it's a normal message | |
num_normal[sender] += 1 | |
last_normal[sender] = time.time() | |
import dbus, gobject | |
from dbus.mainloop.glib import DBusGMainLoop | |
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) | |
bus = dbus.SessionBus() | |
obj = bus.get_object("im.pidgin.purple.PurpleService", "/im/pidgin/purple/PurpleObject") | |
purple = dbus.Interface(obj, "im.pidgin.purple.PurpleInterface") | |
bus.add_signal_receiver(receiving_msg, | |
dbus_interface="im.pidgin.purple.PurpleInterface", | |
signal_name="DisplayingImMsg") | |
loop = gobject.MainLoop() | |
loop.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment