--- /dev/null
+/*
+ rx.c - rxpd plugin for xchat
+
+ Copyright (C)
+ 2007, Christian Thaeter <ct@pipapo.org>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+//#include <sys/resource.h>
+#include <netinet/in.h>
+//#include <arpa/inet.h>
+//#include <fcntl.h>
+//#include <time.h>
+#include <netdb.h>
+#include <sys/uio.h>
+
+#include "xchat-plugin.h"
+
+#define PNAME "RxpdPlugin"
+#define PDESC "Uses rxpd to act on content";
+#define PVERSION "0.1"
+
+#define PREFIXCMP(str, pfx) (!strncmp (str, (pfx), sizeof (pfx)-1))
+
+static xchat_plugin *ph; /* plugin handle */
+
+static struct rx_plugin_data
+{
+ int debug;
+ const char* server;
+ const char* port;
+ const char* prefix;
+ const char* list;
+ int fd; /* the fd used for CHECK:list */
+ char* eol;
+ char* eob;
+ char buffer[4096];
+} rx_private;
+
+
+static char*
+buffer_readline (struct rx_plugin_data* self)
+{
+ ssize_t r;
+
+ if (self->eol < self->eob)
+ {
+ //there was a line pending, shift buffer left
+ memmove (self->buffer, self->eol+1, self->eob - self->eol - 1);
+ self->eob = (char*)(self->eob - (self->eol - self->buffer + 1));
+ self->eol = self->buffer;
+ // TODO handle \r's
+ }
+
+ do {
+ // find next newline, terminate string there
+ char* i;
+ for (i = self->buffer; i < self->eob; ++i)
+ {
+ if (*i == '\n')
+ {
+ *i = '\0';
+ self->eol = i;
+ // have line, return it
+ return (self->eob == self->buffer) ? NULL : self->buffer;
+ }
+ }
+
+ r = 0;
+ do
+ {
+ r = read (self->fd, self->eob, 4095 - (self->eob - self->buffer));
+ }
+ while (r == -1 && errno == EINTR);
+
+ if (r != -1)
+ self->eob += r;
+
+ } while (r != -1);
+
+ return NULL;
+}
+
+
+
+void
+xchat_plugin_get_info (char **name,
+ char **desc,
+ char **version,
+ void **reserved)
+{
+ *name = PNAME;
+ *desc = PDESC;
+ *version = PVERSION;
+}
+
+static int
+rxstart_cb (char *word[], char *word_eol[], void *userdata)
+{
+ // server port list; enables and connects to rxpd", &rx_private);
+ struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
+
+ rx->server = strdup (word[2]);
+ rx->port = strdup (word[3]);
+ rx->list = strdup (word[4]);
+
+ struct addrinfo* addrs = NULL;
+ int aierr;
+
+ /* resolve peer */
+ aierr = getaddrinfo (rx->server, rx->port, NULL, &addrs);
+ if (aierr)
+ {
+ xchat_printf (ph, "could not resolve %s:%s, %s\n", rx->server, rx->port, gai_strerror (aierr));
+ return XCHAT_EAT_ALL;
+ }
+
+ rx->fd = socket (addrs->ai_family, addrs->ai_socktype, addrs->ai_protocol);
+ if (rx->fd == -1 || connect (rx->fd, addrs->ai_addr, addrs->ai_addrlen))
+ {
+ freeaddrinfo (addrs);
+ xchat_printf (ph, "error connecting %s:%s, %s\n", rx->server, rx->port, strerror (errno));
+ return XCHAT_EAT_ALL;
+ }
+ freeaddrinfo (addrs);
+
+ struct iovec cmd[3] =
+ {
+ {"CHECK:", sizeof("CHECK:")-1},
+ {(void*)rx->list, strlen (rx->list)},
+ {"\n", 1}
+ };
+
+ ssize_t written = writev (rx->fd, cmd, 3);
+ if (written < cmd[0].iov_len + cmd[1].iov_len + cmd[2].iov_len)
+ {
+ xchat_printf (ph, "error writing check commmand\n");
+ close (rx->fd);
+ rx->fd = -1;
+ return XCHAT_EAT_ALL;
+ }
+
+ if (rx->debug)
+ xchat_printf (ph, "established rxpd connection to %s:%s\n", rx->server, rx->port);
+
+ return XCHAT_EAT_ALL;
+}
+
+static int
+rxstop_cb (char *word[], char *word_eol[], void *userdata)
+{
+ struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
+
+ if (rx->fd != -1)
+ {
+ close (rx->fd);
+ rx->fd = -1;
+ if (rx->debug)
+ xchat_printf (ph, "closed rxpd connection to %s:%s\n", rx->server, rx->port);
+ }
+ else
+ if (rx->debug)
+ xchat_printf (ph, "no rxpd connection established\n");
+
+ return XCHAT_EAT_ALL;
+}
+
+static int
+rxadd_cb (char *word[], char *word_eol[], void *userdata)
+{
+ //struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
+ return XCHAT_EAT_ALL; /* eat this command so xchat and other plugins can't process it */
+}
+
+static int
+rxdel_cb (char *word[], char *word_eol[], void *userdata)
+{
+ //struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
+ return XCHAT_EAT_ALL; /* eat this command so xchat and other plugins can't process it */
+}
+
+static int
+rxlist_cb (char *word[], char *word_eol[], void *userdata)
+{
+ //struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
+ return XCHAT_EAT_ALL; /* eat this command so xchat and other plugins can't process it */
+}
+
+static int
+rxraw_cb (char *word[], char *word_eol[], void *userdata)
+{
+ //struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
+ return XCHAT_EAT_ALL; /* eat this command so xchat and other plugins can't process it */
+}
+
+static int
+rxdebug_cb (char *word[], char *word_eol[], void *userdata)
+{
+ struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
+ rx->debug ^= 1;
+ xchat_printf (ph, "Turned rxpd debugging %s\n", rx->debug?"on":"off");
+ return XCHAT_EAT_ALL;
+}
+
+static int
+rxhook_cb (char *word[], char *word_eol[], void *userdata)
+{
+ struct rx_plugin_data* rx = (struct rx_plugin_data*)userdata;
+
+ if (rx->fd != -1)
+ {
+ /* ok do the checking*/
+
+ struct iovec check[2] =
+ {
+ {(void*)word_eol[1], strlen (word_eol[1])},
+ {"\n", 1}
+ };
+
+ ssize_t written = writev (rx->fd, check, 2);
+ if (written < check[0].iov_len + 1)
+ {
+ xchat_printf (ph, "RXPD: error writing\n");
+ close (rx->fd);
+ rx->fd = -1;
+ return XCHAT_EAT_NONE;
+ }
+
+ char* line = buffer_readline (rx);
+
+ if (rx->debug && !PREFIXCMP(line, "ok:"))
+ xchat_printf (ph, "RXPD: '%s'\n", line);
+
+ if (PREFIXCMP(line, "ignore:"))
+ return XCHAT_EAT_XCHAT;
+
+ //else if (PREFIXCMP(line, "kick:"))
+ //else if (PREFIXCMP(line, "kickban:"))
+ //else if (PREFIXCMP(line, "ban:"))
+ //else if (PREFIXCMP(line, "op:"))
+
+ }
+
+ return XCHAT_EAT_NONE;
+}
+
+int
+xchat_plugin_init(xchat_plugin *plugin_handle,
+ char **plugin_name,
+ char **plugin_desc,
+ char **plugin_version,
+ char *arg)
+{
+ /* we need to save this for use with any xchat_* functions */
+ ph = plugin_handle;
+
+ /* tell xchat our info */
+ *plugin_name = PNAME;
+ *plugin_desc = PDESC;
+ *plugin_version = PVERSION;
+
+ rx_private.debug = 0;
+ rx_private.server = NULL;
+ rx_private.port = NULL;
+ rx_private.list = NULL;
+ rx_private.fd = -1;
+ rx_private.eol = rx_private.eob = rx_private.buffer;
+ rx_private.buffer [4095] = '\0';
+
+ xchat_hook_command (ph, "RXSTART", XCHAT_PRI_NORM, rxstart_cb,
+ "Usage: RXSTART server port list; enables and connects to rxpd", &rx_private);
+
+ xchat_hook_command (ph, "RXSTOP", XCHAT_PRI_NORM, rxstop_cb,
+ "Usage: RXSTOP; disconnects and stops rxpd plugin", &rx_private);
+
+ xchat_hook_command (ph, "RXADD", XCHAT_PRI_NORM, rxadd_cb,
+ "Usage: RXADD listname rule; adds rule to list", &rx_private);
+
+ xchat_hook_command (ph, "RXDEL", XCHAT_PRI_NORM, rxdel_cb,
+ "Usage: RXDEL list rule; removes rule from list", &rx_private);
+
+ xchat_hook_command (ph, "RXLIST", XCHAT_PRI_NORM, rxlist_cb,
+ "Usage: RXLIST [list]; shows list", &rx_private);
+
+ xchat_hook_command (ph, "RXRAW", XCHAT_PRI_NORM, rxraw_cb,
+ "Usage: RXRAW ...; sends a raw command to the rxpd", &rx_private);
+
+ xchat_hook_command (ph, "RXDEBUG", XCHAT_PRI_NORM, rxdebug_cb,
+ "Usage: RXDEBUG; toggle rxpd plugin debugging", &rx_private);
+
+ xchat_hook_server (ph, "RAW LINE", XCHAT_PRI_NORM, rxhook_cb, &rx_private);
+
+ xchat_print (ph, "Rxpd plugin loaded successfully!\n");
+
+ return 1;
+}