mirror of
https://github.com/moparisthebest/hexchat
synced 2024-11-28 04:02:16 -05:00
Create ZNC plugin
This commit is contained in:
parent
2aa3eb8cfb
commit
08ce54bbb5
22
configure.ac
22
configure.ac
@ -123,6 +123,10 @@ AC_ARG_ENABLE(doat,
|
||||
[AS_HELP_STRING([--disable-doat],[disable the Do At plugin])],
|
||||
doat=$enableval, doat=yes)
|
||||
|
||||
AC_ARG_ENABLE(znc,
|
||||
[AS_HELP_STRING([--disable-znc],[disable the ZNC plugin])],
|
||||
znc=$enableval, znc=yes)
|
||||
|
||||
AC_ARG_ENABLE(fishlim,
|
||||
[AS_HELP_STRING([--disable-fishlim],[disable the FiSHLiM plugin])],
|
||||
fishlim=$enableval, fishlim=yes)
|
||||
@ -478,6 +482,21 @@ if test "$doat" != "no"; then
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl *********************************************************************
|
||||
dnl ** ZNC **************************************************************
|
||||
dnl *********************************************************************
|
||||
|
||||
if test "$znc" != "no"; then
|
||||
AC_MSG_CHECKING(for plugin interface used by ZNC)
|
||||
znc=no
|
||||
if test "$plugin" = yes; then
|
||||
znc=yes
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([plugins are disabled, use the --enable-plugin option for ZNC])
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl *********************************************************************
|
||||
dnl ** FiSHLiM **********************************************************
|
||||
dnl *********************************************************************
|
||||
@ -599,6 +618,7 @@ AM_CONDITIONAL(DO_PYTHON, test "x$python" != "xno")
|
||||
AM_CONDITIONAL(DO_PLUGIN, test "x$plugin" = "xyes")
|
||||
AM_CONDITIONAL(DO_CHECKSUM, test "x$checksum" = "xyes")
|
||||
AM_CONDITIONAL(DO_DOAT, test "x$doat" = "xyes")
|
||||
AM_CONDITIONAL(DO_ZNC, test "x$znc" = "xyes")
|
||||
AM_CONDITIONAL(DO_FISHLIM, test "x$fishlim" = "xyes")
|
||||
AM_CONDITIONAL(DO_SYSINFO, test "x$sysinfo" = "xyes")
|
||||
AM_CONDITIONAL(USE_DBUS, test "x$dbus" = "xyes")
|
||||
@ -836,6 +856,7 @@ plugins/python/Makefile
|
||||
plugins/perl/Makefile
|
||||
plugins/checksum/Makefile
|
||||
plugins/doat/Makefile
|
||||
plugins/znc/Makefile
|
||||
plugins/fishlim/Makefile
|
||||
plugins/sysinfo/Makefile
|
||||
po/Makefile.in
|
||||
@ -864,6 +885,7 @@ echo Python ................ : $python
|
||||
echo
|
||||
echo Checksum .............. : $checksum
|
||||
echo Do At ................. : $doat
|
||||
echo ZNC Extras ............ : $znc
|
||||
echo FiSHLiM ............... : $fishlim
|
||||
echo SysInfo ............... : $sysinfo
|
||||
echo
|
||||
|
@ -10,6 +10,10 @@ if DO_DOAT
|
||||
doatdir = doat
|
||||
endif
|
||||
|
||||
if DO_ZNC
|
||||
zncdir = znc
|
||||
endif
|
||||
|
||||
if DO_FISHLIM
|
||||
fishlimdir = fishlim
|
||||
endif
|
||||
@ -22,4 +26,4 @@ if DO_SYSINFO
|
||||
sysinfodir = sysinfo
|
||||
endif
|
||||
|
||||
SUBDIRS = $(pythondir) $(perldir) $(checksumdir) $(doatdir) $(fishlimdir) $(sysinfodir)
|
||||
SUBDIRS = $(pythondir) $(perldir) $(checksumdir) $(doatdir) $(fishlimdir) $(sysinfodir) $(zncdir)
|
||||
|
7
plugins/znc/Makefile.am
Normal file
7
plugins/znc/Makefile.am
Normal file
@ -0,0 +1,7 @@
|
||||
libdir = $(hexchatlibdir)
|
||||
|
||||
lib_LTLIBRARIES = znc.la
|
||||
znc_la_SOURCES = znc.c
|
||||
znc_la_LDFLAGS = -avoid-version -module
|
||||
znc_la_LIBADD =
|
||||
AM_CPPFLAGS = $(COMMON_CFLAGS) -I$(srcdir)/../../src/common
|
387
plugins/znc/znc.c
Normal file
387
plugins/znc/znc.c
Normal file
@ -0,0 +1,387 @@
|
||||
/* HexChat
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <glib.h>
|
||||
#include "hexchat-plugin.h"
|
||||
|
||||
static hexchat_plugin *ph;
|
||||
static char name[] = "ZNC Extras";
|
||||
static char desc[] = "Integrate with optional ZNC plugins";
|
||||
static char version[] = "1.0";
|
||||
|
||||
|
||||
/* Playback: http://wiki.znc.in/Playback */
|
||||
|
||||
/* This should behave like this:
|
||||
* On connect (end of MOTD):
|
||||
* if new server, play all
|
||||
* if old server, play all after latest timestamp
|
||||
* On new query:
|
||||
* play all
|
||||
* On close query:
|
||||
* clear all
|
||||
* On new message:
|
||||
* update latest timestamp
|
||||
*/
|
||||
|
||||
static GHashTable *playback_servers = NULL;
|
||||
|
||||
#define PLAYBACK_CAP "znc.in/playback"
|
||||
|
||||
static int
|
||||
get_current_context_type (void)
|
||||
{
|
||||
int type = 0;
|
||||
hexchat_list *list;
|
||||
hexchat_context *cur_ctx;
|
||||
|
||||
list = hexchat_list_get (ph, "channels");
|
||||
if (!list)
|
||||
return 0;
|
||||
|
||||
cur_ctx = hexchat_get_context (ph);
|
||||
|
||||
while (hexchat_list_next (ph, list))
|
||||
{
|
||||
if ((hexchat_context*)hexchat_list_str (ph, list, "context") == cur_ctx)
|
||||
{
|
||||
type = hexchat_list_int (ph, list, "type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hexchat_list_free (ph, list);
|
||||
return type;
|
||||
}
|
||||
|
||||
static int
|
||||
get_current_context_id (void)
|
||||
{
|
||||
gint id;
|
||||
|
||||
if (hexchat_get_prefs (ph, "id", NULL, &id) != 2)
|
||||
return -1;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static int
|
||||
capls_cb (char *word[], void *userdata)
|
||||
{
|
||||
if (strstr (word[2], PLAYBACK_CAP) != NULL)
|
||||
hexchat_command (ph, "quote CAP REQ :" PLAYBACK_CAP);
|
||||
|
||||
return HEXCHAT_EAT_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
capack_cb (char *word[], void *userdata)
|
||||
{
|
||||
if (strstr (word[2], PLAYBACK_CAP) != NULL)
|
||||
{
|
||||
int id;
|
||||
|
||||
/* FIXME: emit this after request but before ack.. */
|
||||
hexchat_emit_print (ph, "Capability Request", PLAYBACK_CAP, NULL);
|
||||
|
||||
id = get_current_context_id ();
|
||||
if (!g_hash_table_contains (playback_servers, GINT_TO_POINTER(id)))
|
||||
g_hash_table_insert (playback_servers, GINT_TO_POINTER(id), g_strdup ("0"));
|
||||
}
|
||||
|
||||
return HEXCHAT_EAT_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
connected_cb (char *word[], char *word_eol[], void *userdata)
|
||||
{
|
||||
int id = get_current_context_id ();
|
||||
if (g_hash_table_contains (playback_servers, GINT_TO_POINTER(id)))
|
||||
{
|
||||
g_print("connected\n");
|
||||
char *timestamp = g_hash_table_lookup (playback_servers, GINT_TO_POINTER(id));
|
||||
hexchat_commandf (ph, "quote PRIVMSG *playback :play * %s", timestamp);
|
||||
}
|
||||
|
||||
return HEXCHAT_EAT_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
opencontext_cb (char *word[], void *userdata)
|
||||
{
|
||||
#if 0
|
||||
int id = get_current_context_id ();
|
||||
if (g_hash_table_contains (playback_servers, GINT_TO_POINTER(id))
|
||||
&& get_current_context_type () == 3)
|
||||
{
|
||||
const char *channel = hexchat_get_info (ph, "channel");
|
||||
char *time_str = g_hash_table_lookup (playback_servers, GINT_TO_POINTER(id));
|
||||
hexchat_commandf (ph, "quote PRIVMSG *playback :play %s %s", channel, time_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
return HEXCHAT_EAT_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
closecontext_cb (char *word[], void *userdata)
|
||||
{
|
||||
int id = get_current_context_id ();
|
||||
if (g_hash_table_contains (playback_servers, GINT_TO_POINTER(id)))
|
||||
{
|
||||
int type = get_current_context_type ();
|
||||
if (type == 3) /* Dialog */
|
||||
{
|
||||
const char *channel = hexchat_get_info (ph, "channel");
|
||||
hexchat_commandf (ph, "quote PRIVMSG *playback :clear %s", channel);
|
||||
}
|
||||
else if (type == 1) /* Server */
|
||||
{
|
||||
g_hash_table_remove (playback_servers, GINT_TO_POINTER(id));
|
||||
}
|
||||
}
|
||||
|
||||
return HEXCHAT_EAT_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
chanactivity_cb (char *word[], char *word_eol[], hexchat_event_attrs *attrs, void *userdata)
|
||||
{
|
||||
int id;
|
||||
|
||||
if (!attrs->server_time_utc)
|
||||
return HEXCHAT_EAT_NONE;
|
||||
|
||||
id = get_current_context_id ();
|
||||
if (g_hash_table_contains (playback_servers, GINT_TO_POINTER(id)))
|
||||
{
|
||||
char *time_str;
|
||||
|
||||
time_str = g_strdup_printf ("%ld", attrs->server_time_utc);
|
||||
g_hash_table_replace (playback_servers, GINT_TO_POINTER(id), time_str);
|
||||
}
|
||||
|
||||
return HEXCHAT_EAT_NONE;
|
||||
}
|
||||
|
||||
/* End Playback */
|
||||
|
||||
|
||||
/* Buffextras: http://wiki.znc.in/Buffextras */
|
||||
|
||||
static inline char *
|
||||
strip_brackets (char *str)
|
||||
{
|
||||
str++;
|
||||
str[strlen(str) - 1] = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
static int
|
||||
buffextras_cb (char *word[], char *word_eol[], hexchat_event_attrs *attrs, void *userdata)
|
||||
{
|
||||
char *channel, *user_nick, *user_host = NULL, *p;
|
||||
|
||||
if (g_ascii_strncasecmp (word[1] + 1, "*buffextras", 11) != 0)
|
||||
return HEXCHAT_EAT_NONE;
|
||||
|
||||
channel = word[3];
|
||||
user_nick = word[4] + 1;
|
||||
p = strchr (user_nick, '!');
|
||||
if (p != NULL)
|
||||
{
|
||||
*p = '\0';
|
||||
user_host = p + 1;
|
||||
}
|
||||
|
||||
/* This might be gross, but there are a lot of repeated calls.. */
|
||||
#define EMIT(x,...) hexchat_emit_print_attrs(ph,attrs,x,__VA_ARGS__,NULL)
|
||||
#define IS_EVENT(x) g_str_has_prefix(word_eol[5],x)
|
||||
|
||||
if (IS_EVENT ("joined"))
|
||||
{
|
||||
EMIT ("Join", user_nick, channel, user_host);
|
||||
}
|
||||
else if (IS_EVENT ("quit with message"))
|
||||
{
|
||||
EMIT ("Quit", user_nick, strip_brackets(word_eol[7]), user_host);
|
||||
}
|
||||
else if (IS_EVENT ("parted with message"))
|
||||
{
|
||||
char *reason = strip_brackets(word_eol[7]);
|
||||
|
||||
if (*reason)
|
||||
EMIT ("Part with Reason", user_nick, user_host, channel, reason);
|
||||
else
|
||||
EMIT ("Part", user_nick, user_host, channel);
|
||||
}
|
||||
else if (IS_EVENT ("is now known as"))
|
||||
{
|
||||
EMIT ("Change Nick", user_nick, word[9]);
|
||||
}
|
||||
else if (IS_EVENT ("set mode"))
|
||||
{
|
||||
char *prefix = (word[7][0] == '+' ? "+" : "-");
|
||||
|
||||
EMIT ("Channel Mode Generic", user_nick, prefix, word[7] + 1, channel);
|
||||
}
|
||||
else if (IS_EVENT ("changed the topic to"))
|
||||
{
|
||||
EMIT ("Topic Change", user_nick, word_eol[9], channel);
|
||||
}
|
||||
else if (IS_EVENT ("kicked")) /* X Reason: [Y] */
|
||||
{
|
||||
EMIT ("Kick", user_nick, word[6], channel, strip_brackets(word_eol[8]));
|
||||
}
|
||||
else
|
||||
{
|
||||
return HEXCHAT_EAT_NONE; /* We don't know, let it print */
|
||||
}
|
||||
|
||||
return HEXCHAT_EAT_ALL;
|
||||
}
|
||||
|
||||
/* End Buffextras */
|
||||
|
||||
|
||||
/* Privmsg: http://wiki.znc.in/Privmsg */
|
||||
|
||||
static gboolean
|
||||
prefix_is_channel (char prefix)
|
||||
{
|
||||
gboolean is_channel = TRUE; /* Defaults to TRUE as being wrong would be annoying */
|
||||
int id;
|
||||
hexchat_list *list;
|
||||
|
||||
if (hexchat_get_prefs (ph, "id", NULL, &id) != 2)
|
||||
return TRUE;
|
||||
|
||||
list = hexchat_list_get (ph, "channels");
|
||||
if (!list)
|
||||
return TRUE;
|
||||
|
||||
|
||||
while (hexchat_list_next (ph, list))
|
||||
{
|
||||
if (hexchat_list_int (ph, list, "id") == id)
|
||||
{
|
||||
const char *chantypes = hexchat_list_str (ph, list, "chantypes");
|
||||
if (strchr (chantypes, prefix) == NULL)
|
||||
is_channel = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hexchat_list_free (ph, list);
|
||||
return is_channel;
|
||||
}
|
||||
|
||||
static int
|
||||
privmsg_cb (char *word[], char *word_eol[], hexchat_event_attrs *attrs, void *userdata)
|
||||
{
|
||||
char *sender, *recipient, *msg, *p;
|
||||
const char *network, *mynick;
|
||||
|
||||
if (prefix_is_channel (word[3][0]))
|
||||
return HEXCHAT_EAT_NONE;
|
||||
|
||||
mynick = hexchat_get_info (ph, "nick");
|
||||
network = hexchat_get_info (ph, "network");
|
||||
recipient = word[3];
|
||||
msg = word_eol[4] + 1;
|
||||
sender = word[1] + 1;
|
||||
|
||||
p = strchr (sender, '!');
|
||||
if (p != NULL)
|
||||
*p = '\0';
|
||||
|
||||
if (hexchat_nickcmp (ph, sender, mynick) == 0
|
||||
&& hexchat_nickcmp (ph, recipient, mynick) != 0)
|
||||
{
|
||||
hexchat_context *new_ctx;
|
||||
char *event;
|
||||
|
||||
hexchat_commandf (ph, "query -nofocus %s", recipient);
|
||||
new_ctx = hexchat_find_context (ph, network, recipient);
|
||||
hexchat_set_context (ph, new_ctx);
|
||||
|
||||
if (g_ascii_strncasecmp (msg, "\001ACTION", 7) == 0)
|
||||
{
|
||||
msg += 7;
|
||||
msg[strlen (msg) - 1] = '\0';
|
||||
msg = g_strstrip (msg);
|
||||
event = "Your Action";
|
||||
}
|
||||
else
|
||||
{
|
||||
event = "Your Message";
|
||||
}
|
||||
|
||||
hexchat_emit_print_attrs (ph, attrs, event, mynick, msg, NULL);
|
||||
return HEXCHAT_EAT_ALL;
|
||||
}
|
||||
|
||||
return HEXCHAT_EAT_NONE;
|
||||
}
|
||||
|
||||
/* End Privmsg */
|
||||
|
||||
|
||||
int
|
||||
hexchat_plugin_init (hexchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc,
|
||||
char **plugin_version, char *arg)
|
||||
{
|
||||
ph = plugin_handle;
|
||||
*plugin_name = name;
|
||||
*plugin_desc = desc;
|
||||
*plugin_version = version;
|
||||
|
||||
/* Privmsg */
|
||||
hexchat_hook_server_attrs (ph, "PRIVMSG", HEXCHAT_PRI_HIGH, privmsg_cb, NULL);
|
||||
|
||||
/* Buffextras */
|
||||
hexchat_hook_server_attrs (ph, "PRIVMSG", HEXCHAT_PRI_HIGHEST, buffextras_cb, NULL);
|
||||
|
||||
/* Playback */
|
||||
playback_servers = g_hash_table_new_full (NULL, NULL, NULL, g_free);
|
||||
|
||||
hexchat_hook_print (ph, "Capability List", HEXCHAT_PRI_NORM, capls_cb, NULL);
|
||||
hexchat_hook_print (ph, "Capability Acknowledgement", HEXCHAT_PRI_NORM, capack_cb, NULL);
|
||||
hexchat_hook_print (ph, "Open Context", HEXCHAT_PRI_NORM, opencontext_cb, NULL);
|
||||
hexchat_hook_print (ph, "Close Context", HEXCHAT_PRI_NORM, closecontext_cb, NULL);
|
||||
hexchat_hook_server (ph, "376", HEXCHAT_PRI_NORM, connected_cb, NULL);
|
||||
|
||||
/* FIXME: Events buffextras uses */
|
||||
hexchat_hook_server_attrs (ph, "PRIVMSG", HEXCHAT_PRI_LOW, chanactivity_cb, NULL);
|
||||
|
||||
hexchat_printf (ph, "%s plugin loaded\n", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
hexchat_plugin_deinit (void)
|
||||
{
|
||||
g_hash_table_unref (playback_servers);
|
||||
hexchat_printf (ph, "%s plugin unloaded\n", name);
|
||||
return 1;
|
||||
}
|
Loading…
Reference in New Issue
Block a user