--- 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