summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile7
-rw-r--r--src/botserv.c9
-rw-r--r--src/chanserv.c7
-rw-r--r--src/events.c779
-rw-r--r--src/init.c3
-rw-r--r--src/main.c10
-rw-r--r--src/makefile.win3210
-rw-r--r--src/misc.c10
-rw-r--r--src/modules/events.c53
-rw-r--r--src/modules/makefile.inc.win322
-rw-r--r--src/nickserv.c4
-rw-r--r--src/process.c2
-rw-r--r--src/send.c2
-rw-r--r--src/users.c2
14 files changed, 890 insertions, 10 deletions
diff --git a/src/Makefile b/src/Makefile
index 1e576a74a..f1c6a4169 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -2,13 +2,13 @@ MYSQL_OBJ = $(MYSQL:.c=.o)
RDB_OBJ = $(RDB:.c=.o)
IRCD_OBJ = $(IRCDFILE:.c=.o)
OBJS = actions.o base64.o botserv.o channels.o chanserv.o commands.o compat.o converter.o \
- config.o datafiles.o encrypt.o helpserv.o hostserv.o init.o language.o list.o log.o mail.o main.o \
+ config.o datafiles.o encrypt.o events.o helpserv.o hostserv.o init.o language.o list.o log.o mail.o main.o \
memory.o memoserv.o messages.o misc.o modules.o news.o nickserv.o operserv.o \
process.o proxy.o send.o servers.o sessions.o slist.o sockutil.o \
timeout.o users.o \
$(VSNPRINTF_O) $(RDB_OBJ) $(MYSQL_OBJ) $(IRCD_OBJ)
SRCS = actions.c base64.c botserv.c channels.c chanserv.c commands.c compat.c converter.c \
- config.c datafiles.c encrypt.c helpserv.c hostserv.c init.c language.c list.c log.c mail.c main.c \
+ config.c datafiles.c encrypt.c events.c helpserv.c hostserv.c init.c language.c list.c log.c mail.c main.c \
memory.c memoserv.c messages.c misc.c modules.c news.c nickserv.c operserv.c \
process.c proxy.c send.c servers.c sessions.c slist.c sockutil.c \
timeout.c users.c \
@@ -54,6 +54,7 @@ config.o: config.c $(INCLUDES)
converter.o: converter.c $(INCLUDES)
datafiles.o: datafiles.c $(INCLUDES)
encrypt.o: encrypt.c $(INCLUDES)
+events.o: events.c $(INCLUDES)
init.o: init.c $(INCLUDES)
helpserv.o: helpserv.c $(INCLUDES)
hostserv.o: hostserv.c $(INCLUDES)
@@ -65,7 +66,7 @@ main.o: main.c $(INCLUDES)
memory.o: memory.c $(INCLUDES)
memoserv.o: memoserv.c $(INCLUDES)
messages.o: messages.c $(INCLUDES)
-modules.o: modules.c $(INCLUDES)
+modules.o: modules.c $(INCLUDES)
misc.o: misc.c $(INCLUDES)
news.o: news.c $(INCLUDES)
nickserv.o: nickserv.c $(INCLUDES)
diff --git a/src/botserv.c b/src/botserv.c
index 1931b8f6c..6cfae0989 100644
--- a/src/botserv.c
+++ b/src/botserv.c
@@ -849,6 +849,8 @@ BotInfo *findbot(char *nick)
static void unassign(User * u, ChannelInfo * ci)
{
+ send_event(EVENT_BOT_UNASSIGN, ci->name);
+
if (ci->c && ci->c->usercount >= BSMinUsers) {
anope_cmd_part(ci->bi->nick, ci->name, "UNASSIGN from %s",
u->nick);
@@ -995,6 +997,7 @@ void bot_join(ChannelInfo * ci)
}
anope_cmd_join(ci->bi->nick, ci->c->name, ci->c->creation_time);
anope_cmd_bot_chan_mode(ci->bi->nick, ci->c->name);
+ send_event(EVENT_BOT_JOIN, ci->name);
}
/*************************************************************************/
@@ -1353,6 +1356,8 @@ static int do_bot(User * u)
notice_lang(s_BotServ, u, BOT_BOT_ADDED, bi->nick, bi->user,
bi->host, bi->real);
+
+ send_event(EVENT_BOT_CREATE, bi->nick);
}
} else if (!stricmp(cmd, "CHANGE")) {
char *oldnick = strtok(NULL, " ");
@@ -1478,6 +1483,8 @@ static int do_bot(User * u)
notice_lang(s_BotServ, u, BOT_BOT_CHANGED, oldnick, bi->nick,
bi->user, bi->host, bi->real);
+
+ send_event(EVENT_BOT_CHANGE, bi->nick);
}
} else if (!stricmp(cmd, "DEL")) {
char *nick = strtok(NULL, " ");
@@ -1489,6 +1496,7 @@ static int do_bot(User * u)
else if (!(bi = findbot(nick)))
notice_lang(s_BotServ, u, BOT_DOES_NOT_EXIST, nick);
else {
+ send_event(EVENT_BOT_DEL, bi->nick);
anope_cmd_quit(bi->nick,
"Quit: Help! I'm being deleted by %s!",
u->nick);
@@ -1587,6 +1595,7 @@ static int do_assign(User * u)
bot_join(ci);
}
notice_lang(s_BotServ, u, BOT_ASSIGN_ASSIGNED, bi->nick, ci->name);
+ send_event(EVENT_BOT_ASSIGN, bi->nick);
}
return MOD_CONT;
}
diff --git a/src/chanserv.c b/src/chanserv.c
index ce8863133..30d794231 100644
--- a/src/chanserv.c
+++ b/src/chanserv.c
@@ -1740,6 +1740,7 @@ void record_topic(const char *chan)
ci->last_topic = NULL;
strscpy(ci->last_topic_setter, c->topic_setter, NICKMAX);
ci->last_topic_time = c->topic_time;
+ send_event(EVENT_TOPIC_UPDATED, chan);
}
/*************************************************************************/
@@ -1871,6 +1872,7 @@ void expire_chans()
next = ci->next;
if (!ci->c && now - ci->last_used >= CSExpire
&& !(ci->flags & (CI_VERBOTEN | CI_NO_EXPIRE))) {
+ send_event(EVENT_CHAN_EXPIRE, ci->name);
alog("Expiring channel %s (founder: %s)", ci->name,
(ci->founder ? ci->founder->display : "(none)"));
delchan(ci);
@@ -2789,6 +2791,7 @@ static int do_register(User * u)
anope_cmd_mode(s_ChanServ, chan, "%s %s", ircd->ownerset,
u->nick);
}
+ send_event(EVENT_CHAN_REGISTERED, chan);
}
return MOD_CONT;
}
@@ -2945,6 +2948,7 @@ static int do_drop(User * u)
chan);
notice_lang(s_ChanServ, u, CHAN_DROPPED, chan);
+ send_event(EVENT_CHAN_DROP, chan);
}
return MOD_CONT;
}
@@ -6371,6 +6375,7 @@ static int do_forbid(User * u)
alog("%s: %s set FORBID for channel %s", s_ChanServ, u->nick,
ci->name);
notice_lang(s_ChanServ, u, CHAN_FORBID_SUCCEEDED, chan);
+ send_event(EVENT_CHAN_FORBIDDEN, chan);
} else {
alog("%s: Valid FORBID for %s by %s failed", s_ChanServ, ci->name,
u->nick);
@@ -6444,6 +6449,7 @@ static int do_suspend(User * u)
alog("%s: %s set SUSPEND for channel %s", s_ChanServ, u->nick,
ci->name);
notice_lang(s_ChanServ, u, CHAN_SUSPEND_SUCCEEDED, chan);
+ send_event(EVENT_CHAN_SUSPENDED, chan);
} else {
alog("%s: Valid SUSPEND for %s by %s failed", s_ChanServ, ci->name,
u->nick);
@@ -6486,6 +6492,7 @@ static int do_unsuspend(User * u)
alog("%s: %s set UNSUSPEND for channel %s", s_ChanServ, u->nick,
ci->name);
notice_lang(s_ChanServ, u, CHAN_UNSUSPEND_SUCCEEDED, chan);
+ send_event(EVENT_CHAN_UNSUSPEND, chan);
} else {
alog("%s: Valid UNSUSPEND for %s by %s failed", s_ChanServ,
chan, u->nick);
diff --git a/src/events.c b/src/events.c
new file mode 100644
index 000000000..e4735efbf
--- /dev/null
+++ b/src/events.c
@@ -0,0 +1,779 @@
+/* Events functions.
+ *
+ * (C) 2004-2005 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+#include "modules.h"
+#include "language.h"
+#include "version.h"
+
+extern Module *mod_current_module;
+extern char *mod_current_module_name;
+char *mod_current_evtbuffer = NULL;
+
+EvtMessageHash *EVENT[MAX_CMD_HASH];
+EvtHookHash *EVENTHOOKS[MAX_CMD_HASH];
+
+EvtMessage *find_event(const char *name)
+{
+ EvtMessage *m;
+ m = findEventHandler(EVENT, name);
+ return m;
+}
+
+EvtHook *find_eventhook(const char *name)
+{
+ EvtHook *m;
+ m = findEventHook(EVENTHOOKS, name);
+ return m;
+}
+
+void send_event(char *name, const char *fmt, ...)
+{
+ va_list args;
+ char buf[16384]; /* Really huge, to try and avoid truncation */
+ *buf = '\0';
+
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ event_process_hook(name, buf);
+}
+
+void eventprintf(char *fmt, ...)
+{
+ va_list args;
+ char buf[16384]; /* Really huge, to try and avoid truncation */
+ char *event;
+
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ event = sstrdup(buf);
+ event_message_process(event);
+ va_end(args);
+ if (event) {
+ free(event);
+ }
+ return;
+}
+
+void event_message_process(char *eventbuf)
+{
+ int retVal = 0;
+ EvtMessage *current = NULL;
+ char source[64];
+ char cmd[64];
+ char buf[512]; /* Longest legal IRC command line */
+ char *s;
+ int ac; /* Parameters for the command */
+ char **av;
+ EvtMessage *evm;
+
+ /* zero out the buffers before we do much else */
+ *buf = '\0';
+ *source = '\0';
+ *cmd = '\0';
+
+ strscpy(buf, eventbuf, sizeof(buf));
+
+ doCleanBuffer((char *) buf);
+
+ /* Split the buffer into pieces. */
+ if (*buf == ':') {
+ s = strpbrk(buf, " ");
+ if (!s)
+ return;
+ *s = 0;
+ while (isspace(*++s));
+ strscpy(source, buf + 1, sizeof(source));
+ memmove(buf, s, strlen(s) + 1);
+ } else {
+ *source = 0;
+ }
+ if (!*buf)
+ return;
+ s = strpbrk(buf, " ");
+ if (s) {
+ *s = 0;
+ while (isspace(*++s));
+ } else
+ s = buf + strlen(buf);
+ strscpy(cmd, buf, sizeof(cmd));
+ ac = split_buf(s, &av, 1);
+
+ /* Do something with the message. */
+ evm = find_event(cmd);
+ if (evm) {
+ if (evm->func) {
+ mod_current_module_name = evm->mod_name;
+ retVal = evm->func(source, ac, av);
+ mod_current_module_name = NULL;
+ if (retVal == MOD_CONT) {
+ current = evm->next;
+ while (current && current->func && retVal == MOD_CONT) {
+ mod_current_module_name = current->mod_name;
+ retVal = current->func(source, ac, av);
+ mod_current_module_name = NULL;
+ current = current->next;
+ }
+ }
+ }
+ }
+ /* Free argument list we created */
+ free(av);
+}
+
+void event_process_hook(char *name, char *eventbuf)
+{
+ int retVal = 0;
+ EvtHook *current = NULL;
+ EvtHook *evh;
+ if (mod_current_evtbuffer) {
+ free(mod_current_evtbuffer);
+ }
+ if (eventbuf) {
+ mod_current_evtbuffer = sstrdup(eventbuf);
+ } else {
+ mod_current_evtbuffer = NULL;
+ }
+ /* Do something with the message. */
+ evh = find_eventhook(name);
+ if (evh) {
+ if (evh->func) {
+ mod_current_module_name = evh->mod_name;
+ retVal = evh->func(eventbuf);
+ mod_current_module_name = NULL;
+ if (retVal == MOD_CONT) {
+ current = evh->next;
+ while (current && current->func && retVal == MOD_CONT) {
+ mod_current_module_name = current->mod_name;
+ retVal = current->func(eventbuf);
+ mod_current_module_name = NULL;
+ current = current->next;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Displays a message list for a given message.
+ * Again this is of little use other than debugging.
+ * @param m the message to display
+ * @return 0 is returned and has no meaning
+ */
+int displayEventMessage(EvtMessage * evm)
+{
+ EvtMessage *msg = NULL;
+ int i = 0;
+ alog("Displaying message list for %s", evm->name);
+ for (msg = evm; msg; msg = msg->next) {
+ alog("%d: 0x%p", ++i, (void *) msg);
+ }
+ alog("end");
+ return 0;
+}
+
+/**
+ * Displays a message list for a given message.
+ * Again this is of little use other than debugging.
+ * @param m the message to display
+ * @return 0 is returned and has no meaning
+ */
+int displayEventHook(EvtHook * evh)
+{
+ EvtHook *msg = NULL;
+ int i = 0;
+ alog("Displaying message list for %s", evh->name);
+ for (msg = evh; msg; msg = msg->next) {
+ alog("%d: 0x%p", ++i, (void *) msg);
+ }
+ alog("end");
+ return 0;
+}
+
+/**
+ * Display the message call stak.
+ * Prints the call stack for a message based on the message name, again useful for debugging and little lese :)
+ * @param name the name of the message to print info for
+ * @return the return int has no relevence atm :)
+ */
+int displayHookFromHash(char *name)
+{
+ EvtHookHash *current = NULL;
+ int index = 0;
+ index = CMD_HASH(name);
+ if (debug > 1) {
+ alog("trying to display message %s", name);
+ }
+ for (current = EVENTHOOKS[index]; current; current = current->next) {
+ if (stricmp(name, current->name) == 0) {
+ displayEventHook(current->evh);
+ }
+ }
+ if (debug > 1) {
+ alog("done displaying message %s", name);
+ }
+ return 0;
+}
+
+/**
+ * Display the message call stak.
+ * Prints the call stack for a message based on the message name, again useful for debugging and little lese :)
+ * @param name the name of the message to print info for
+ * @return the return int has no relevence atm :)
+ */
+int displayEvtMessageFromHash(char *name)
+{
+ EvtMessageHash *current = NULL;
+ int index = 0;
+ index = CMD_HASH(name);
+ if (debug > 1) {
+ alog("trying to display message %s", name);
+ }
+ for (current = EVENT[index]; current; current = current->next) {
+ if (stricmp(name, current->name) == 0) {
+ displayEventMessage(current->evm);
+ }
+ }
+ if (debug > 1) {
+ alog("done displaying message %s", name);
+ }
+ return 0;
+}
+
+/*******************************************************************************
+ * Message Functions
+ *******************************************************************************/
+
+ /**
+ * Create a new Message struct.
+ * @param name the name of the message
+ * @param func a pointer to the function to call when we recive this message
+ * @return a new Message object
+ **/
+EvtMessage *createEventHandler(char *name,
+ int (*func) (char *source, int ac,
+ char **av))
+{
+ EvtMessage *evm = NULL;
+ if (!func) {
+ return NULL;
+ }
+ if ((evm = malloc(sizeof(EvtMessage))) == NULL) {
+ fatal("Out of memory!");
+ }
+ evm->name = sstrdup(name);
+ evm->func = func;
+ evm->mod_name = NULL;
+ evm->next = NULL;
+ return evm;
+}
+
+ /**
+ * Create a new Message struct.
+ * @param name the name of the message
+ * @param func a pointer to the function to call when we recive this message
+ * @return a new Message object
+ **/
+EvtHook *createEventHook(char *name, int (*func) (char *message))
+{
+ EvtHook *evh = NULL;
+ if (!func) {
+ return NULL;
+ }
+ if ((evh = malloc(sizeof(EvtHook))) == NULL) {
+ fatal("Out of memory!");
+ }
+ evh->name = sstrdup(name);
+ evh->func = func;
+ evh->mod_name = NULL;
+ evh->next = NULL;
+ return evh;
+}
+
+/**
+ * find a message in the given table.
+ * Looks up the message <name> in the MessageHash given
+ * @param MessageHash the message table to search for this command, will almost always be IRCD
+ * @param name the name of the command were looking for
+ * @return NULL if we cant find it, or a pointer to the Message if we can
+ **/
+EvtMessage *findEventHandler(EvtMessageHash * msgEvtTable[],
+ const char *name)
+{
+ int idx;
+ EvtMessageHash *current = NULL;
+ if (!msgEvtTable || !name) {
+ return NULL;
+ }
+ idx = CMD_HASH(name);
+
+ for (current = msgEvtTable[idx]; current; current = current->next) {
+ if (stricmp(name, current->name) == 0) {
+ return current->evm;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * find a message in the given table.
+ * Looks up the message <name> in the MessageHash given
+ * @param MessageHash the message table to search for this command, will almost always be IRCD
+ * @param name the name of the command were looking for
+ * @return NULL if we cant find it, or a pointer to the Message if we can
+ **/
+EvtHook *findEventHook(EvtHookHash * hookEvtTable[], const char *name)
+{
+ int idx;
+ EvtHookHash *current = NULL;
+ if (!hookEvtTable || !name) {
+ return NULL;
+ }
+ idx = CMD_HASH(name);
+
+ for (current = hookEvtTable[idx]; current; current = current->next) {
+ if (stricmp(name, current->name) == 0) {
+ return current->evh;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Add the given message (m) to the MessageHash marking it as a core command
+ * @param msgTable the MessageHash we want to add to
+ * @param m the Message we are adding
+ * @return MOD_ERR_OK on a successful add.
+ **/
+int addCoreEventHandler(EvtMessageHash * msgEvtTable[], EvtMessage * evm)
+{
+ if (!msgEvtTable || !evm) {
+ return MOD_ERR_PARAMS;
+ }
+ evm->core = 1;
+ return addEventHandler(msgEvtTable, evm);
+}
+
+/**
+ * Add a message to the MessageHash.
+ * @param msgTable the MessageHash we want to add a message to
+ * @param m the Message we want to add
+ * @return MOD_ERR_OK on a successful add.
+ **/
+int addEventHandler(EvtMessageHash * msgEvtTable[], EvtMessage * evm)
+{
+ /* We can assume both param's have been checked by this point.. */
+ int index = 0;
+ EvtMessageHash *current = NULL;
+ EvtMessageHash *newHash = NULL;
+ EvtMessageHash *lastHash = NULL;
+
+ if (!msgEvtTable || !evm) {
+ return MOD_ERR_PARAMS;
+ }
+
+ index = CMD_HASH(evm->name);
+
+ for (current = msgEvtTable[index]; current; current = current->next) {
+ if (stricmp(evm->name, current->name) == 0) { /* the msg exist's we are a addHead */
+ evm->next = current->evm;
+ current->evm = evm;
+ if (debug)
+ alog("existing msg: (0x%p), new msg (0x%p)",
+ (void *) evm->next, (void *) evm);
+ return MOD_ERR_OK;
+ }
+ lastHash = current;
+ }
+
+ if ((newHash = malloc(sizeof(EvtMessageHash))) == NULL) {
+ fatal("Out of memory");
+ }
+ newHash->next = NULL;
+ newHash->name = sstrdup(evm->name);
+ newHash->evm = evm;
+
+ if (lastHash == NULL)
+ msgEvtTable[index] = newHash;
+ else
+ lastHash->next = newHash;
+ return MOD_ERR_OK;
+}
+
+/**
+ * Add a message to the MessageHash.
+ * @param msgTable the MessageHash we want to add a message to
+ * @param m the Message we want to add
+ * @return MOD_ERR_OK on a successful add.
+ **/
+int addEventHook(EvtHookHash * hookEvtTable[], EvtHook * evh)
+{
+ /* We can assume both param's have been checked by this point.. */
+ int index = 0;
+ EvtHookHash *current = NULL;
+ EvtHookHash *newHash = NULL;
+ EvtHookHash *lastHash = NULL;
+
+ if (!hookEvtTable || !evh) {
+ return MOD_ERR_PARAMS;
+ }
+
+ index = CMD_HASH(evh->name);
+
+ for (current = hookEvtTable[index]; current; current = current->next) {
+ if (stricmp(evh->name, current->name) == 0) { /* the msg exist's we are a addHead */
+ evh->next = current->evh;
+ current->evh = evh;
+ if (debug)
+ alog("existing msg: (0x%p), new msg (0x%p)",
+ (void *) evh->next, (void *) evh);
+ return MOD_ERR_OK;
+ }
+ lastHash = current;
+ }
+
+ if ((newHash = malloc(sizeof(EvtHookHash))) == NULL) {
+ fatal("Out of memory");
+ }
+ newHash->next = NULL;
+ newHash->name = sstrdup(evh->name);
+ newHash->evh = evh;
+
+ if (lastHash == NULL)
+ hookEvtTable[index] = newHash;
+ else
+ lastHash->next = newHash;
+ return MOD_ERR_OK;
+}
+
+/**
+ * Add the given message (m) to the MessageHash marking it as a core command
+ * @param msgTable the MessageHash we want to add to
+ * @param m the Message we are adding
+ * @return MOD_ERR_OK on a successful add.
+ **/
+int addCoreEventHook(EvtHookHash * hookEvtTable[], EvtHook * evh)
+{
+ if (!hookEvtTable || !evh) {
+ return MOD_ERR_PARAMS;
+ }
+ evh->core = 1;
+ return addEventHook(hookEvtTable, evh);
+}
+
+/**
+ * Add a module message to the IRCD message hash
+ * @param m the Message to add
+ * @param pos the Position to add the message to, e.g. MOD_HEAD, MOD_TAIL, MOD_UNIQUE
+ * @return MOD_ERR_OK on success, althing else on fail.
+ **/
+int moduleAddEventHandler(EvtMessage * evm)
+{
+ int status;
+
+ if (!evm) {
+ return MOD_ERR_PARAMS;
+ }
+
+ /* ok, this appears to be a module adding a message from outside of AnopeInit, try to look up its module struct for it */
+ if ((mod_current_module_name) && (!mod_current_module)) {
+ mod_current_module = findModule(mod_current_module_name);
+ }
+
+ if (!mod_current_module) {
+ return MOD_ERR_UNKNOWN;
+ } /* shouldnt happen */
+ evm->core = 0;
+ if (!evm->mod_name) {
+ evm->mod_name = sstrdup(mod_current_module->name);
+ }
+
+ status = addEventHandler(EVENT, evm);
+ if (debug) {
+ displayEvtMessageFromHash(evm->name);
+ }
+ return status;
+}
+
+/**
+ * Add a module message to the IRCD message hash
+ * @param m the Message to add
+ * @param pos the Position to add the message to, e.g. MOD_HEAD, MOD_TAIL, MOD_UNIQUE
+ * @return MOD_ERR_OK on success, althing else on fail.
+ **/
+int moduleAddEventHook(EvtHook * evh)
+{
+ int status;
+
+ if (!evh) {
+ return MOD_ERR_PARAMS;
+ }
+
+ if ((mod_current_module_name) && (!mod_current_module)) {
+ mod_current_module = findModule(mod_current_module_name);
+ }
+
+ if (!mod_current_module) {
+ return MOD_ERR_UNKNOWN;
+ } /* shouldnt happen */
+ evh->core = 0;
+ if (!evh->mod_name) {
+ evh->mod_name = sstrdup(mod_current_module->name);
+ }
+
+ status = addEventHook(EVENTHOOKS, evh);
+ if (debug) {
+ displayHookFromHash(evh->name);
+ }
+ return status;
+}
+
+/**
+ * remove the given message from the IRCD message hash
+ * @param name the name of the message to remove
+ * @return MOD_ERR_OK on success, althing else on fail.
+ **/
+int moduleEventDelHandler(char *name)
+{
+ EvtMessage *evm;
+ int status;
+
+ if (!mod_current_module) {
+ return MOD_ERR_UNKNOWN;
+ }
+ evm = findEventHandler(EVENT, name);
+ if (!evm) {
+ return MOD_ERR_NOEXIST;
+ }
+
+ status = delEventHandler(EVENT, evm, mod_current_module->name);
+ if (debug) {
+ displayEvtMessageFromHash(evm->name);
+ }
+ return status;
+}
+
+/**
+ * remove the given message from the IRCD message hash
+ * @param name the name of the message to remove
+ * @return MOD_ERR_OK on success, althing else on fail.
+ **/
+int moduleEventDelHook(const char *name)
+{
+ EvtHook *evh;
+ int status;
+
+ if (!mod_current_module) {
+ return MOD_ERR_UNKNOWN;
+ }
+ evh = findEventHook(EVENTHOOKS, name);
+ if (!evh) {
+ return MOD_ERR_NOEXIST;
+ }
+
+ status = delEventHook(EVENTHOOKS, evh, mod_current_module->name);
+ if (debug) {
+ displayHookFromHash(evh->name);
+ }
+ return status;
+}
+
+/**
+ * remove the given message from the given message hash, for the given module
+ * @param msgTable which MessageHash we are removing from
+ * @param m the Message we want to remove
+ * @mod_name the name of the module we are removing
+ * @return MOD_ERR_OK on success, althing else on fail.
+ **/
+int delEventHandler(EvtMessageHash * msgEvtTable[], EvtMessage * evm,
+ char *mod_name)
+{
+ int index = 0;
+ EvtMessageHash *current = NULL;
+ EvtMessageHash *lastHash = NULL;
+ EvtMessage *tail = NULL, *last = NULL;
+
+ if (!evm || !msgEvtTable) {
+ return MOD_ERR_PARAMS;
+ }
+
+ index = CMD_HASH(evm->name);
+
+ for (current = msgEvtTable[index]; current; current = current->next) {
+ if (stricmp(evm->name, current->name) == 0) {
+ if (!lastHash) {
+ tail = current->evm;
+ if (tail->next) {
+ while (tail) {
+ if (mod_name && tail->mod_name
+ && (stricmp(mod_name, tail->mod_name) == 0)) {
+ if (last) {
+ last->next = tail->next;
+ } else {
+ current->evm = tail->next;
+ }
+ return MOD_ERR_OK;
+ }
+ last = tail;
+ tail = tail->next;
+ }
+ } else {
+ msgEvtTable[index] = current->next;
+ free(current->name);
+ return MOD_ERR_OK;
+ }
+ } else {
+ tail = current->evm;
+ if (tail->next) {
+ while (tail) {
+ if (mod_name && tail->mod_name
+ && (stricmp(mod_name, tail->mod_name) == 0)) {
+ if (last) {
+ last->next = tail->next;
+ } else {
+ current->evm = tail->next;
+ }
+ return MOD_ERR_OK;
+ }
+ last = tail;
+ tail = tail->next;
+ }
+ } else {
+ lastHash->next = current->next;
+ free(current->name);
+ return MOD_ERR_OK;
+ }
+ }
+ }
+ lastHash = current;
+ }
+ return MOD_ERR_NOEXIST;
+}
+
+
+/**
+ * remove the given message from the given message hash, for the given module
+ * @param msgTable which MessageHash we are removing from
+ * @param m the Message we want to remove
+ * @mod_name the name of the module we are removing
+ * @return MOD_ERR_OK on success, althing else on fail.
+ **/
+int delEventHook(EvtHookHash * hookEvtTable[], EvtHook * evh,
+ char *mod_name)
+{
+ int index = 0;
+ EvtHookHash *current = NULL;
+ EvtHookHash *lastHash = NULL;
+ EvtHook *tail = NULL, *last = NULL;
+
+ if (!evh || !hookEvtTable) {
+ return MOD_ERR_PARAMS;
+ }
+
+ index = CMD_HASH(evh->name);
+
+ for (current = hookEvtTable[index]; current; current = current->next) {
+ if (stricmp(evh->name, current->name)) {
+ if (!lastHash) {
+ tail = current->evh;
+ if (tail->next) {
+ while (tail) {
+ if (mod_name && tail->mod_name
+ && (stricmp(mod_name, tail->mod_name) == 0)) {
+ if (last) {
+ last->next = tail->next;
+ } else {
+ current->evh = tail->next;
+ }
+ return MOD_ERR_OK;
+ }
+ last = tail;
+ tail = tail->next;
+ }
+ } else {
+ hookEvtTable[index] = current->next;
+ free(current->name);
+ return MOD_ERR_OK;
+ }
+ } else {
+ tail = current->evh;
+ if (tail->next) {
+ while (tail) {
+ if (mod_name && tail->mod_name
+ && (stricmp(mod_name, tail->mod_name) == 0)) {
+ if (last) {
+ last->next = tail->next;
+ } else {
+ current->evh = tail->next;
+ }
+ return MOD_ERR_OK;
+ }
+ last = tail;
+ tail = tail->next;
+ }
+ } else {
+ lastHash->next = current->next;
+ free(current->name);
+ return MOD_ERR_OK;
+ }
+ }
+ }
+ lastHash = current;
+ }
+ return MOD_ERR_NOEXIST;
+}
+
+
+/**
+ * Destory a message, freeing its memory.
+ * @param m the message to be destroyed
+ * @return MOD_ERR_SUCCESS on success
+ **/
+int destroyEventHandler(EvtMessage * evm)
+{
+ if (!evm) {
+ return MOD_ERR_PARAMS;
+ }
+ if (evm->name) {
+ free(evm->name);
+ }
+ evm->func = NULL;
+ if (evm->mod_name) {
+ free(evm->mod_name);
+ }
+ evm->next = NULL;
+ return MOD_ERR_OK;
+}
+
+/**
+ * Destory a message, freeing its memory.
+ * @param m the message to be destroyed
+ * @return MOD_ERR_SUCCESS on success
+ **/
+int destroyEventHook(EvtHook * evh)
+{
+ if (!evh) {
+ return MOD_ERR_PARAMS;
+ }
+ if (evh->name) {
+ free(evh->name);
+ }
+ evh->func = NULL;
+ if (evh->mod_name) {
+ free(evh->mod_name);
+ }
+ evh->next = NULL;
+ return MOD_ERR_OK;
+}
diff --git a/src/init.c b/src/init.c
index e26378dfb..37725437d 100644
--- a/src/init.c
+++ b/src/init.c
@@ -683,6 +683,8 @@ int init(int ac, char **av)
alog("Info: Not reflecting database records.");
}
#endif
+ send_event(EVENT_CONNECT, EVENT_START);
+
/* Connect to the remote server */
servsock = conn(RemoteServer, RemotePort, LocalHost, LocalPort);
if (servsock < 0 && RemoteServer2) {
@@ -715,6 +717,7 @@ int init(int ac, char **av)
}
anope_cmd_connect(servernum);
+ send_event(EVENT_CONNECT, EVENT_STOP);
sgets2(inbuf, sizeof(inbuf), servsock);
if (strnicmp(inbuf, "ERROR", 5) == 0) {
diff --git a/src/main.c b/src/main.c
index d75a88f00..e3786bbd6 100644
--- a/src/main.c
+++ b/src/main.c
@@ -101,6 +101,7 @@ static int started = 0;
extern void expire_all(void)
{
+ send_event(EVENT_DB_EXPIRE, EVENT_START);
waiting = -3;
if (debug)
alog("debug: Running expire routines");
@@ -131,12 +132,15 @@ extern void expire_all(void)
if (ProxyDetect)
proxy_expire();
#endif
+ send_event(EVENT_DB_EXPIRE, EVENT_STOP);
}
/*************************************************************************/
void save_databases(void)
{
+ send_event(EVENT_DB_SAVING, EVENT_START);
+
waiting = -2;
if (debug)
alog("debug: Saving FFF databases");
@@ -207,6 +211,7 @@ void save_databases(void)
}
}
#endif
+ send_event(EVENT_DB_SAVING, EVENT_STOP);
}
/*************************************************************************/
@@ -216,6 +221,7 @@ void save_databases(void)
static void services_restart(void)
{
alog("Restarting");
+ send_event(EVENT_RESTART, EVENT_START);
if (!quitmsg)
quitmsg = "Restarting";
anope_cmd_squit(ServerName, quitmsg);
@@ -255,6 +261,8 @@ static void services_shutdown(void)
{
User *u, *next;
+ send_event(EVENT_SHUTDOWN, EVENT_START);
+
if (!quitmsg)
quitmsg = "Terminating, reason unknown";
alog("%s", quitmsg);
@@ -272,6 +280,7 @@ static void services_shutdown(void)
u = next;
}
}
+ send_event(EVENT_SHUTDOWN, EVENT_STOP);
disconn(servsock);
}
@@ -430,6 +439,7 @@ void sighandler(int signum)
if (signum == SIGSEGV) {
do_backtrace(1);
}
+ send_event(EVENT_SIGNAL, quitmsg);
if (started) {
services_shutdown();
diff --git a/src/makefile.win32 b/src/makefile.win32
index e7434cdba..64bf75eea 100644
--- a/src/makefile.win32
+++ b/src/makefile.win32
@@ -18,16 +18,16 @@ include ../Makefile.inc.win32
###########################################################################
OBJS = actions.obj base64.obj botserv.obj channels.obj chanserv.obj commands.obj compat.obj \
- converter.obj config.obj datafiles.obj encrypt.obj helpserv.obj hostserv.obj \
+ converter.obj config.obj datafiles.obj encrypt.obj events.obj helpserv.obj hostserv.obj \
init.obj language.obj list.obj log.obj mail.obj main.obj memory.obj memoserv.obj \
messages.obj misc.obj modules.obj news.obj nickserv.obj operserv.obj \
process.obj proxy.obj send.obj servers.obj sessions.obj slist.obj sockutil.obj \
timeout.obj users.obj $(RDB_O) $(MYSQL_O) $(CAPAB_O)
SRCS = actions.c base64.c botserv.c channels.c chanserv.c commands.c compat.c converter.c \
- config.c datafiles.c encrypt.c helpserv.c hostserv.c init.c language.c list.c log.c mail.c main.c \
- memory.c memoserv.c messages.c misc.c modules.c news.c nickserv.c operserv.c \
- process.c proxy.c send.c servers.obj sessions.c slist.c sockutil.c \
+ config.c datafiles.c encrypt.c events.c helpserv.c hostserv.c init.c language.c list.c \
+ log.c mail.c main.c memory.c memoserv.c messages.c misc.c modules.c news.c nickserv.c \
+ operserv.c process.c proxy.c send.c servers.obj sessions.c slist.c sockutil.c \
timeout.c users.c $(RDB_C) $(MYSQL_C) $(CAPAB_C)
###########################################################################
@@ -69,6 +69,7 @@ config.obj: config.c ..\include\services.h
converter.obj: converter.c ..\include\services.h ..\include\datafiles.h
datafiles.obj: datafiles.c ..\include\services.h ..\include\datafiles.h
encrypt.obj: encrypt.c ..\include\encrypt.h ..\include\sysconf.h
+events.obj: events.c ..\include\modules.h ..\include\language.h ..\include\version.h
init.obj: init.c ..\include\services.h
hostserv.obj: hostserv.c ..\include\services.h ..\include\pseudo.h
language.obj: language.c ..\include\services.h ..\include\language.h
@@ -79,6 +80,7 @@ main.obj: main.c ..\include\services.h ..\include\
memory.obj: memory.c ..\include\services.h
memoserv.obj: memoserv.c ..\include\services.h ..\include\pseudo.h
messages.obj: messages.c ..\include\services.h ..\include\messages.h ..\include\language.h
+modules.obj: modules.c ..\include\modules.h ..\include\language.h ..\include\version.h
misc.obj: misc.c ..\include\services.h ..\include\language.h
news.obj: news.c ..\include\services.h ..\include\pseudo.h
nickserv.obj: nickserv.c ..\include\services.h ..\include\pseudo.h
diff --git a/src/misc.c b/src/misc.c
index c1c2c7f7d..97b1af506 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -814,9 +814,17 @@ void EnforceQlinedNick(char *nick, char *killer)
int nickIsServices(char *nick, int bot)
{
int found = 0;
+ char *s;
if (!nick) {
- return found;
+ return found;
+ }
+
+ s = strchr(nick, '@');
+ if (s) {
+ *s++ = 0;
+ if (stricmp(s, ServerName) != 0)
+ return found;
}
if (s_NickServ && (stricmp(nick, s_NickServ) == 0))
diff --git a/src/modules/events.c b/src/modules/events.c
new file mode 100644
index 000000000..af53a3d40
--- /dev/null
+++ b/src/modules/events.c
@@ -0,0 +1,53 @@
+/**
+ * Simple module to show the usage of event messages and hooks
+ * This module is an example, and has no useful purpose!
+ *
+ * Please visit http://modules.anope.org for useful modules!
+ *
+ **/
+
+#include "module.h"
+
+#define AUTHOR "Anope"
+#define VERSION "1.1"
+
+int my_nick(char *source, int ac, char **av);
+int my_save(char *message);
+
+int AnopeInit(int argc, char **argv)
+{
+ EvtMessage *msg = NULL;
+ EvtHook *hook = NULL;
+ int status;
+ msg = createEventHandler("NICK", my_nick);
+ status = moduleAddEventHandler(msg);
+
+ hook = createEventHook(EVENT_DB_SAVING, my_save);
+ status = moduleAddEventHook(hook);
+
+ moduleAddAuthor(AUTHOR);
+ moduleAddVersion(VERSION);
+ return MOD_CONT;
+}
+
+void AnopeFini(void)
+{
+ /* unloading */
+}
+
+int my_nick(char *source, int ac, char **av)
+{
+ alog("Internal Event - nick is %s",av[0]);
+ return MOD_CONT;
+}
+
+int my_save(char *message)
+{
+ if (!stricmp(message, EVENT_START)) {
+ alog("Saving the databases! has started");
+ } else {
+ alog("Saving the databases is complete");
+ }
+ return MOD_CONT;
+}
+
diff --git a/src/modules/makefile.inc.win32 b/src/modules/makefile.inc.win32
index 95c0c84b1..f97acfd3d 100644
--- a/src/modules/makefile.inc.win32
+++ b/src/modules/makefile.inc.win32
@@ -1,2 +1,2 @@
-SRCS=hs_moo.c ircd_catserv.c
+SRCS=hs_moo.c ircd_catserv.c events.c
diff --git a/src/nickserv.c b/src/nickserv.c
index bf8d5cd99..a3a81f5ab 100644
--- a/src/nickserv.c
+++ b/src/nickserv.c
@@ -2306,6 +2306,7 @@ static int do_confirm(User * u)
else
notice_lang(s_NickServ, u, NICK_REGISTERED_NO_MASK,
u->nick);
+ send_event(EVENT_NICK_REGISTED, u->nick);
#ifndef USE_ENCRYPTION
notice_lang(s_NickServ, u, NICK_PASSWORD_IS, na->nc->pass);
#endif
@@ -2804,6 +2805,8 @@ static int do_drop(User * u)
(na->nc->email ? na->nc->email : "none"));
delnick(na);
+ send_event(EVENT_NICK_DROPPED, nick);
+
if (!is_mine) {
if (WallDrop)
anope_cmd_global(s_NickServ, "\2%s\2 used DROP on \2%s\2",
@@ -4282,6 +4285,7 @@ static int do_forbid(User * u)
alog("%s: %s set FORBID for nick %s", s_NickServ, u->nick, nick);
notice_lang(s_NickServ, u, NICK_FORBID_SUCCEEDED, nick);
+ send_event(EVENT_NICK_FORBIDDEN, nick);
} else {
alog("%s: Valid FORBID for %s by %s failed", s_NickServ, nick,
u->nick);
diff --git a/src/process.c b/src/process.c
index d4ea8b29e..f1e97fbed 100644
--- a/src/process.c
+++ b/src/process.c
@@ -246,7 +246,7 @@ void process()
av[0] to see if its a service nick if so assign mod_current_buffer the
value from AV[1] else just assign av[0] - TSL */
if (av[0]) {
- if (nickIsServices(av[0], 0)) {
+ if (nickIsServices(av[0], 1)) {
if (av[1]) {
mod_current_buffer = sstrdup(av[1]);
} else {
diff --git a/src/send.c b/src/send.c
index e30bbd88a..1ea115518 100644
--- a/src/send.c
+++ b/src/send.c
@@ -58,11 +58,13 @@ void vsend_cmd(const char *source, const char *fmt, va_list args)
if (source) {
sockprintf(servsock, ":%s %s\r\n", source, buf);
+ eventprintf(":%s %s", source, buf);
if (debug) {
alog("debug: Sent: :%s %s", source, buf);
}
} else {
sockprintf(servsock, "%s\r\n", buf);
+ eventprintf("%s", buf);
if (debug) {
alog("debug: Sent: %s", buf);
}
diff --git a/src/users.c b/src/users.c
index 1979f0283..85c89648c 100644
--- a/src/users.c
+++ b/src/users.c
@@ -645,6 +645,7 @@ User *do_nick(const char *source, char *nick, char *username, char *host,
} else {
user->svid = 1;
}
+ send_event(EVENT_NEWNICK, nick);
} else {
/* An old user changing nicks. */
@@ -685,6 +686,7 @@ User *do_nick(const char *source, char *nick, char *username, char *host,
}
change_user_nick(user, nick);
+ send_event(EVENT_CHANGE_NICK, nick);
if ((old_na ? old_na->nc : NULL) ==
(user->na ? user->na->nc : NULL))