implement logwatch_on_line/logwatch_filter_apply, along with irc_*_NOTICE
authorTero Marttila <terom@fixme.fi>
Sat, 11 Apr 2009 04:26:46 +0300
changeset 127 94e6c3b4230f
parent 126 8065a624ba37
child 128 6c5a5fdfd1d5
implement logwatch_on_line/logwatch_filter_apply, along with irc_*_NOTICE
src/error.h
src/irc_chan.c
src/irc_chan.h
src/irc_conn.c
src/irc_conn.h
src/modules/logwatch.c
src/modules/logwatch.h
src/modules/logwatch_filter.c
src/modules/logwatch_source.c
--- a/src/error.h	Sat Apr 11 04:26:22 2009 +0300
+++ b/src/error.h	Sat Apr 11 04:26:46 2009 +0300
@@ -111,6 +111,7 @@
     /** pcre errors */
     _ERR_PCRE       = 0x000e00,
     ERR_PCRE_COMPILE,       ///< pcre_compile: <error_msg>
+    ERR_PCRE_EXEC,          ///< pcre_exec: <error code>
 
     /** General errors */
     _ERR_GENERAL    = 0xffff00,
--- a/src/irc_chan.c	Sat Apr 11 04:26:22 2009 +0300
+++ b/src/irc_chan.c	Sat Apr 11 04:26:46 2009 +0300
@@ -392,3 +392,15 @@
     return irc_conn_PRIVMSG(chan->net->conn, chan->info.channel, message);
 }
 
+err_t irc_chan_NOTICE (struct irc_chan *chan, const char *message)
+{
+    // correct state 
+    if (!chan->joined)
+        return ERR_IRC_CHAN_STATE;
+
+    if (!chan->net->conn)
+        return ERR_IRC_NET_STATE;
+
+    // send the PRIVMSG message
+    return irc_conn_NOTICE(chan->net->conn, chan->info.channel, message);
+}
--- a/src/irc_chan.h	Sat Apr 11 04:26:22 2009 +0300
+++ b/src/irc_chan.h	Sat Apr 11 04:26:46 2009 +0300
@@ -181,4 +181,12 @@
  */
 err_t irc_chan_PRIVMSG (struct irc_chan *chan, const char *message);
 
+/**
+ * Send a NOTICE message to the channel.
+ *
+ * @param chan the IRC channel
+ * @param message the message to send
+ */
+err_t irc_chan_NOTICE (struct irc_chan *chan, const char *message);
+
 #endif
--- a/src/irc_conn.c	Sat Apr 11 04:26:22 2009 +0300
+++ b/src/irc_conn.c	Sat Apr 11 04:26:46 2009 +0300
@@ -388,6 +388,16 @@
     return irc_conn_send(conn, &line);
 }
 
+err_t irc_conn_NOTICE (struct irc_conn *conn, const char *target, const char *message)
+{
+    // NOTICE <msgtarget> <message>
+    struct irc_line line = {
+        NULL, "NOTICE", { target, message }
+    };
+
+    return irc_conn_send(conn, &line);
+}
+
 err_t irc_conn_QUIT (struct irc_conn *conn, const char *message)
 {
     err_t err;
--- a/src/irc_conn.h	Sat Apr 11 04:26:22 2009 +0300
+++ b/src/irc_conn.h	Sat Apr 11 04:26:46 2009 +0300
@@ -318,6 +318,23 @@
 err_t irc_conn_PRIVMSG (struct irc_conn *conn, const char *target, const char *message);
 
 /**
+ * Send a NOTICE messaeg to some target, usually a channel or another user (nickname).
+ *
+ * The same limitations on message length and data apply as for irc_conn_PRIVMSG.
+ *
+ * The only difference between PRIVMSG and NOTICE is that NOTICE messages should never generate an automated reply,
+ * hence, they are used for e.g. CTCP replies, and ideally, for IRC bot output.
+ *
+ * @param conn the IRC protocol connection
+ * @param target the message target, usually either a channel name or a nickname
+ * @param message the message to send
+ *
+ * Possible errors (from RFC2812):
+ *  None. Servers do not ever reply to NOTICE messages.
+ */
+err_t irc_conn_NOTICE (struct irc_conn *conn, const char *target, const char *message);
+
+/**
  * Send a QUIT message to the server. The server will reply with an ERROR message and close the connection.
  *
  * This updates our state as disconnecting, and once EOF is recieved, the irc_conn_callbacks::on_quit callback is
--- a/src/modules/logwatch.c	Sat Apr 11 04:26:22 2009 +0300
+++ b/src/modules/logwatch.c	Sat Apr 11 04:26:46 2009 +0300
@@ -1,6 +1,7 @@
 #include "logwatch.h"
 
 #include "../config.h"
+#include "../log.h"
 
 static err_t logwatch_init (struct nexus *nexus, void **ctx_ptr, struct error_info *err)
 {
@@ -45,6 +46,18 @@
     return NULL;    
 }
 
+void logwatch_on_line (struct logwatch *ctx, const struct logwatch_source *source, const char *line)
+{
+    const struct logwatch_filter *filter;
+    struct error_info err;
+
+    // apply each filter
+    TAILQ_FOREACH(filter, &ctx->filters, logwatch_filters) {
+        if (logwatch_filter_apply(filter, source, line, &err))
+            log_warn("logwatch_filter_apply(%s, %p, %s): %s", filter->name, source, line, error_msg(&err));
+    }
+}
+
 /**
  * Add a logwatch_source with a FIFO at the given path
  */
@@ -112,7 +125,7 @@
  * Deinitialize by freeing all filters, closing all sources, and releasing all channels.
  *
  * XXX: unused
- */
+ * /
 static err_t logwatch_unload (void *_ctx, struct module *module)
 {
     struct logwatch *ctx = _ctx;
@@ -120,7 +133,7 @@
     // XXX: implement
 
     return SUCCESS;
-}
+} */
 
 static void logwatch_destroy (void *_ctx)
 {
--- a/src/modules/logwatch.h	Sat Apr 11 04:26:22 2009 +0300
+++ b/src/modules/logwatch.h	Sat Apr 11 04:26:46 2009 +0300
@@ -65,6 +65,16 @@
 };
 
 /**
+ * Maximum number of capture groups in the filter's regexp
+ */
+#define LOGWATCH_FILTER_GROUPS_MAX 16
+
+/**
+ * Maximum length of output string, not including NUL byte
+ */
+#define LOGWATCH_FILTER_OUT_MAX 450
+
+/**
  * A channel for outputting logwatch output
  *
  * XXX; do we need this?
@@ -129,3 +139,13 @@
  */
 void logwatch_filter_destroy (struct logwatch_filter *filter);
 
+/**
+ * Pass the given line (from the given source) through the given filter
+ */
+err_t logwatch_filter_apply (const struct logwatch_filter *filter, const struct logwatch_source *source, const char *line, struct error_info *err);
+
+/**
+ * Handle a line from the given source by applying it to all filters
+ */
+void logwatch_on_line (struct logwatch *ctx, const struct logwatch_source *source, const char *line);
+
--- a/src/modules/logwatch_filter.c	Sat Apr 11 04:26:22 2009 +0300
+++ b/src/modules/logwatch_filter.c	Sat Apr 11 04:26:46 2009 +0300
@@ -59,3 +59,59 @@
     free(filter->name);
     free(filter);
 }
+
+// number of pcre ovec elemnents required
+#define LOGWATCH_FILTER_OVEC_ITEMS ((LOGWATCH_FILTER_GROUPS_MAX + 1) * 3)
+
+err_t logwatch_filter_apply (const struct logwatch_filter *filter, const struct logwatch_source *source, const char *line, struct error_info *err)
+{
+    int ovec[LOGWATCH_FILTER_OVEC_ITEMS], ret;
+    char out_buf[LOGWATCH_FILTER_OUT_MAX + 1];
+
+    // XXX: prefix output with filter->name tag
+    // XXX: implement output formatting
+    // XXX: escape the output data
+    // XXX: what to do for truncated data?
+
+    // discard based on source?
+    if (filter->source && source != filter->source)
+        return SUCCESS;
+    
+    // match against the regexp
+    if ((ret = pcre_exec(filter->regexp, NULL, line, strlen(line), 0, 0, ovec, LOGWATCH_FILTER_OVEC_ITEMS)) <= 0) {
+        if (ret == PCRE_ERROR_NOMATCH)
+            // no match, ignore
+            return SUCCESS;
+
+        else if (ret == 0)
+            // too many match groups
+            return SET_ERROR(err, -1);
+
+        else
+            // misc. error
+            RETURN_SET_ERROR_EXTRA(err, ERR_PCRE_EXEC, ret);
+    }
+
+    // format?
+    if (filter->format) {
+        return SET_ERROR(err, -2);
+    
+    } else {
+        // copy the line directly
+        if (strlen(line) > LOGWATCH_FILTER_OUT_MAX)
+            return SET_ERROR(err, -3);
+
+        strcpy(out_buf, line);
+    }
+
+    // then send it as a notice
+    if ((ERROR_CODE(err) = irc_chan_NOTICE(filter->chan, out_buf)))
+        goto error;
+
+    // ok
+    return SUCCESS;
+
+error:
+    return ERROR_CODE(err);    
+}
+
--- a/src/modules/logwatch_source.c	Sat Apr 11 04:26:22 2009 +0300
+++ b/src/modules/logwatch_source.c	Sat Apr 11 04:26:46 2009 +0300
@@ -6,14 +6,18 @@
 void logwatch_source_on_line (char *line, void *arg)
 {
     struct logwatch_source *source = arg;
-
-    log_info("%s", line);
+    
+    // apply it to the logwatch's filters
+    logwatch_on_line(source->ctx, source, line);
 }
 
 void logwatch_source_on_error (struct error_info *err, void *arg)
 {
     struct logwatch_source *source = arg;
+
+    (void) source;
     
+    // XXX: complain more loudly
     log_error("%s", error_msg(err));
 }
 
@@ -27,6 +31,7 @@
  */
 err_t logwatch_source_init (struct logwatch_source *source, struct logwatch *ctx, struct sock_stream *stream, struct error_info *err)
 {
+    // store
     source->ctx = ctx;
     
     // create the lp to wrap the sock